From 760b20504f0574512f90e179f3ae763950a26d48 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 9 Nov 2025 13:33:55 +0100 Subject: [PATCH] Support array textures in shadow renderer (the lazy way) --- .../shaders/shadow/pass1/opengl_fragment.glsl | 24 +++--- .../shaders/shadow/pass1/opengl_vertex.glsl | 13 ++-- .../shadow/pass1_trans/opengl_fragment.glsl | 30 ++++---- .../shadow/pass1_trans/opengl_vertex.glsl | 13 ++-- src/client/node_visuals.cpp | 3 - src/client/shadows/dynamicshadowsrender.cpp | 77 ++++++++++++++----- src/client/shadows/dynamicshadowsrender.h | 13 ++-- 7 files changed, 108 insertions(+), 65 deletions(-) diff --git a/client/shaders/shadow/pass1/opengl_fragment.glsl b/client/shaders/shadow/pass1/opengl_fragment.glsl index 99bfbc4147..7f079417e8 100644 --- a/client/shaders/shadow/pass1/opengl_fragment.glsl +++ b/client/shaders/shadow/pass1/opengl_fragment.glsl @@ -1,18 +1,22 @@ -// FIXME missing array texture handling -uniform sampler2D ColorMapSampler; +#ifdef USE_ARRAY_TEXTURE + uniform mediump sampler2DArray baseTexture; +#else + uniform sampler2D baseTexture; +#endif varying vec4 tPos; -#ifdef GL_ES -varying mediump vec2 varTexCoord; -#else -centroid varying vec2 varTexCoord; -#endif +CENTROID_ VARYING_ mediump vec2 varTexCoord; +CENTROID_ VARYING_ float varTexLayer; // actually int void main() { - vec4 col = texture2D(ColorMapSampler, varTexCoord); - // FIXME: magic number??? - if (col.a < 0.70) +#ifdef USE_ARRAY_TEXTURE + vec4 base = texture(baseTexture, vec3(varTexCoord, varTexLayer)).rgba; +#else + vec4 base = texture2D(baseTexture, varTexCoord).rgba; +#endif + // (this totally ignores the node's alpha mode) + if (base.a < 0.70) discard; float depth = 0.5 + tPos.z * 0.5; diff --git a/client/shaders/shadow/pass1/opengl_vertex.glsl b/client/shaders/shadow/pass1/opengl_vertex.glsl index e0d460a3cf..295dde72c6 100644 --- a/client/shaders/shadow/pass1/opengl_vertex.glsl +++ b/client/shaders/shadow/pass1/opengl_vertex.glsl @@ -6,11 +6,8 @@ uniform float xyPerspectiveBias0; uniform float xyPerspectiveBias1; uniform float zPerspectiveBias; -#ifdef GL_ES -varying mediump vec2 varTexCoord; -#else -centroid varying vec2 varTexCoord; -#endif +CENTROID_ VARYING_ mediump vec2 varTexCoord; +CENTROID_ VARYING_ float varTexLayer; // actually int vec4 getRelativePosition(in vec4 position) { @@ -45,5 +42,9 @@ void main() tPos = applyPerspectiveDistortion(pos); gl_Position = vec4(tPos.xyz, 1.0); - varTexCoord = (mTexture * vec4(inTexCoord0.xy, 0.0, 1.0)).xy; + + varTexCoord = (mTexture * vec4(inTexCoord0.xy, 1.0, 1.0)).st; +#ifdef USE_ARRAY_TEXTURE + varTexLayer = inVertexAux; +#endif } diff --git a/client/shaders/shadow/pass1_trans/opengl_fragment.glsl b/client/shaders/shadow/pass1_trans/opengl_fragment.glsl index 3746a42c54..a13877b58e 100644 --- a/client/shaders/shadow/pass1_trans/opengl_fragment.glsl +++ b/client/shaders/shadow/pass1_trans/opengl_fragment.glsl @@ -1,12 +1,12 @@ -// FIXME missing array texture handling -uniform sampler2D ColorMapSampler; +#ifdef USE_ARRAY_TEXTURE + uniform mediump sampler2DArray baseTexture; +#else + uniform sampler2D baseTexture; +#endif varying vec4 tPos; -#ifdef GL_ES -varying mediump vec2 varTexCoord; -#else -centroid varying vec2 varTexCoord; -#endif +CENTROID_ VARYING_ mediump vec2 varTexCoord; +CENTROID_ VARYING_ float varTexLayer; // actually int #ifdef COLORED_SHADOWS varying vec3 varColor; @@ -21,27 +21,27 @@ float packColor(vec3 color) + floor(color.g * c_precision + 0.5) * c_precisionp1 + floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1; } - -const vec3 black = vec3(0.0); #endif void main() { - vec4 col = texture2D(ColorMapSampler, varTexCoord); +#ifdef USE_ARRAY_TEXTURE + vec4 base = texture(baseTexture, vec3(varTexCoord, varTexLayer)).rgba; +#else + vec4 base = texture2D(baseTexture, varTexCoord).rgba; +#endif #ifndef COLORED_SHADOWS - if (col.a < 0.5) + if (base.a < 0.5) discard; #endif float depth = 0.5 + tPos.z * 0.5; - // ToDo: Liso: Apply movement on waving plants // depth in [0, 1] for texture - //col.rgb = col.a == 1.0 ? vec3(1.0) : col.rgb; #ifdef COLORED_SHADOWS - col.rgb *= varColor.rgb; + base.rgb *= varColor.rgb; // premultiply color alpha (see-through side) - float packedColor = packColor(col.rgb * (1.0 - col.a)); + float packedColor = packColor(base.rgb * (1.0 - base.a)); gl_FragColor = vec4(depth, packedColor, 0.0,1.0); #else gl_FragColor = vec4(depth, 0.0, 0.0, 1.0); diff --git a/client/shaders/shadow/pass1_trans/opengl_vertex.glsl b/client/shaders/shadow/pass1_trans/opengl_vertex.glsl index 9a7a452bf4..e4ce21bbd7 100644 --- a/client/shaders/shadow/pass1_trans/opengl_vertex.glsl +++ b/client/shaders/shadow/pass1_trans/opengl_vertex.glsl @@ -9,11 +9,8 @@ uniform float xyPerspectiveBias0; uniform float xyPerspectiveBias1; uniform float zPerspectiveBias; -#ifdef GL_ES -varying mediump vec2 varTexCoord; -#else -centroid varying vec2 varTexCoord; -#endif +CENTROID_ VARYING_ mediump vec2 varTexCoord; +CENTROID_ VARYING_ float varTexLayer; // actually int vec4 getRelativePosition(in vec4 position) { @@ -48,7 +45,11 @@ void main() tPos = applyPerspectiveDistortion(pos); gl_Position = vec4(tPos.xyz, 1.0); - varTexCoord = inTexCoord0.xy; + + varTexCoord = (mTexture * vec4(inTexCoord0.xy, 1.0, 1.0)).st; +#ifdef USE_ARRAY_TEXTURE + varTexLayer = inVertexAux; +#endif #ifdef COLORED_SHADOWS varColor = inVertexColor.rgb; diff --git a/src/client/node_visuals.cpp b/src/client/node_visuals.cpp index bc7c7b92c3..c674dbfdaf 100644 --- a/src/client/node_visuals.cpp +++ b/src/client/node_visuals.cpp @@ -192,9 +192,6 @@ static size_t getArrayTextureMax(IShaderSource *shdsrc) // must support sampling from them if (!shdsrc->supportsSampler2DArray()) return 0; - // shadow shaders can't handle array textures yet (TODO) - if (g_settings->getBool("enable_dynamic_shadows")) - return 0; u32 n = driver->getLimits().MaxArrayTextureImages; constexpr u32 type_max = std::numeric_limits::max(); diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 190ff36720..aa4a1f3c3a 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -49,13 +49,16 @@ ShadowRenderer::~ShadowRenderer() // call to disable releases dynamically allocated resources disable(); - if (m_shadow_depth_cb) { - m_shadow_depth_cb->drop(); - m_shadow_depth_cb = nullptr; + for (auto *ptr : m_shadow_depth_cb) { + if (ptr) + ptr->drop(); } - if (m_shadow_depth_trans_cb) { - m_shadow_depth_trans_cb->drop(); - m_shadow_depth_trans_cb = nullptr; + m_shadow_depth_cb.clear(); + + auto *gpu = m_driver->getGPUProgrammingServices(); + for (auto id : {depth_shader, depth_shader_a, depth_shader_trans, depth_shader_trans_a}) { + if (id != video::EMT_INVALID) + gpu->deleteShaderMaterial(id); } delete m_screen_quad; @@ -231,14 +234,14 @@ void ShadowRenderer::updateSMTextures() video::ECOLOR_FORMAT frt; if (m_shadow_map_texture_32bit) { if (m_shadow_map_colored) - frt = video::ECOLOR_FORMAT::ECF_A32B32G32R32F; + frt = video::ECF_A32B32G32R32F; else - frt = video::ECOLOR_FORMAT::ECF_R32F; + frt = video::ECF_R32F; } else { if (m_shadow_map_colored) - frt = video::ECOLOR_FORMAT::ECF_A16B16G16R16F; + frt = video::ECF_A16B16G16R16F; else - frt = video::ECOLOR_FORMAT::ECF_R16F; + frt = video::ECF_R16F; } shadowMapTextureFinal = getSMTexture( std::string("shadowmap_final_") + itos(m_shadow_map_texture_size), @@ -271,7 +274,7 @@ void ShadowRenderer::updateSMTextures() // Update SM incrementally: for (DirectionalLight &light : m_light_list) { // Static shader values. - for (auto *cb : {m_shadow_depth_cb, m_shadow_depth_trans_cb}) { + for (auto *cb : m_shadow_depth_cb) { if (cb) { cb->MapRes = (u32)m_shadow_map_texture_size; cb->MaxFar = (f32)m_shadow_map_max_distance * BS; @@ -292,7 +295,6 @@ void ShadowRenderer::updateSMTextures() // This is also handled in ClientMap. if (m_current_frame == m_map_shadow_update_frames - 1 || m_force_update_shadow_map) { if (m_shadow_map_colored) { - m_driver->setRenderTarget(0, false, false); m_driver->setRenderTarget(shadowMapTextureColors, true, false, video::SColor(255, 255, 255, 255)); } @@ -340,7 +342,10 @@ void ShadowRenderer::update(video::ITexture *outputTarget) // Static shader values for entities are set in updateSMTextures // SM texture for entities is not updated incrementally and // must by updated using current player position. - m_shadow_depth_cb->CameraPos = light.getPlayerPos(); + for (auto *cb : m_shadow_depth_cb) { + if (cb) + cb->CameraPos = light.getPlayerPos(); + } // render shadows for the non-map objects. m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true, @@ -435,10 +440,19 @@ void ShadowRenderer::renderShadowMap(video::ITexture *target, mat.FrontfaceCulling = false; } + /* + * Here we unconditionally replace the material shader with our custom ones + * to render the depth map. + * Be warned that this is a very flawed approach and the reason why waving + * doesn't work or why the node alpha mode is totally ignored. + * Array texture support was tacked on but this should really be rewritten: + * The shadow map code should be part of nodes_shader and activated on demand. + */ + bool array_tex = mat.getTexture(0) && mat.getTexture(0)->getType() == video::ETT_2D_ARRAY; if (m_shadow_map_colored && is_transparent_pass) { - mat.MaterialType = depth_shader_trans; + mat.MaterialType = array_tex ? depth_shader_trans_a : depth_shader_trans; } else { - mat.MaterialType = depth_shader; + mat.MaterialType = array_tex ? depth_shader_a : depth_shader; mat.BlendOperation = video::EBO_MIN; } }; @@ -478,6 +492,8 @@ void ShadowRenderer::renderShadowObjects( auto ¤t_mat = shadow_node.node->getMaterial(m); BufferMaterialList.push_back(current_mat.MaterialType); + // Note: this suffers from the same misdesign and will break once we + // start doing more special shader things for entities. current_mat.MaterialType = depth_shader; BufferMaterialCullingList.emplace_back( @@ -517,22 +533,43 @@ void ShadowRenderer::createShaders() { auto *shdsrc = m_client->getShaderSource(); - assert(!m_shadow_depth_cb); + assert(m_shadow_depth_cb.empty()); + + ShaderConstants a_const; + a_const["USE_ARRAY_TEXTURE"] = 1; { - m_shadow_depth_cb = new ShadowDepthUniformSetter(); + auto *cb = new ShadowDepthUniformSetter(); + m_shadow_depth_cb.push_back(cb); u32 shader_id = shdsrc->getShader("shadow/pass1", {}, - video::EMT_SOLID, m_shadow_depth_cb); + video::EMT_SOLID, cb); depth_shader = shdsrc->getShaderInfo(shader_id).material; } + if (shdsrc->supportsSampler2DArray()) { + auto *cb = new ShadowDepthUniformSetter(); + m_shadow_depth_cb.push_back(cb); + u32 shader_id = shdsrc->getShader("shadow/pass1", a_const, + video::EMT_SOLID, cb); + depth_shader_a = shdsrc->getShaderInfo(shader_id).material; + } + if (m_shadow_map_colored) { - m_shadow_depth_trans_cb = new ShadowDepthUniformSetter(); + auto *cb = new ShadowDepthUniformSetter(); + m_shadow_depth_cb.push_back(cb); u32 shader_id = shdsrc->getShader("shadow/pass1_trans", {}, - video::EMT_SOLID, m_shadow_depth_trans_cb); + video::EMT_SOLID, cb); depth_shader_trans = shdsrc->getShaderInfo(shader_id).material; } + if (m_shadow_map_colored && shdsrc->supportsSampler2DArray()) { + auto *cb = new ShadowDepthUniformSetter(); + m_shadow_depth_cb.push_back(cb); + u32 shader_id = shdsrc->getShader("shadow/pass1_trans", a_const, + video::EMT_SOLID, cb); + depth_shader_trans_a = shdsrc->getShaderInfo(shader_id).material; + } + { auto *shadow_mix_cb = new ShadowScreenQuadUniformSetter(); u32 shader_id = shdsrc->getShader("shadow/pass2", {}, diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index b329dbc527..f8912c59c2 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -138,17 +138,20 @@ private: f32 m_perspective_bias_xy; f32 m_perspective_bias_z; - video::ECOLOR_FORMAT m_texture_format{video::ECOLOR_FORMAT::ECF_R16F}; - video::ECOLOR_FORMAT m_texture_format_color{video::ECOLOR_FORMAT::ECF_R16G16}; + video::ECOLOR_FORMAT m_texture_format{video::ECF_R16F}; + video::ECOLOR_FORMAT m_texture_format_color{video::ECF_R16G16}; // Shadow Shader stuff void createShaders(); - video::E_MATERIAL_TYPE depth_shader, depth_shader_trans; + // _a suffix is with support for array textures + video::E_MATERIAL_TYPE depth_shader{video::EMT_INVALID}, + depth_shader_a{video::EMT_INVALID}; + video::E_MATERIAL_TYPE depth_shader_trans{video::EMT_INVALID}, + depth_shader_trans_a{video::EMT_INVALID}; - ShadowDepthUniformSetter *m_shadow_depth_cb{nullptr}; - ShadowDepthUniformSetter *m_shadow_depth_trans_cb{nullptr}; + std::vector m_shadow_depth_cb; ShadowScreenQuad *m_screen_quad{nullptr}; };