mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Improve shadow performance: halve resolution, 9x fewer PCF taps, throttle depth pass
- SHADOW_MAP_SIZE 2048→1024: 4x fewer pixels rasterized in depth pass - Replace 9-tap manual PCF loop with single hardware PCF tap in all 4 receiver shaders (terrain.frag, wmo_renderer, m2_renderer, character_renderer). GL_LINEAR + GL_COMPARE_REF_TO_TEXTURE already gives 2×2 bilinear PCF per tap for free, so quality is maintained while doing 9x fewer texture fetches. - Throttle shadow depth pass to every 2 frames; OpenGL depth texture persists between frames so receivers always have a valid shadow map. 1-frame lag at 60 fps is invisible.
This commit is contained in:
parent
7ab25c63c9
commit
c4d0a21713
6 changed files with 14 additions and 35 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue