From 2124761ea87561d2e5d82cf5d911c75351306ff9 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Feb 2026 04:48:26 -0800 Subject: [PATCH] Add distance culling to shadow passes for CPU-bound shadow perf All three shadow renderers (WMO, M2, Character) were iterating every loaded instance with zero culling. Now skip instances outside the 180-unit shadow frustum radius via squared-distance check. --- src/rendering/character_renderer.cpp | 8 +++++++- src/rendering/m2_renderer.cpp | 8 +++++++- src/rendering/wmo_renderer.cpp | 7 ++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/rendering/character_renderer.cpp b/src/rendering/character_renderer.cpp index 4ff49bc7..c9155a16 100644 --- a/src/rendering/character_renderer.cpp +++ b/src/rendering/character_renderer.cpp @@ -2302,7 +2302,8 @@ bool CharacterRenderer::initializeShadow(VkRenderPass shadowRenderPass) { return true; } -void CharacterRenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix) { +void CharacterRenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix, + const glm::vec3& shadowCenter, float shadowRadius) { if (!shadowPipeline_ || !shadowParamsSet_) return; if (instances.empty() || models.empty()) return; @@ -2316,10 +2317,15 @@ void CharacterRenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& light struct ShadowPush { glm::mat4 lightSpaceMatrix; glm::mat4 model; }; + const float shadowRadiusSq = shadowRadius * shadowRadius; for (auto& pair : instances) { auto& inst = pair.second; if (!inst.visible) continue; + // Distance cull against shadow frustum + glm::vec3 diff = inst.position - shadowCenter; + if (glm::dot(diff, diff) > shadowRadiusSq) continue; + auto modelIt = models.find(inst.modelId); if (modelIt == models.end()) continue; const M2ModelGPU& gpuModel = modelIt->second; diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 63fe6427..9644d187 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -2607,11 +2607,13 @@ bool M2Renderer::initializeShadow(VkRenderPass shadowRenderPass) { return true; } -void M2Renderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix, float globalTime) { +void M2Renderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix, float globalTime, + const glm::vec3& shadowCenter, float shadowRadius) { if (!shadowPipeline_ || !shadowParamsSet_) return; if (instances.empty() || models.empty()) return; struct ShadowPush { glm::mat4 lightSpaceMatrix; glm::mat4 model; }; + const float shadowRadiusSq = shadowRadius * shadowRadius; // Helper lambda to draw instances with a given foliageSway setting auto drawPass = [&](bool foliagePass) { @@ -2641,6 +2643,10 @@ void M2Renderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMa const M2ModelGPU* currentModel = nullptr; for (const auto& instance : instances) { + // Distance cull against shadow frustum + glm::vec3 diff = instance.position - shadowCenter; + if (glm::dot(diff, diff) > shadowRadiusSq) continue; + auto modelIt = models.find(instance.modelId); if (modelIt == models.end()) continue; const M2ModelGPU& model = modelIt->second; diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index 76a584bc..97e1946e 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -1671,7 +1671,8 @@ bool WMORenderer::initializeShadow(VkRenderPass shadowRenderPass) { return true; } -void WMORenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix) { +void WMORenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceMatrix, + const glm::vec3& shadowCenter, float shadowRadius) { if (!shadowPipeline_ || !shadowParamsSet_) return; if (instances.empty() || loadedModels.empty()) return; @@ -1681,7 +1682,11 @@ void WMORenderer::renderShadow(VkCommandBuffer cmd, const glm::mat4& lightSpaceM struct ShadowPush { glm::mat4 lightSpaceMatrix; glm::mat4 model; }; + const float shadowRadiusSq = shadowRadius * shadowRadius; for (const auto& instance : instances) { + // Distance cull against shadow frustum + glm::vec3 diff = instance.position - shadowCenter; + if (glm::dot(diff, diff) > shadowRadiusSq) continue; auto modelIt = loadedModels.find(instance.modelId); if (modelIt == loadedModels.end()) continue; const ModelData& model = modelIt->second;