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:
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user