1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-11-21 17:05:20 +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, 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; bool is_transparent_pass = pass != scene::ESNRP_SOLID;
std::string prefix; std::string prefix;
@@ -1504,22 +1504,9 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
for (auto &descriptor : draw_order) { for (auto &descriptor : draw_order) {
if (!descriptor.m_reuse_material) { if (!descriptor.m_reuse_material) {
// override some material properties
video::SMaterial local_material = descriptor.getMaterial(); video::SMaterial local_material = descriptor.getMaterial();
// do not override culling if the original material renders both back bool is_foliage = translucent_foliage && CONTAINS(leaves_material, local_material.MaterialType);
// and front faces in solid mode (e.g. plantlike) cb(local_material, is_foliage);
// 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;
driver->setMaterial(local_material); driver->setMaterial(local_material);
++material_swaps; ++material_swaps;
} }
@@ -1533,9 +1520,9 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
// restore the driver material state // restore the driver material state
video::SMaterial clean; video::SMaterial clean;
clean.BlendOperation = video::EBO_ADD; 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 // 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)); driver->draw3DLine(v3f(), v3f(), video::SColor(0));
g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true)); g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));

View File

@@ -9,6 +9,7 @@
#include <ISceneNode.h> #include <ISceneNode.h>
#include <set> #include <set>
#include <map> #include <map>
#include <functional>
struct MapDrawControl struct MapDrawControl
{ {
@@ -46,6 +47,7 @@ struct CachedMeshBuffer {
using CachedMeshBuffers = std::unordered_map<std::string, CachedMeshBuffer>; using CachedMeshBuffers = std::unordered_map<std::string, CachedMeshBuffer>;
using ModifyMaterialCallback = std::function<void(video::SMaterial& /* material */, bool /* is_foliage */)>;
/* /*
ClientMap ClientMap
@@ -107,7 +109,7 @@ public:
void renderMap(video::IVideoDriver* driver, s32 pass); void renderMap(video::IVideoDriver* driver, s32 pass);
void renderMapShadows(video::IVideoDriver *driver, 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 getBackgroundBrightness(float max_d, u32 daylight_factor,
int oldvalue, bool *sunlight_seen_result); 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, void ShadowRenderer::renderShadowMap(video::ITexture *target,
DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass) 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_VIEW, light.getFutureViewMatrix());
m_driver->setTransform(video::ETS_PROJECTION, light.getFutureProjectionMatrix()); 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()); 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 frame = m_force_update_shadow_map ? 0 : m_current_frame;
int total_frames = m_force_update_shadow_map ? 1 : m_map_shadow_update_frames; 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( void ShadowRenderer::renderShadowObjects(
@@ -480,6 +486,7 @@ void ShadowRenderer::renderShadowObjects(
current_mat.FrontfaceCulling = false; current_mat.FrontfaceCulling = false;
BufferBlendOperationList.push_back(current_mat.BlendOperation); BufferBlendOperationList.push_back(current_mat.BlendOperation);
// shouldn't we be setting EBO_MIN here?
} }
m_driver->setTransform(video::ETS_WORLD, m_driver->setTransform(video::ETS_WORLD,