From c47313db65f968559711ac1b505ef341a9872017 Mon Sep 17 00:00:00 2001 From: Liso Date: Sun, 6 Jun 2021 18:51:21 +0200 Subject: Shadow mapping render pass (#11244) Co-authored-by: x2048 --- src/client/shadows/dynamicshadowsrender.cpp | 539 ++++++++++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 src/client/shadows/dynamicshadowsrender.cpp (limited to 'src/client/shadows/dynamicshadowsrender.cpp') diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp new file mode 100644 index 000000000..135c9f895 --- /dev/null +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -0,0 +1,539 @@ +/* +Minetest +Copyright (C) 2021 Liso + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include "client/shadows/dynamicshadowsrender.h" +#include "client/shadows/shadowsScreenQuad.h" +#include "client/shadows/shadowsshadercallbacks.h" +#include "settings.h" +#include "filesys.h" +#include "util/string.h" +#include "client/shader.h" +#include "client/client.h" +#include "client/clientmap.h" + +ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : + m_device(device), m_smgr(device->getSceneManager()), + m_driver(device->getVideoDriver()), m_client(client) +{ + m_shadows_enabled = true; + + m_shadow_strength = g_settings->getFloat("shadow_strength"); + + m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance"); + + m_shadow_map_texture_size = g_settings->getFloat("shadow_map_texture_size"); + + m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit"); + m_shadow_map_colored = g_settings->getBool("shadow_map_color"); + m_shadow_samples = g_settings->getS32("shadow_filters"); + m_update_delta = g_settings->getFloat("shadow_update_time"); +} + +ShadowRenderer::~ShadowRenderer() +{ + if (m_shadow_depth_cb) + delete m_shadow_depth_cb; + if (m_shadow_mix_cb) + delete m_shadow_mix_cb; + m_shadow_node_array.clear(); + m_light_list.clear(); + + if (shadowMapTextureDynamicObjects) + m_driver->removeTexture(shadowMapTextureDynamicObjects); + + if (shadowMapTextureFinal) + m_driver->removeTexture(shadowMapTextureFinal); + + if (shadowMapTextureColors) + m_driver->removeTexture(shadowMapTextureColors); + + if (shadowMapClientMap) + m_driver->removeTexture(shadowMapClientMap); +} + +void ShadowRenderer::initialize() +{ + auto *gpu = m_driver->getGPUProgrammingServices(); + + // we need glsl + if (m_shadows_enabled && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) { + createShaders(); + } else { + m_shadows_enabled = false; + + warningstream << "Shadows: GLSL Shader not supported on this system." + << std::endl; + return; + } + + m_texture_format = m_shadow_map_texture_32bit + ? video::ECOLOR_FORMAT::ECF_R32F + : video::ECOLOR_FORMAT::ECF_R16F; + + m_texture_format_color = m_shadow_map_texture_32bit + ? video::ECOLOR_FORMAT::ECF_G32R32F + : video::ECOLOR_FORMAT::ECF_G16R16F; +} + + +float ShadowRenderer::getUpdateDelta() const +{ + return m_update_delta; +} + +size_t ShadowRenderer::addDirectionalLight() +{ + m_light_list.emplace_back(m_shadow_map_texture_size, + v3f(0.f, 0.f, 0.f), + video::SColor(255, 255, 255, 255), m_shadow_map_max_distance); + return m_light_list.size() - 1; +} + +DirectionalLight &ShadowRenderer::getDirectionalLight(u32 index) +{ + return m_light_list[index]; +} + +size_t ShadowRenderer::getDirectionalLightCount() const +{ + return m_light_list.size(); +} + +f32 ShadowRenderer::getMaxShadowFar() const +{ + if (!m_light_list.empty()) { + float wanted_range = m_client->getEnv().getClientMap().getWantedRange(); + + float zMax = m_light_list[0].getMaxFarValue() > wanted_range + ? wanted_range + : m_light_list[0].getMaxFarValue(); + return zMax * MAP_BLOCKSIZE; + } + return 0.0f; +} + +void ShadowRenderer::addNodeToShadowList( + scene::ISceneNode *node, E_SHADOW_MODE shadowMode) +{ + m_shadow_node_array.emplace_back(NodeToApply(node, shadowMode)); +} + +void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node) +{ + for (auto it = m_shadow_node_array.begin(); it != m_shadow_node_array.end();) { + if (it->node == node) { + it = m_shadow_node_array.erase(it); + break; + } else { + ++it; + } + } +} + +void ShadowRenderer::setClearColor(video::SColor ClearColor) +{ + m_clear_color = ClearColor; +} + +void ShadowRenderer::update(video::ITexture *outputTarget) +{ + if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) { + m_smgr->drawAll(); + return; + } + + if (!shadowMapTextureDynamicObjects) { + + shadowMapTextureDynamicObjects = getSMTexture( + std::string("shadow_dynamic_") + itos(m_shadow_map_texture_size), + m_texture_format, true); + } + + if (!shadowMapClientMap) { + + shadowMapClientMap = getSMTexture( + std::string("shadow_clientmap_") + itos(m_shadow_map_texture_size), + m_shadow_map_colored ? m_texture_format_color : m_texture_format, + true); + } + + if (m_shadow_map_colored && !shadowMapTextureColors) { + shadowMapTextureColors = getSMTexture( + std::string("shadow_colored_") + itos(m_shadow_map_texture_size), + m_shadow_map_colored ? m_texture_format_color : m_texture_format, + true); + } + + // The merge all shadowmaps texture + if (!shadowMapTextureFinal) { + video::ECOLOR_FORMAT frt; + if (m_shadow_map_texture_32bit) { + if (m_shadow_map_colored) + frt = video::ECOLOR_FORMAT::ECF_A32B32G32R32F; + else + frt = video::ECOLOR_FORMAT::ECF_R32F; + } else { + if (m_shadow_map_colored) + frt = video::ECOLOR_FORMAT::ECF_A16B16G16R16F; + else + frt = video::ECOLOR_FORMAT::ECF_R16F; + } + shadowMapTextureFinal = getSMTexture( + std::string("shadowmap_final_") + itos(m_shadow_map_texture_size), + frt, true); + } + + if (!m_shadow_node_array.empty() && !m_light_list.empty()) { + // for every directional light: + for (DirectionalLight &light : m_light_list) { + // Static shader values. + m_shadow_depth_cb->MapRes = (f32)m_shadow_map_texture_size; + m_shadow_depth_cb->MaxFar = (f32)m_shadow_map_max_distance * BS; + + // set the Render Target + // right now we can only render in usual RTT, not + // Depth texture is available in irrlicth maybe we + // should put some gl* fn here + + if (light.should_update_map_shadow) { + light.should_update_map_shadow = false; + + m_driver->setRenderTarget(shadowMapClientMap, true, true, + video::SColor(255, 255, 255, 255)); + renderShadowMap(shadowMapClientMap, light); + + if (m_shadow_map_colored) { + m_driver->setRenderTarget(shadowMapTextureColors, + true, false, video::SColor(255, 255, 255, 255)); + } + renderShadowMap(shadowMapTextureColors, light, + scene::ESNRP_TRANSPARENT); + m_driver->setRenderTarget(0, false, false); + } + + // render shadows for the n0n-map objects. + m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true, + true, video::SColor(255, 255, 255, 255)); + renderShadowObjects(shadowMapTextureDynamicObjects, light); + // clear the Render Target + m_driver->setRenderTarget(0, false, false); + + // in order to avoid too many map shadow renders, + // we should make a second pass to mix clientmap shadows and + // entities shadows :( + m_screen_quad->getMaterial().setTexture(0, shadowMapClientMap); + // dynamic objs shadow texture. + if (m_shadow_map_colored) + m_screen_quad->getMaterial().setTexture(1, shadowMapTextureColors); + m_screen_quad->getMaterial().setTexture(2, shadowMapTextureDynamicObjects); + + m_driver->setRenderTarget(shadowMapTextureFinal, false, false, + video::SColor(255, 255, 255, 255)); + m_screen_quad->render(m_driver); + m_driver->setRenderTarget(0, false, false); + + } // end for lights + + // now render the actual MT render pass + m_driver->setRenderTarget(outputTarget, true, true, m_clear_color); + m_smgr->drawAll(); + + /* this code just shows shadows textures in screen and in ONLY for debugging*/ + #if 0 + // this is debug, ignore for now. + m_driver->draw2DImage(shadowMapTextureFinal, + core::rect(0, 50, 128, 128 + 50), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); + + m_driver->draw2DImage(shadowMapClientMap, + core::rect(0, 50 + 128, 128, 128 + 50 + 128), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); + m_driver->draw2DImage(shadowMapTextureDynamicObjects, + core::rect(0, 128 + 50 + 128, 128, + 128 + 50 + 128 + 128), + core::rect({0, 0}, shadowMapTextureDynamicObjects->getSize())); + + if (m_shadow_map_colored) { + + m_driver->draw2DImage(shadowMapTextureColors, + core::rect(128,128 + 50 + 128 + 128, + 128 + 128, 128 + 50 + 128 + 128 + 128), + core::rect({0, 0}, shadowMapTextureColors->getSize())); + } + #endif + m_driver->setRenderTarget(0, false, false); + } +} + + +video::ITexture *ShadowRenderer::getSMTexture(const std::string &shadow_map_name, + video::ECOLOR_FORMAT texture_format, bool force_creation) +{ + if (force_creation) { + return m_driver->addRenderTargetTexture( + core::dimension2du(m_shadow_map_texture_size, + m_shadow_map_texture_size), + shadow_map_name.c_str(), texture_format); + } + + return m_driver->getTexture(shadow_map_name.c_str()); +} + +void ShadowRenderer::renderShadowMap(video::ITexture *target, + DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass) +{ + m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix()); + m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix()); + + // Operate on the client map + for (const auto &shadow_node : m_shadow_node_array) { + if (strcmp(shadow_node.node->getName(), "ClientMap") != 0) + continue; + + ClientMap *map_node = static_cast(shadow_node.node); + + 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; + material.PolygonOffsetFactor = 4.0f; + material.PolygonOffsetDirection = video::EPO_BACK; + //material.PolygonOffsetDepthBias = 1.0f/4.0f; + //material.PolygonOffsetSlopeScale = -1.f; + + if (m_shadow_map_colored && pass != scene::ESNRP_SOLID) + material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader_trans; + else + material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader; + + // FIXME: I don't think this is needed here + map_node->OnAnimate(m_device->getTimer()->getTime()); + + m_driver->setTransform(video::ETS_WORLD, + map_node->getAbsoluteTransformation()); + + map_node->renderMapShadows(m_driver, material, pass); + break; + } +} + +void ShadowRenderer::renderShadowObjects( + video::ITexture *target, DirectionalLight &light) +{ + m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix()); + m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix()); + + for (const auto &shadow_node : m_shadow_node_array) { + // we only take care of the shadow casters + if (shadow_node.shadowMode == ESM_RECEIVE || + strcmp(shadow_node.node->getName(), "ClientMap") == 0) + continue; + + // render other objects + u32 n_node_materials = shadow_node.node->getMaterialCount(); + std::vector BufferMaterialList; + std::vector> BufferMaterialCullingList; + BufferMaterialList.reserve(n_node_materials); + BufferMaterialCullingList.reserve(n_node_materials); + + // backup materialtype for each material + // (aka shader) + // and replace it by our "depth" shader + for (u32 m = 0; m < n_node_materials; m++) { + auto ¤t_mat = shadow_node.node->getMaterial(m); + + BufferMaterialList.push_back(current_mat.MaterialType); + current_mat.MaterialType = + (video::E_MATERIAL_TYPE)depth_shader; + + current_mat.setTexture(3, shadowMapTextureFinal); + + BufferMaterialCullingList.emplace_back( + (bool)current_mat.BackfaceCulling, (bool)current_mat.FrontfaceCulling); + + current_mat.BackfaceCulling = true; + current_mat.FrontfaceCulling = false; + current_mat.PolygonOffsetFactor = 1.0f/2048.0f; + current_mat.PolygonOffsetDirection = video::EPO_BACK; + //current_mat.PolygonOffsetDepthBias = 1.0 * 2.8e-6; + //current_mat.PolygonOffsetSlopeScale = -1.f; + } + + m_driver->setTransform(video::ETS_WORLD, + shadow_node.node->getAbsoluteTransformation()); + shadow_node.node->render(); + + // restore the material. + + for (u32 m = 0; m < n_node_materials; m++) { + auto ¤t_mat = shadow_node.node->getMaterial(m); + + current_mat.MaterialType = (video::E_MATERIAL_TYPE) BufferMaterialList[m]; + + current_mat.BackfaceCulling = BufferMaterialCullingList[m].first; + current_mat.FrontfaceCulling = BufferMaterialCullingList[m].second; + } + + } // end for caster shadow nodes +} + +void ShadowRenderer::mixShadowsQuad() +{ +} + +/* + * @Liso's disclaimer ;) This function loads the Shadow Mapping Shaders. + * I used a custom loader because I couldn't figure out how to use the base + * Shaders system with custom IShaderConstantSetCallBack without messing up the + * code too much. If anyone knows how to integrate this with the standard MT + * shaders, please feel free to change it. + */ + +void ShadowRenderer::createShaders() +{ + video::IGPUProgrammingServices *gpu = m_driver->getGPUProgrammingServices(); + + if (depth_shader == -1) { + std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl"); + if (depth_shader_vs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping vs shader not found." << std::endl; + return; + } + std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl"); + if (depth_shader_fs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping fs shader not found." << std::endl; + return; + } + m_shadow_depth_cb = new ShadowDepthShaderCB(); + + depth_shader = gpu->addHighLevelShaderMaterial( + readShaderFile(depth_shader_vs).c_str(), "vertexMain", + video::EVST_VS_1_1, + readShaderFile(depth_shader_fs).c_str(), "pixelMain", + video::EPST_PS_1_2, m_shadow_depth_cb); + + if (depth_shader == -1) { + // upsi, something went wrong loading shader. + delete m_shadow_depth_cb; + m_shadows_enabled = false; + errorstream << "Error compiling shadow mapping shader." << std::endl; + return; + } + + // HACK, TODO: investigate this better + // Grab the material renderer once more so minetest doesn't crash + // on exit + m_driver->getMaterialRenderer(depth_shader)->grab(); + } + + if (mixcsm_shader == -1) { + std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl"); + if (depth_shader_vs.empty()) { + m_shadows_enabled = false; + errorstream << "Error cascade shadow mapping fs shader not found." << std::endl; + return; + } + + std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass2_fragment.glsl"); + if (depth_shader_fs.empty()) { + m_shadows_enabled = false; + errorstream << "Error cascade shadow mapping fs shader not found." << std::endl; + return; + } + m_shadow_mix_cb = new shadowScreenQuadCB(); + m_screen_quad = new shadowScreenQuad(); + mixcsm_shader = gpu->addHighLevelShaderMaterial( + readShaderFile(depth_shader_vs).c_str(), "vertexMain", + video::EVST_VS_1_1, + readShaderFile(depth_shader_fs).c_str(), "pixelMain", + video::EPST_PS_1_2, m_shadow_mix_cb); + + m_screen_quad->getMaterial().MaterialType = + (video::E_MATERIAL_TYPE)mixcsm_shader; + + if (mixcsm_shader == -1) { + // upsi, something went wrong loading shader. + delete m_shadow_mix_cb; + delete m_screen_quad; + m_shadows_enabled = false; + errorstream << "Error compiling cascade shadow mapping shader." << std::endl; + return; + } + + // HACK, TODO: investigate this better + // Grab the material renderer once more so minetest doesn't crash + // on exit + m_driver->getMaterialRenderer(mixcsm_shader)->grab(); + } + + if (m_shadow_map_colored && depth_shader_trans == -1) { + std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_trans_vertex.glsl"); + if (depth_shader_vs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping vs shader not found." << std::endl; + return; + } + std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_trans_fragment.glsl"); + if (depth_shader_fs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping fs shader not found." << std::endl; + return; + } + m_shadow_depth_trans_cb = new ShadowDepthShaderCB(); + + depth_shader_trans = gpu->addHighLevelShaderMaterial( + readShaderFile(depth_shader_vs).c_str(), "vertexMain", + video::EVST_VS_1_1, + readShaderFile(depth_shader_fs).c_str(), "pixelMain", + video::EPST_PS_1_2, m_shadow_depth_trans_cb); + + if (depth_shader_trans == -1) { + // upsi, something went wrong loading shader. + delete m_shadow_depth_trans_cb; + m_shadow_map_colored = false; + m_shadows_enabled = false; + errorstream << "Error compiling colored shadow mapping shader." << std::endl; + return; + } + + // HACK, TODO: investigate this better + // Grab the material renderer once more so minetest doesn't crash + // on exit + m_driver->getMaterialRenderer(depth_shader_trans)->grab(); + } +} + +std::string ShadowRenderer::readShaderFile(const std::string &path) +{ + std::string prefix; + if (m_shadow_map_colored) + prefix.append("#define COLORED_SHADOWS 1\n"); + + std::string content; + fs::ReadFile(path, content); + + return prefix + content; +} -- cgit v1.2.3 From bf3acbf388406f736286d990adb5f35a9023c390 Mon Sep 17 00:00:00 2001 From: x2048 Date: Sun, 25 Jul 2021 12:36:23 +0200 Subject: Distribute shadow map update over multiple frames to reduce stutter (#11422) Reduces stutter and freezes when playing. * Maintains double SM and SM Color textures * Light frustum update triggers incremental generation of shadow map into secondary 'future' textures. * Every incremental update renders a portion of the shadow draw list (split equally). * After defined number of frames (currently, 4), 'future' and 'current' textures are swapped, and DirectionalLight 'commits' the new frustum to use when rendering shadows on screen. Co-authored-by: sfan5 --- builtin/settingtypes.txt | 10 +- client/shaders/nodes_shader/opengl_fragment.glsl | 10 +- src/client/clientmap.cpp | 25 +++- src/client/clientmap.h | 2 +- src/client/game.cpp | 17 +-- src/client/shadows/dynamicshadows.cpp | 60 +++++++-- src/client/shadows/dynamicshadows.h | 9 +- src/client/shadows/dynamicshadowsrender.cpp | 156 ++++++++++++++++++----- src/client/shadows/dynamicshadowsrender.h | 7 +- src/defaultsettings.cpp | 2 +- 10 files changed, 225 insertions(+), 73 deletions(-) (limited to 'src/client/shadows/dynamicshadowsrender.cpp') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 17843fac8..420e9d49c 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -618,11 +618,11 @@ shadow_filters (Shadow filter quality) enum 1 0,1,2 # On true translucent nodes cast colored shadows. This is expensive. shadow_map_color (Colored shadows) bool false - -# Set the shadow update time, in seconds. -# Lower value means shadows and map updates faster, but it consumes more resources. -# Minimum value: 0.001; maximum value: 0.2 -shadow_update_time (Map update time) float 0.2 0.001 0.2 +# Spread a complete update of shadow map over given amount of frames. +# Higher values might make shadows laggy, lower values +# will consume more resources. +# Minimum value: 1; maximum value: 16 +shadow_update_frames (Map shadows update frames) int 8 1 16 # Set the soft shadow radius size. # Lower values mean sharper shadows, bigger values mean softer shadows. diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 64a88ebbb..f85ca7b48 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -197,7 +197,7 @@ float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDist float pointDepth; float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier; - float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND); + float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND); int n = 0; for (y = -bound; y <= bound; y += 1.0) @@ -304,7 +304,7 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance float perspectiveFactor; float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), 1, PCFSAMPLES)); + int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; @@ -334,7 +334,7 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) float perspectiveFactor; float texture_size = 1.0 / (f_textureresolution * 0.5); - int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), 1, PCFSAMPLES)); + int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES)); int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples))); int end_offset = int(samples) + init_offset; @@ -370,7 +370,7 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance float texture_size = 1.0 / (f_textureresolution * 0.5); float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND); + float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); int n = 0; // basic PCF filter @@ -402,7 +402,7 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance) float texture_size = 1.0 / (f_textureresolution * 0.5); float y, x; - float bound = clamp(PCFBOUND * (1 - baseLength), 0.5, PCFBOUND); + float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND); int n = 0; // basic PCF filter diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 8b09eade1..77f3b9fe8 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -636,7 +636,7 @@ void ClientMap::PrintInfo(std::ostream &out) } void ClientMap::renderMapShadows(video::IVideoDriver *driver, - const video::SMaterial &material, s32 pass) + const video::SMaterial &material, s32 pass, int frame, int total_frames) { bool is_transparent_pass = pass != scene::ESNRP_SOLID; std::string prefix; @@ -650,7 +650,23 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, MeshBufListList drawbufs; + int count = 0; + int low_bound = is_transparent_pass ? 0 : m_drawlist_shadow.size() / total_frames * frame; + int high_bound = is_transparent_pass ? m_drawlist_shadow.size() : m_drawlist_shadow.size() / total_frames * (frame + 1); + + // transparent pass should be rendered in one go + if (is_transparent_pass && frame != total_frames - 1) { + return; + } + for (auto &i : m_drawlist_shadow) { + // only process specific part of the list & break early + ++count; + if (count <= low_bound) + continue; + if (count > high_bound) + break; + v3s16 block_pos = i.first; MapBlock *block = i.second; @@ -705,6 +721,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, local_material.MaterialType = material.MaterialType; local_material.BackfaceCulling = material.BackfaceCulling; local_material.FrontfaceCulling = material.FrontfaceCulling; + local_material.BlendOperation = material.BlendOperation; local_material.Lighting = false; driver->setMaterial(local_material); @@ -720,6 +737,12 @@ 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->draw3DLine(v3f(), v3f(), video::SColor(0)); + g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true)); g_profiler->avg(prefix + "vertices drawn [#]", vertex_count); g_profiler->avg(prefix + "drawcalls [#]", drawcall_count); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 93ade4c15..97ce8d355 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -125,7 +125,7 @@ public: void renderMap(video::IVideoDriver* driver, s32 pass); void renderMapShadows(video::IVideoDriver *driver, - const video::SMaterial &material, s32 pass); + const video::SMaterial &material, 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/game.cpp b/src/client/game.cpp index 85dd8f4bb..6fc57c8cc 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -609,7 +609,6 @@ struct GameRunData { float jump_timer; float damage_flash; float update_draw_list_timer; - float update_shadows_timer; f32 fog_range; @@ -3881,10 +3880,8 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, changed much */ runData.update_draw_list_timer += dtime; - runData.update_shadows_timer += dtime; float update_draw_list_delta = 0.2f; - bool draw_list_updated = false; v3f camera_direction = camera->getDirection(); if (runData.update_draw_list_timer >= update_draw_list_delta @@ -3894,18 +3891,10 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, runData.update_draw_list_timer = 0; client->getEnv().getClientMap().updateDrawList(); runData.update_draw_list_last_cam_dir = camera_direction; - draw_list_updated = true; } - if (ShadowRenderer *shadow = RenderingEngine::get_shadow_renderer()) { - update_draw_list_delta = shadow->getUpdateDelta(); - - if (m_camera_offset_changed || - (runData.update_shadows_timer > update_draw_list_delta && - (!draw_list_updated || shadow->getDirectionalLightCount() == 0))) { - runData.update_shadows_timer = 0; - updateShadows(); - } + if (RenderingEngine::get_shadow_renderer()) { + updateShadows(); } m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, gui_chat_console, dtime); @@ -4062,7 +4051,7 @@ void Game::updateShadows() shadow->getDirectionalLight().setDirection(sun_pos); shadow->setTimeOfDay(in_timeofday); - shadow->getDirectionalLight().update_frustum(camera, client); + shadow->getDirectionalLight().update_frustum(camera, client, m_camera_offset_changed); } /**************************************************************************** diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp index 17b711a61..0c7eea0e7 100644 --- a/src/client/shadows/dynamicshadows.cpp +++ b/src/client/shadows/dynamicshadows.cpp @@ -38,8 +38,8 @@ void DirectionalLight::createSplitMatrices(const Camera *cam) float tanFovX = tanf(cam->getFovX() * 0.5f); // adjusted frustum boundaries - float sfNear = shadow_frustum.zNear; - float sfFar = adjustDist(shadow_frustum.zFar, cam->getFovY()); + float sfNear = future_frustum.zNear; + float sfFar = adjustDist(future_frustum.zFar, cam->getFovY()); // adjusted camera positions v3f camPos2 = cam->getPosition(); @@ -87,14 +87,15 @@ void DirectionalLight::createSplitMatrices(const Camera *cam) v3f eye_displacement = direction * vvolume; // we must compute the viewmat with the position - the camera offset - // but the shadow_frustum position must be the actual world position + // but the future_frustum position must be the actual world position v3f eye = frustumCenter - eye_displacement; - shadow_frustum.position = world_center - eye_displacement; - shadow_frustum.length = vvolume; - shadow_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, frustumCenter, v3f(0.0f, 1.0f, 0.0f)); - shadow_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(shadow_frustum.length, - shadow_frustum.length, -shadow_frustum.length, - shadow_frustum.length,false); + future_frustum.position = world_center - eye_displacement; + future_frustum.length = vvolume; + future_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, frustumCenter, v3f(0.0f, 1.0f, 0.0f)); + future_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(future_frustum.length, + future_frustum.length, -future_frustum.length, + future_frustum.length,false); + future_frustum.camera_offset = cam->getOffset(); } DirectionalLight::DirectionalLight(const u32 shadowMapResolution, @@ -104,23 +105,44 @@ DirectionalLight::DirectionalLight(const u32 shadowMapResolution, farPlane(farValue), mapRes(shadowMapResolution), pos(position) {} -void DirectionalLight::update_frustum(const Camera *cam, Client *client) +void DirectionalLight::update_frustum(const Camera *cam, Client *client, bool force) { - should_update_map_shadow = true; + if (dirty && !force) + return; + float zNear = cam->getCameraNode()->getNearValue(); float zFar = getMaxFarValue(); /////////////////////////////////// // update splits near and fars - shadow_frustum.zNear = zNear; - shadow_frustum.zFar = zFar; + future_frustum.zNear = zNear; + future_frustum.zFar = zFar; // update shadow frustum createSplitMatrices(cam); // get the draw list for shadows client->getEnv().getClientMap().updateDrawListShadow( - getPosition(), getDirection(), shadow_frustum.length); + getPosition(), getDirection(), future_frustum.length); should_update_map_shadow = true; + dirty = true; + + // when camera offset changes, adjust the current frustum view matrix to avoid flicker + v3s16 cam_offset = cam->getOffset(); + if (cam_offset != shadow_frustum.camera_offset) { + v3f rotated_offset; + shadow_frustum.ViewMat.rotateVect(rotated_offset, intToFloat(cam_offset - shadow_frustum.camera_offset, BS)); + shadow_frustum.ViewMat.setTranslation(shadow_frustum.ViewMat.getTranslation() + rotated_offset); + shadow_frustum.camera_offset = cam_offset; + } +} + +void DirectionalLight::commitFrustum() +{ + if (!dirty) + return; + + shadow_frustum = future_frustum; + dirty = false; } void DirectionalLight::setDirection(v3f dir) @@ -144,6 +166,16 @@ const m4f &DirectionalLight::getProjectionMatrix() const return shadow_frustum.ProjOrthMat; } +const m4f &DirectionalLight::getFutureViewMatrix() const +{ + return future_frustum.ViewMat; +} + +const m4f &DirectionalLight::getFutureProjectionMatrix() const +{ + return future_frustum.ProjOrthMat; +} + m4f DirectionalLight::getViewProjMatrix() { return shadow_frustum.ProjOrthMat * shadow_frustum.ViewMat; diff --git a/src/client/shadows/dynamicshadows.h b/src/client/shadows/dynamicshadows.h index a53612f7c..d8be66be8 100644 --- a/src/client/shadows/dynamicshadows.h +++ b/src/client/shadows/dynamicshadows.h @@ -34,6 +34,7 @@ struct shadowFrustum core::matrix4 ProjOrthMat; core::matrix4 ViewMat; v3f position; + v3s16 camera_offset; }; class DirectionalLight @@ -47,7 +48,7 @@ public: //DISABLE_CLASS_COPY(DirectionalLight) - void update_frustum(const Camera *cam, Client *client); + void update_frustum(const Camera *cam, Client *client, bool force = false); // when set direction is updated to negative normalized(direction) void setDirection(v3f dir); @@ -59,6 +60,8 @@ public: /// Gets the light's matrices. const core::matrix4 &getViewMatrix() const; const core::matrix4 &getProjectionMatrix() const; + const core::matrix4 &getFutureViewMatrix() const; + const core::matrix4 &getFutureProjectionMatrix() const; core::matrix4 getViewProjMatrix(); /// Gets the light's far value. @@ -88,6 +91,8 @@ public: bool should_update_map_shadow{true}; + void commitFrustum(); + private: void createSplitMatrices(const Camera *cam); @@ -99,4 +104,6 @@ private: v3f pos; v3f direction{0}; shadowFrustum shadow_frustum; + shadowFrustum future_frustum; + bool dirty{false}; }; diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 135c9f895..350586225 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -27,10 +27,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/shader.h" #include "client/client.h" #include "client/clientmap.h" +#include "profiler.h" ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : m_device(device), m_smgr(device->getSceneManager()), - m_driver(device->getVideoDriver()), m_client(client) + m_driver(device->getVideoDriver()), m_client(client), m_current_frame(0) { m_shadows_enabled = true; @@ -43,7 +44,7 @@ ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit"); m_shadow_map_colored = g_settings->getBool("shadow_map_color"); m_shadow_samples = g_settings->getS32("shadow_filters"); - m_update_delta = g_settings->getFloat("shadow_update_time"); + m_map_shadow_update_frames = g_settings->getS16("shadow_update_frames"); } ShadowRenderer::~ShadowRenderer() @@ -66,6 +67,9 @@ ShadowRenderer::~ShadowRenderer() if (shadowMapClientMap) m_driver->removeTexture(shadowMapClientMap); + + if (shadowMapClientMapFuture) + m_driver->removeTexture(shadowMapClientMapFuture); } void ShadowRenderer::initialize() @@ -93,11 +97,6 @@ void ShadowRenderer::initialize() } -float ShadowRenderer::getUpdateDelta() const -{ - return m_update_delta; -} - size_t ShadowRenderer::addDirectionalLight() { m_light_list.emplace_back(m_shadow_map_texture_size, @@ -152,10 +151,9 @@ void ShadowRenderer::setClearColor(video::SColor ClearColor) m_clear_color = ClearColor; } -void ShadowRenderer::update(video::ITexture *outputTarget) +void ShadowRenderer::updateSMTextures() { if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) { - m_smgr->drawAll(); return; } @@ -174,6 +172,13 @@ void ShadowRenderer::update(video::ITexture *outputTarget) true); } + if (!shadowMapClientMapFuture && m_map_shadow_update_frames > 1) { + shadowMapClientMapFuture = getSMTexture( + std::string("shadow_clientmap_bb_") + itos(m_shadow_map_texture_size), + m_shadow_map_colored ? m_texture_format_color : m_texture_format, + true); + } + if (m_shadow_map_colored && !shadowMapTextureColors) { shadowMapTextureColors = getSMTexture( std::string("shadow_colored_") + itos(m_shadow_map_texture_size), @@ -201,7 +206,22 @@ void ShadowRenderer::update(video::ITexture *outputTarget) } if (!m_shadow_node_array.empty() && !m_light_list.empty()) { - // for every directional light: + bool reset_sm_texture = false; + + // detect if SM should be regenerated + for (DirectionalLight &light : m_light_list) { + if (light.should_update_map_shadow) { + light.should_update_map_shadow = false; + m_current_frame = 0; + reset_sm_texture = true; + } + } + + video::ITexture* shadowMapTargetTexture = shadowMapClientMapFuture; + if (shadowMapTargetTexture == nullptr) + shadowMapTargetTexture = shadowMapClientMap; + + // Update SM incrementally: for (DirectionalLight &light : m_light_list) { // Static shader values. m_shadow_depth_cb->MapRes = (f32)m_shadow_map_texture_size; @@ -212,22 +232,60 @@ void ShadowRenderer::update(video::ITexture *outputTarget) // Depth texture is available in irrlicth maybe we // should put some gl* fn here - if (light.should_update_map_shadow) { - light.should_update_map_shadow = false; - m_driver->setRenderTarget(shadowMapClientMap, true, true, + if (m_current_frame < m_map_shadow_update_frames) { + m_driver->setRenderTarget(shadowMapTargetTexture, reset_sm_texture, true, video::SColor(255, 255, 255, 255)); - renderShadowMap(shadowMapClientMap, light); - - if (m_shadow_map_colored) { - m_driver->setRenderTarget(shadowMapTextureColors, - true, false, video::SColor(255, 255, 255, 255)); + renderShadowMap(shadowMapTargetTexture, light); + + // Render transparent part in one pass. + // This is also handled in ClientMap. + if (m_current_frame == m_map_shadow_update_frames - 1) { + if (m_shadow_map_colored) { + m_driver->setRenderTarget(shadowMapTextureColors, + true, false, video::SColor(255, 255, 255, 255)); + } + renderShadowMap(shadowMapTextureColors, light, + scene::ESNRP_TRANSPARENT); } - renderShadowMap(shadowMapTextureColors, light, - scene::ESNRP_TRANSPARENT); m_driver->setRenderTarget(0, false, false); } + reset_sm_texture = false; + } // end for lights + + // move to the next section + if (m_current_frame <= m_map_shadow_update_frames) + ++m_current_frame; + + // pass finished, swap textures and commit light changes + if (m_current_frame == m_map_shadow_update_frames) { + if (shadowMapClientMapFuture != nullptr) + std::swap(shadowMapClientMapFuture, shadowMapClientMap); + + // Let all lights know that maps are updated + for (DirectionalLight &light : m_light_list) + light.commitFrustum(); + } + } +} + +void ShadowRenderer::update(video::ITexture *outputTarget) +{ + if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) { + m_smgr->drawAll(); + return; + } + + updateSMTextures(); + + if (!m_shadow_node_array.empty() && !m_light_list.empty()) { + + for (DirectionalLight &light : m_light_list) { + // Static shader values. + m_shadow_depth_cb->MapRes = (f32)m_shadow_map_texture_size; + m_shadow_depth_cb->MaxFar = (f32)m_shadow_map_max_distance * BS; + // render shadows for the n0n-map objects. m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true, true, video::SColor(255, 255, 255, 255)); @@ -299,8 +357,8 @@ 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) { - m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix()); - m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix()); + m_driver->setTransform(video::ETS_VIEW, light.getFutureViewMatrix()); + m_driver->setTransform(video::ETS_PROJECTION, light.getFutureProjectionMatrix()); // Operate on the client map for (const auto &shadow_node : m_shadow_node_array) { @@ -322,10 +380,13 @@ void ShadowRenderer::renderShadowMap(video::ITexture *target, //material.PolygonOffsetDepthBias = 1.0f/4.0f; //material.PolygonOffsetSlopeScale = -1.f; - if (m_shadow_map_colored && pass != scene::ESNRP_SOLID) + if (m_shadow_map_colored && pass != scene::ESNRP_SOLID) { material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader_trans; - else + } + else { material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader; + material.BlendOperation = video::EBO_MIN; + } // FIXME: I don't think this is needed here map_node->OnAnimate(m_device->getTimer()->getTime()); @@ -333,7 +394,7 @@ void ShadowRenderer::renderShadowMap(video::ITexture *target, m_driver->setTransform(video::ETS_WORLD, map_node->getAbsoluteTransformation()); - map_node->renderMapShadows(m_driver, material, pass); + map_node->renderMapShadows(m_driver, material, pass, m_current_frame, m_map_shadow_update_frames); break; } } @@ -354,8 +415,10 @@ void ShadowRenderer::renderShadowObjects( u32 n_node_materials = shadow_node.node->getMaterialCount(); std::vector BufferMaterialList; std::vector> BufferMaterialCullingList; + std::vector BufferBlendOperationList; BufferMaterialList.reserve(n_node_materials); BufferMaterialCullingList.reserve(n_node_materials); + BufferBlendOperationList.reserve(n_node_materials); // backup materialtype for each material // (aka shader) @@ -365,12 +428,11 @@ void ShadowRenderer::renderShadowObjects( BufferMaterialList.push_back(current_mat.MaterialType); current_mat.MaterialType = - (video::E_MATERIAL_TYPE)depth_shader; - - current_mat.setTexture(3, shadowMapTextureFinal); + (video::E_MATERIAL_TYPE)depth_shader_entities; BufferMaterialCullingList.emplace_back( (bool)current_mat.BackfaceCulling, (bool)current_mat.FrontfaceCulling); + BufferBlendOperationList.push_back(current_mat.BlendOperation); current_mat.BackfaceCulling = true; current_mat.FrontfaceCulling = false; @@ -393,6 +455,7 @@ void ShadowRenderer::renderShadowObjects( current_mat.BackfaceCulling = BufferMaterialCullingList[m].first; current_mat.FrontfaceCulling = BufferMaterialCullingList[m].second; + current_mat.BlendOperation = BufferBlendOperationList[m]; } } // end for caster shadow nodes @@ -433,7 +496,7 @@ void ShadowRenderer::createShaders() readShaderFile(depth_shader_vs).c_str(), "vertexMain", video::EVST_VS_1_1, readShaderFile(depth_shader_fs).c_str(), "pixelMain", - video::EPST_PS_1_2, m_shadow_depth_cb); + video::EPST_PS_1_2, m_shadow_depth_cb, video::EMT_ONETEXTURE_BLEND); if (depth_shader == -1) { // upsi, something went wrong loading shader. @@ -449,6 +512,41 @@ void ShadowRenderer::createShaders() m_driver->getMaterialRenderer(depth_shader)->grab(); } + // This creates a clone of depth_shader with base material set to EMT_SOLID, + // because entities won't render shadows with base material EMP_ONETEXTURE_BLEND + if (depth_shader_entities == -1) { + std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl"); + if (depth_shader_vs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping vs shader not found." << std::endl; + return; + } + std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl"); + if (depth_shader_fs.empty()) { + m_shadows_enabled = false; + errorstream << "Error shadow mapping fs shader not found." << std::endl; + return; + } + + depth_shader_entities = gpu->addHighLevelShaderMaterial( + readShaderFile(depth_shader_vs).c_str(), "vertexMain", + video::EVST_VS_1_1, + readShaderFile(depth_shader_fs).c_str(), "pixelMain", + video::EPST_PS_1_2, m_shadow_depth_cb); + + if (depth_shader_entities == -1) { + // upsi, something went wrong loading shader. + m_shadows_enabled = false; + errorstream << "Error compiling shadow mapping shader (dynamic)." << std::endl; + return; + } + + // HACK, TODO: investigate this better + // Grab the material renderer once more so minetest doesn't crash + // on exit + m_driver->getMaterialRenderer(depth_shader_entities)->grab(); + } + if (mixcsm_shader == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl"); if (depth_shader_vs.empty()) { diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index e633bd4f7..52b24a18f 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -64,7 +64,6 @@ public: size_t getDirectionalLightCount() const; f32 getMaxShadowFar() const; - float getUpdateDelta() const; /// Adds a shadow to the scene node. /// The shadow mode can be ESM_BOTH, or ESM_RECEIVE. /// ESM_BOTH casts and receives shadows @@ -101,6 +100,7 @@ private: scene::ESNRP_SOLID); void renderShadowObjects(video::ITexture *target, DirectionalLight &light); void mixShadowsQuad(); + void updateSMTextures(); // a bunch of variables IrrlichtDevice *m_device{nullptr}; @@ -108,6 +108,7 @@ private: video::IVideoDriver *m_driver{nullptr}; Client *m_client{nullptr}; video::ITexture *shadowMapClientMap{nullptr}; + video::ITexture *shadowMapClientMapFuture{nullptr}; video::ITexture *shadowMapTextureFinal{nullptr}; video::ITexture *shadowMapTextureDynamicObjects{nullptr}; video::ITexture *shadowMapTextureColors{nullptr}; @@ -120,11 +121,12 @@ private: float m_shadow_map_max_distance; float m_shadow_map_texture_size; float m_time_day{0.0f}; - float m_update_delta; int m_shadow_samples; bool m_shadow_map_texture_32bit; bool m_shadows_enabled; bool m_shadow_map_colored; + u8 m_map_shadow_update_frames; /* Use this number of frames to update map shaodw */ + u8 m_current_frame{0}; /* Current frame */ video::ECOLOR_FORMAT m_texture_format{video::ECOLOR_FORMAT::ECF_R16F}; video::ECOLOR_FORMAT m_texture_format_color{video::ECOLOR_FORMAT::ECF_R16G16}; @@ -135,6 +137,7 @@ private: std::string readShaderFile(const std::string &path); s32 depth_shader{-1}; + s32 depth_shader_entities{-1}; s32 depth_shader_trans{-1}; s32 mixcsm_shader{-1}; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 6791fccf5..faf839b3a 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -272,7 +272,7 @@ void set_default_settings() settings->setDefault("shadow_map_color", "false"); settings->setDefault("shadow_filters", "1"); settings->setDefault("shadow_poisson_filter", "true"); - settings->setDefault("shadow_update_time", "0.2"); + settings->setDefault("shadow_update_frames", "8"); settings->setDefault("shadow_soft_radius", "1.0"); settings->setDefault("shadow_sky_body_orbit_tilt", "0.0"); -- cgit v1.2.3 From 442e48b84fea511badf108cedc2a6b43d79fd852 Mon Sep 17 00:00:00 2001 From: x2048 Date: Thu, 12 Aug 2021 20:07:09 +0200 Subject: Move updating shadows outside of RenderingCore::drawAll. (#11491) Fixes indirect rendering modes such as some 3D modes mentioned in #11437 and undersampled rendering. Does not fully fix anaglyph 3d mode. --- src/client/render/core.cpp | 13 +++--- src/client/shadows/dynamicshadowsrender.cpp | 61 ++++++++++++--------------- src/client/shadows/dynamicshadowsrender.h | 4 +- src/client/shadows/shadowsScreenQuad.cpp | 12 ++---- src/client/shadows/shadowsScreenQuad.h | 11 ++++- src/client/shadows/shadowsshadercallbacks.cpp | 16 ++----- src/client/shadows/shadowsshadercallbacks.h | 14 ++++++ 7 files changed, 65 insertions(+), 66 deletions(-) (limited to 'src/client/shadows/dynamicshadowsrender.cpp') diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp index 4a820f583..f151832f3 100644 --- a/src/client/render/core.cpp +++ b/src/client/render/core.cpp @@ -76,19 +76,18 @@ void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_min draw_wield_tool = _draw_wield_tool; draw_crosshair = _draw_crosshair; + if (shadow_renderer) + shadow_renderer->update(); + beforeDraw(); drawAll(); } void RenderingCore::draw3D() { - if (shadow_renderer) { - // Shadow renderer will handle the draw stage - shadow_renderer->setClearColor(skycolor); - shadow_renderer->update(); - } else { - smgr->drawAll(); - } + smgr->drawAll(); + if (shadow_renderer) + shadow_renderer->drawDebug(); driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); if (!show_hud) diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 350586225..a913a9290 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -146,11 +146,6 @@ void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node) } } -void ShadowRenderer::setClearColor(video::SColor ClearColor) -{ - m_clear_color = ClearColor; -} - void ShadowRenderer::updateSMTextures() { if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) { @@ -242,6 +237,7 @@ void ShadowRenderer::updateSMTextures() // This is also handled in ClientMap. if (m_current_frame == m_map_shadow_update_frames - 1) { if (m_shadow_map_colored) { + m_driver->setRenderTarget(0, false, false); m_driver->setRenderTarget(shadowMapTextureColors, true, false, video::SColor(255, 255, 255, 255)); } @@ -273,7 +269,6 @@ void ShadowRenderer::updateSMTextures() void ShadowRenderer::update(video::ITexture *outputTarget) { if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) { - m_smgr->drawAll(); return; } @@ -308,36 +303,34 @@ void ShadowRenderer::update(video::ITexture *outputTarget) m_driver->setRenderTarget(0, false, false); } // end for lights + } +} - // now render the actual MT render pass - m_driver->setRenderTarget(outputTarget, true, true, m_clear_color); - m_smgr->drawAll(); - - /* this code just shows shadows textures in screen and in ONLY for debugging*/ - #if 0 - // this is debug, ignore for now. - m_driver->draw2DImage(shadowMapTextureFinal, - core::rect(0, 50, 128, 128 + 50), - core::rect({0, 0}, shadowMapTextureFinal->getSize())); - - m_driver->draw2DImage(shadowMapClientMap, - core::rect(0, 50 + 128, 128, 128 + 50 + 128), - core::rect({0, 0}, shadowMapTextureFinal->getSize())); - m_driver->draw2DImage(shadowMapTextureDynamicObjects, - core::rect(0, 128 + 50 + 128, 128, - 128 + 50 + 128 + 128), - core::rect({0, 0}, shadowMapTextureDynamicObjects->getSize())); - - if (m_shadow_map_colored) { - - m_driver->draw2DImage(shadowMapTextureColors, - core::rect(128,128 + 50 + 128 + 128, - 128 + 128, 128 + 50 + 128 + 128 + 128), - core::rect({0, 0}, shadowMapTextureColors->getSize())); - } - #endif - m_driver->setRenderTarget(0, false, false); +void ShadowRenderer::drawDebug() +{ + /* this code just shows shadows textures in screen and in ONLY for debugging*/ + #if 0 + // this is debug, ignore for now. + m_driver->draw2DImage(shadowMapTextureFinal, + core::rect(0, 50, 128, 128 + 50), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); + + m_driver->draw2DImage(shadowMapClientMap, + core::rect(0, 50 + 128, 128, 128 + 50 + 128), + core::rect({0, 0}, shadowMapTextureFinal->getSize())); + m_driver->draw2DImage(shadowMapTextureDynamicObjects, + core::rect(0, 128 + 50 + 128, 128, + 128 + 50 + 128 + 128), + core::rect({0, 0}, shadowMapTextureDynamicObjects->getSize())); + + if (m_shadow_map_colored) { + + m_driver->draw2DImage(shadowMapTextureColors, + core::rect(128,128 + 50 + 128 + 128, + 128 + 128, 128 + 50 + 128 + 128 + 128), + core::rect({0, 0}, shadowMapTextureColors->getSize())); } + #endif } diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index 52b24a18f..e4b3c3e22 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -73,9 +73,8 @@ public: E_SHADOW_MODE shadowMode = ESM_BOTH); void removeNodeFromShadowList(scene::ISceneNode *node); - void setClearColor(video::SColor ClearColor); - void update(video::ITexture *outputTarget = nullptr); + void drawDebug(); video::ITexture *get_texture() { @@ -112,7 +111,6 @@ private: video::ITexture *shadowMapTextureFinal{nullptr}; video::ITexture *shadowMapTextureDynamicObjects{nullptr}; video::ITexture *shadowMapTextureColors{nullptr}; - video::SColor m_clear_color{0x0}; std::vector m_light_list; std::vector m_shadow_node_array; diff --git a/src/client/shadows/shadowsScreenQuad.cpp b/src/client/shadows/shadowsScreenQuad.cpp index c36ee0d60..5f6d38157 100644 --- a/src/client/shadows/shadowsScreenQuad.cpp +++ b/src/client/shadows/shadowsScreenQuad.cpp @@ -51,17 +51,11 @@ void shadowScreenQuadCB::OnSetConstants( video::IMaterialRendererServices *services, s32 userData) { s32 TextureId = 0; - services->setPixelShaderConstant( - services->getPixelShaderConstantID("ShadowMapClientMap"), - &TextureId, 1); + m_sm_client_map_setting.set(&TextureId, services); TextureId = 1; - services->setPixelShaderConstant( - services->getPixelShaderConstantID("ShadowMapClientMapTraslucent"), - &TextureId, 1); + m_sm_client_map_trans_setting.set(&TextureId, services); TextureId = 2; - services->setPixelShaderConstant( - services->getPixelShaderConstantID("ShadowMapSamplerdynamic"), - &TextureId, 1); + m_sm_dynamic_sampler_setting.set(&TextureId, services); } diff --git a/src/client/shadows/shadowsScreenQuad.h b/src/client/shadows/shadowsScreenQuad.h index e6cc95957..c18be9a2b 100644 --- a/src/client/shadows/shadowsScreenQuad.h +++ b/src/client/shadows/shadowsScreenQuad.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include #include +#include "client/shader.h" class shadowScreenQuad { @@ -38,8 +39,16 @@ private: class shadowScreenQuadCB : public video::IShaderConstantSetCallBack { public: - shadowScreenQuadCB(){}; + shadowScreenQuadCB() : + m_sm_client_map_setting("ShadowMapClientMap"), + m_sm_client_map_trans_setting("ShadowMapClientMapTraslucent"), + m_sm_dynamic_sampler_setting("ShadowMapSamplerdynamic") + {} virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData); +private: + CachedPixelShaderSetting m_sm_client_map_setting; + CachedPixelShaderSetting m_sm_client_map_trans_setting; + CachedPixelShaderSetting m_sm_dynamic_sampler_setting; }; diff --git a/src/client/shadows/shadowsshadercallbacks.cpp b/src/client/shadows/shadowsshadercallbacks.cpp index 2f5797084..65a63f49c 100644 --- a/src/client/shadows/shadowsshadercallbacks.cpp +++ b/src/client/shadows/shadowsshadercallbacks.cpp @@ -28,17 +28,9 @@ void ShadowDepthShaderCB::OnSetConstants( lightMVP *= driver->getTransform(video::ETS_VIEW); lightMVP *= driver->getTransform(video::ETS_WORLD); - services->setVertexShaderConstant( - services->getPixelShaderConstantID("LightMVP"), - lightMVP.pointer(), 16); - - services->setVertexShaderConstant( - services->getPixelShaderConstantID("MapResolution"), &MapRes, 1); - services->setVertexShaderConstant( - services->getPixelShaderConstantID("MaxFar"), &MaxFar, 1); - + m_light_mvp_setting.set(lightMVP.pointer(), services); + m_map_resolution_setting.set(&MapRes, services); + m_max_far_setting.set(&MaxFar, services); s32 TextureId = 0; - services->setPixelShaderConstant( - services->getPixelShaderConstantID("ColorMapSampler"), &TextureId, - 1); + m_color_map_sampler_setting.set(&TextureId, services); } diff --git a/src/client/shadows/shadowsshadercallbacks.h b/src/client/shadows/shadowsshadercallbacks.h index 43ad489f2..3549567c3 100644 --- a/src/client/shadows/shadowsshadercallbacks.h +++ b/src/client/shadows/shadowsshadercallbacks.h @@ -21,14 +21,28 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include #include +#include "client/shader.h" class ShadowDepthShaderCB : public video::IShaderConstantSetCallBack { public: + ShadowDepthShaderCB() : + m_light_mvp_setting("LightMVP"), + m_map_resolution_setting("MapResolution"), + m_max_far_setting("MaxFar"), + m_color_map_sampler_setting("ColorMapSampler") + {} + void OnSetMaterial(const video::SMaterial &material) override {} void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override; f32 MaxFar{2048.0f}, MapRes{1024.0f}; + +private: + CachedVertexShaderSetting m_light_mvp_setting; + CachedVertexShaderSetting m_map_resolution_setting; + CachedVertexShaderSetting m_max_far_setting; + CachedPixelShaderSetting m_color_map_sampler_setting; }; -- cgit v1.2.3