Add shadow toggle (F4) and distance-based WMO group culling

Shadow toggle allows disabling shadow pass for performance testing.
Distance culling skips WMO groups beyond 200 units. Occlusion queries
disabled by default as overhead outweighs benefits in dense scenes.
This commit is contained in:
Kelsi 2026-02-05 16:11:24 -08:00
parent 83ef27c570
commit ebf349ec7c
5 changed files with 29 additions and 11 deletions

View file

@ -184,7 +184,13 @@ private:
glm::mat4 lightSpaceMatrix = glm::mat4(1.0f);
glm::vec3 shadowCenter = glm::vec3(0.0f);
bool shadowCenterInitialized = false;
bool shadowsEnabled = true;
public:
void setShadowsEnabled(bool enabled) { shadowsEnabled = enabled; }
bool areShadowsEnabled() const { return shadowsEnabled; }
private:
void initShadowMap();
void renderShadowPass();
uint32_t compileShadowShader();

View file

@ -428,7 +428,7 @@ private:
bool frustumCulling = true;
bool portalCulling = false; // Disabled by default - needs debugging
bool distanceCulling = false; // Disabled - causes ground to disappear
bool occlusionCulling = true; // GPU occlusion queries
bool occlusionCulling = false; // GPU occlusion queries - disabled, adds overhead
float maxGroupDistance = 500.0f;
float maxGroupDistanceSq = 250000.0f; // maxGroupDistance^2
uint32_t lastDrawCalls = 0;

View file

@ -255,6 +255,14 @@ void Application::run() {
LOG_INFO("Performance HUD: ", enabled ? "ON" : "OFF");
}
}
// F4: Toggle shadows
else if (event.key.keysym.scancode == SDL_SCANCODE_F4) {
if (renderer) {
bool enabled = !renderer->areShadowsEnabled();
renderer->setShadowsEnabled(enabled);
LOG_INFO("Shadows: ", enabled ? "ON" : "OFF");
}
}
// T: Toggle teleporter panel
else if (event.key.keysym.scancode == SDL_SCANCODE_T) {
if (state == AppState::IN_GAME && uiManager) {

View file

@ -1039,8 +1039,14 @@ void Renderer::renderWorld(game::World* world) {
lastM2RenderMs = 0.0;
// Shadow pass (before main scene)
if (shadowFBO && shadowShaderProgram && terrainLoaded) {
if (shadowsEnabled && shadowFBO && shadowShaderProgram && terrainLoaded) {
renderShadowPass();
} else {
// Clear shadow maps when disabled
if (terrainRenderer) terrainRenderer->clearShadowMap();
if (wmoRenderer) wmoRenderer->clearShadowMap();
if (m2Renderer) m2Renderer->clearShadowMap();
if (characterRenderer) characterRenderer->clearShadowMap();
}
// Bind HDR scene framebuffer for world rendering

View file

@ -645,7 +645,7 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm:
continue;
}
// Occlusion culling check (uses previous frame results)
// Occlusion culling check first (uses previous frame results)
if (occlusionCulling && isGroupOccluded(instance.id, static_cast<uint32_t>(gi))) {
lastOcclusionCulledGroups++;
continue;
@ -654,14 +654,12 @@ void WMORenderer::render(const Camera& camera, const glm::mat4& view, const glm:
if (gi < instance.worldGroupBounds.size()) {
const auto& [gMin, gMax] = instance.worldGroupBounds[gi];
// Distance culling: skip groups whose center is too far
if (distanceCulling) {
glm::vec3 groupCenter = (gMin + gMax) * 0.5f;
float distSq = glm::dot(groupCenter - camPos, groupCenter - camPos);
if (distSq > maxGroupDistanceSq) {
lastDistanceCulledGroups++;
continue;
}
// Hard distance cutoff - skip groups entirely if closest point is too far
glm::vec3 closestPoint = glm::clamp(camPos, gMin, gMax);
float distSq = glm::dot(closestPoint - camPos, closestPoint - camPos);
if (distSq > 40000.0f) { // Beyond 200 units - hard skip
lastDistanceCulledGroups++;
continue;
}
// Frustum culling