1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-11 04:15:25 +01:00

Refactor shadow map material override

This commit is contained in:
sfan5
2025-11-07 12:15:58 +01:00
parent 6205e213c7
commit fad3a0fa6d
3 changed files with 35 additions and 39 deletions

View File

@@ -1414,7 +1414,7 @@ void ClientMap::PrintInfo(std::ostream &out)
}
void ClientMap::renderMapShadows(video::IVideoDriver *driver,
const video::SMaterial &material, s32 pass, int frame, int total_frames)
ModifyMaterialCallback cb, s32 pass, int frame, int total_frames)
{
bool is_transparent_pass = pass != scene::ESNRP_SOLID;
std::string prefix;
@@ -1504,22 +1504,9 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
for (auto &descriptor : draw_order) {
if (!descriptor.m_reuse_material) {
// override some material properties
video::SMaterial local_material = descriptor.getMaterial();
// do not override culling if the original material renders both back
// and front faces in solid mode (e.g. plantlike)
// Transparent plants would still render shadows only from one side,
// but this conflicts with water which occurs much more frequently
if (is_transparent_pass || local_material.BackfaceCulling || local_material.FrontfaceCulling) {
local_material.BackfaceCulling = material.BackfaceCulling;
local_material.FrontfaceCulling = material.FrontfaceCulling;
}
if (translucent_foliage && CONTAINS(leaves_material, local_material.MaterialType)) {
local_material.BackfaceCulling = true;
local_material.FrontfaceCulling = false;
}
local_material.MaterialType = material.MaterialType;
local_material.BlendOperation = material.BlendOperation;
bool is_foliage = translucent_foliage && CONTAINS(leaves_material, local_material.MaterialType);
cb(local_material, is_foliage);
driver->setMaterial(local_material);
++material_swaps;
}
@@ -1533,9 +1520,9 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
// restore the driver material state
video::SMaterial clean;
clean.BlendOperation = video::EBO_ADD;
driver->setMaterial(clean); // reset material to defaults
driver->setMaterial(clean);
// This is somehow needed to fully reset the rendering state, or later operations
// will be broken.
// will be broken. (TODO why?)
driver->draw3DLine(v3f(), v3f(), video::SColor(0));
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));

View File

@@ -9,6 +9,7 @@
#include <ISceneNode.h>
#include <set>
#include <map>
#include <functional>
struct MapDrawControl
{
@@ -46,6 +47,7 @@ struct CachedMeshBuffer {
using CachedMeshBuffers = std::unordered_map<std::string, CachedMeshBuffer>;
using ModifyMaterialCallback = std::function<void(video::SMaterial& /* material */, bool /* is_foliage */)>;
/*
ClientMap
@@ -107,7 +109,7 @@ public:
void renderMap(video::IVideoDriver* driver, s32 pass);
void renderMapShadows(video::IVideoDriver *driver,
const video::SMaterial &material, s32 pass, int frame, int total_frames);
ModifyMaterialCallback cb, s32 pass, int frame, int total_frames);
int getBackgroundBrightness(float max_d, u32 daylight_factor,
int oldvalue, bool *sunlight_seen_result);

View File

@@ -415,34 +415,40 @@ video::ITexture *ShadowRenderer::getSMTexture(const std::string &shadow_map_name
void ShadowRenderer::renderShadowMap(video::ITexture *target,
DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass)
{
bool is_transparent_pass = pass != scene::ESNRP_SOLID;
m_driver->setTransform(video::ETS_VIEW, light.getFutureViewMatrix());
m_driver->setTransform(video::ETS_PROJECTION, light.getFutureProjectionMatrix());
// ClientMap will call this for every material it renders
ModifyMaterialCallback cb = [&] (video::SMaterial &mat, bool foliage) {
// Do not override culling if the original material renders both back
// and front faces in solid mode (e.g. plantlike)
// Transparent plants would still render shadows only from one side,
// but this conflicts with water which occurs much more frequently
if (is_transparent_pass || mat.BackfaceCulling || mat.FrontfaceCulling) {
mat.BackfaceCulling = false;
mat.FrontfaceCulling = true;
}
if (foliage) {
mat.BackfaceCulling = true;
mat.FrontfaceCulling = false;
}
if (m_shadow_map_colored && is_transparent_pass) {
mat.MaterialType = depth_shader_trans;
} else {
mat.MaterialType = depth_shader;
mat.BlendOperation = video::EBO_MIN;
}
};
ClientMap &map_node = static_cast<ClientMap &>(m_client->getEnv().getMap());
video::SMaterial material;
if (map_node.getMaterialCount() > 0) {
// we only want the first material, which is the one with the albedo info
material = map_node.getMaterial(0);
}
material.BackfaceCulling = false;
material.FrontfaceCulling = true;
if (m_shadow_map_colored && pass != scene::ESNRP_SOLID) {
material.MaterialType = depth_shader_trans;
} else {
material.MaterialType = depth_shader;
material.BlendOperation = video::EBO_MIN;
}
m_driver->setTransform(video::ETS_WORLD,
map_node.getAbsoluteTransformation());
int frame = m_force_update_shadow_map ? 0 : m_current_frame;
int total_frames = m_force_update_shadow_map ? 1 : m_map_shadow_update_frames;
map_node.renderMapShadows(m_driver, material, pass, frame, total_frames);
map_node.renderMapShadows(m_driver, cb, pass, frame, total_frames);
}
void ShadowRenderer::renderShadowObjects(
@@ -480,6 +486,7 @@ void ShadowRenderer::renderShadowObjects(
current_mat.FrontfaceCulling = false;
BufferBlendOperationList.push_back(current_mat.BlendOperation);
// shouldn't we be setting EBO_MIN here?
}
m_driver->setTransform(video::ETS_WORLD,