From fad3a0fa6d2e66ac34820f1eb191d6a5076d5ddf Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 7 Nov 2025 12:15:58 +0100 Subject: [PATCH] Refactor shadow map material override --- src/client/clientmap.cpp | 23 +++------- src/client/clientmap.h | 4 +- src/client/shadows/dynamicshadowsrender.cpp | 47 ++++++++++++--------- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index e0665d95b9..7393fa50bf 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -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)); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 9013d0e50f..0e3ac9a2bc 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -9,6 +9,7 @@ #include #include #include +#include struct MapDrawControl { @@ -46,6 +47,7 @@ struct CachedMeshBuffer { using CachedMeshBuffers = std::unordered_map; +using ModifyMaterialCallback = std::function; /* 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); diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index e2c032e203..190ff36720 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -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(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,