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