mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Add shadow frustum culling to terrain and M2 depth passes
Both passes were rendering the entire loaded scene (17×17 tile radius) into a shadow map that only covers 360×360 world units — submitting 10-50× more geometry than the shadow frustum can actually use. - TerrainRenderer::renderShadow: skip chunks whose bounding sphere doesn't overlap the shadow frustum AABB in XY. Reduces terrain draw calls from O(all loaded chunks) to O(chunks within ~180 units). - M2Renderer::renderShadow: skip instances whose world AABB doesn't overlap the shadow frustum in XY. Reduces M2 draw calls similarly. - Both functions now take shadowCenter + halfExtent parameters.
This commit is contained in:
parent
c4d0a21713
commit
514b914068
5 changed files with 23 additions and 8 deletions
|
|
@ -236,7 +236,7 @@ public:
|
|||
/**
|
||||
* Render depth-only pass for shadow casting
|
||||
*/
|
||||
void renderShadow(GLuint shadowShaderProgram);
|
||||
void renderShadow(GLuint shadowShaderProgram, const glm::vec3& shadowCenter, float halfExtent);
|
||||
|
||||
/**
|
||||
* Render smoke particles (call after render())
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ public:
|
|||
/**
|
||||
* Render terrain geometry into shadow depth map
|
||||
*/
|
||||
void renderShadow(GLuint shaderProgram);
|
||||
void renderShadow(GLuint shaderProgram, const glm::vec3& shadowCenter, float halfExtent);
|
||||
|
||||
/**
|
||||
* Set shadow map for receiving shadows
|
||||
|
|
|
|||
|
|
@ -2151,7 +2151,7 @@ void M2Renderer::render(const Camera& camera, const glm::mat4& view, const glm::
|
|||
}
|
||||
}
|
||||
|
||||
void M2Renderer::renderShadow(GLuint shadowShaderProgram) {
|
||||
void M2Renderer::renderShadow(GLuint shadowShaderProgram, const glm::vec3& shadowCenter, float halfExtent) {
|
||||
if (instances.empty() || shadowShaderProgram == 0) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -2172,6 +2172,12 @@ void M2Renderer::renderShadow(GLuint shadowShaderProgram) {
|
|||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
for (const auto& instance : instances) {
|
||||
// Cull instances whose AABB doesn't overlap the shadow frustum (XY plane)
|
||||
glm::vec3 instCenter = (instance.worldBoundsMin + instance.worldBoundsMax) * 0.5f;
|
||||
glm::vec3 instHalf = (instance.worldBoundsMax - instance.worldBoundsMin) * 0.5f;
|
||||
if (std::abs(instCenter.x - shadowCenter.x) > halfExtent + instHalf.x) continue;
|
||||
if (std::abs(instCenter.y - shadowCenter.y) > halfExtent + instHalf.y) continue;
|
||||
|
||||
auto it = models.find(instance.modelId);
|
||||
if (it == models.end()) continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -3444,9 +3444,10 @@ void Renderer::renderShadowPass() {
|
|||
if (useBonesLoc >= 0) glUniform1i(useBonesLoc, 0);
|
||||
if (texLoc >= 0) glUniform1i(texLoc, 0);
|
||||
|
||||
// Render terrain into shadow map
|
||||
// Render terrain into shadow map (only chunks within shadow frustum)
|
||||
if (terrainRenderer) {
|
||||
terrainRenderer->renderShadow(shadowShaderProgram);
|
||||
glm::vec3 shadowCtr = shadowCenterInitialized ? shadowCenter : characterPosition;
|
||||
terrainRenderer->renderShadow(shadowShaderProgram, shadowCtr, kShadowHalfExtent);
|
||||
}
|
||||
|
||||
// Render WMO into shadow map
|
||||
|
|
@ -3476,9 +3477,10 @@ void Renderer::renderShadowPass() {
|
|||
shadowShaderWrapper.releaseProgram(); // Don't let wrapper delete our program
|
||||
}
|
||||
|
||||
// Render M2 doodads into shadow map
|
||||
// Render M2 doodads into shadow map (only instances within shadow frustum)
|
||||
if (m2Renderer) {
|
||||
m2Renderer->renderShadow(shadowShaderProgram);
|
||||
glm::vec3 shadowCtr = shadowCenterInitialized ? shadowCenter : characterPosition;
|
||||
m2Renderer->renderShadow(shadowShaderProgram, shadowCtr, kShadowHalfExtent);
|
||||
}
|
||||
|
||||
// Render characters into shadow map
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ GLuint TerrainRenderer::createAlphaTexture(const std::vector<uint8_t>& alphaData
|
|||
return textureID;
|
||||
}
|
||||
|
||||
void TerrainRenderer::renderShadow(GLuint shaderProgram) {
|
||||
void TerrainRenderer::renderShadow(GLuint shaderProgram, const glm::vec3& shadowCenter, float halfExtent) {
|
||||
if (chunks.empty()) return;
|
||||
|
||||
GLint modelLoc = glGetUniformLocation(shaderProgram, "uModel");
|
||||
|
|
@ -378,6 +378,13 @@ void TerrainRenderer::renderShadow(GLuint shaderProgram) {
|
|||
|
||||
for (const auto& chunk : chunks) {
|
||||
if (!chunk.isValid()) continue;
|
||||
|
||||
// Cull chunks whose bounding sphere doesn't overlap the shadow frustum (XY plane)
|
||||
float maxDist = halfExtent + chunk.boundingSphereRadius;
|
||||
float dx = chunk.boundingSphereCenter.x - shadowCenter.x;
|
||||
float dy = chunk.boundingSphereCenter.y - shadowCenter.y;
|
||||
if (dx * dx + dy * dy > maxDist * maxDist) continue;
|
||||
|
||||
glBindVertexArray(chunk.vao);
|
||||
glDrawElements(GL_TRIANGLES, chunk.indexCount, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue