diff --git a/assets/shaders/terrain.frag b/assets/shaders/terrain.frag index 64104b0e..194e23cf 100644 --- a/assets/shaders/terrain.frag +++ b/assets/shaders/terrain.frag @@ -52,14 +52,8 @@ float calcShadow() { vec3 norm = normalize(Normal); vec3 lightDir = normalize(-uLightDir); float bias = max(0.005 * (1.0 - dot(norm, lightDir)), 0.001); - float shadow = 0.0; - vec2 texelSize = vec2(1.0 / 2048.0); - for (int x = -1; x <= 1; x++) { - for (int y = -1; y <= 1; y++) { - shadow += texture(uShadowMap, vec3(proj.xy + vec2(x, y) * texelSize, proj.z - bias)); - } - } - shadow /= 9.0; + // Single hardware PCF tap — GL_LINEAR + compare mode gives 2×2 bilinear PCF for free + float shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias)); return mix(1.0, shadow, coverageFade); } diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index b6b517c3..d2146fc7 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -223,7 +223,7 @@ private: void shutdownPostProcess(); // Shadow mapping - static constexpr int SHADOW_MAP_SIZE = 2048; + static constexpr int SHADOW_MAP_SIZE = 1024; uint32_t shadowFBO = 0; uint32_t shadowDepthTex = 0; uint32_t shadowShaderProgram = 0; @@ -231,6 +231,7 @@ private: glm::vec3 shadowCenter = glm::vec3(0.0f); bool shadowCenterInitialized = false; bool shadowsEnabled = false; + int shadowFrameCounter_ = 0; // throttle: only re-render depth map every 2 frames public: void setShadowsEnabled(bool enabled) { shadowsEnabled = enabled; } diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index 31216866..3c19b500 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -153,14 +153,8 @@ bool CharacterRenderer::initialize() { float edgeDist = max(abs(proj.x - 0.5), abs(proj.y - 0.5)); float coverageFade = 1.0 - smoothstep(0.40, 0.49, edgeDist); float bias = max(0.005 * (1.0 - abs(dot(normal, lightDir))), 0.001); - shadow = 0.0; - vec2 texelSize = vec2(1.0 / 2048.0); - for (int sx = -1; sx <= 1; sx++) { - for (int sy = -1; sy <= 1; sy++) { - shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias)); - } - } - shadow /= 9.0; + // Single hardware PCF tap — GL_LINEAR + compare mode gives 2×2 bilinear PCF for free + shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias)); shadow = mix(1.0, shadow, coverageFade); } } diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index fe689a18..7828d911 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -391,14 +391,8 @@ bool M2Renderer::initialize(pipeline::AssetManager* assets) { float edgeDist = max(abs(proj.x - 0.5), abs(proj.y - 0.5)); float coverageFade = 1.0 - smoothstep(0.40, 0.49, edgeDist); float bias = max(0.005 * (1.0 - abs(dot(normal, lightDir))), 0.001); - shadow = 0.0; - vec2 texelSize = vec2(1.0 / 2048.0); - for (int sx = -1; sx <= 1; sx++) { - for (int sy = -1; sy <= 1; sy++) { - shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias)); - } - } - shadow /= 9.0; + // Single hardware PCF tap — GL_LINEAR + compare mode gives 2×2 bilinear PCF for free + shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias)); shadow = mix(1.0, shadow, coverageFade); } } diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 63518232..9aedb0a6 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -2449,9 +2449,11 @@ void Renderer::renderWorld(game::World* world, game::GameHandler* gameHandler) { lastWMORenderMs = 0.0; lastM2RenderMs = 0.0; - // Shadow pass (before main scene) + // Shadow pass (before main scene) — throttled to every 2 frames (depth buffer persists) if (shadowsEnabled && shadowFBO && shadowShaderProgram && terrainLoaded) { - renderShadowPass(); + if (shadowFrameCounter_++ % 2 == 0) { + renderShadowPass(); + } } else { // Clear shadow maps when disabled if (terrainRenderer) terrainRenderer->clearShadowMap(); diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index f9b6ae9d..f32affc8 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -161,14 +161,8 @@ bool WMORenderer::initialize(pipeline::AssetManager* assets) { float edgeDist = max(abs(proj.x - 0.5), abs(proj.y - 0.5)); float coverageFade = 1.0 - smoothstep(0.40, 0.49, edgeDist); float bias = max(0.005 * (1.0 - dot(normal, lightDir)), 0.001); - shadow = 0.0; - vec2 texelSize = vec2(1.0 / 2048.0); - for (int sx = -1; sx <= 1; sx++) { - for (int sy = -1; sy <= 1; sy++) { - shadow += texture(uShadowMap, vec3(proj.xy + vec2(sx, sy) * texelSize, proj.z - bias)); - } - } - shadow /= 9.0; + // Single hardware PCF tap — GL_LINEAR + compare mode gives 2×2 bilinear PCF for free + shadow = texture(uShadowMap, vec3(proj.xy, proj.z - bias)); shadow = mix(1.0, shadow, coverageFade); } }