From 230dd4722d1afa0d0031b30ed2520d61a3393e83 Mon Sep 17 00:00:00 2001 From: kearwood Date: Thu, 22 Nov 2012 09:02:25 +0000 Subject: [PATCH] Implemented automatic tuning of shadow space frustum used for illuminating volumetric effects and particle systems. --HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40163 --- KREngine/KREngine/Classes/KRAABB.cpp | 14 +++ KREngine/KREngine/Classes/KRAABB.h | 3 + KREngine/KREngine/Classes/KRCamera.cpp | 17 ++-- .../KREngine/Classes/KRDirectionalLight.cpp | 29 +++++- KREngine/KREngine/Classes/KREngine.mm | 4 +- KREngine/KREngine/Classes/KRLight.cpp | 88 +++++++++++-------- KREngine/KREngine/Classes/KRScene.cpp | 11 ++- KREngine/KREngine/Classes/KRScene.h | 2 + KREngine/KREngine/Classes/KRShader.cpp | 4 +- KREngine/KREngine/Classes/KRShaderManager.cpp | 5 +- 10 files changed, 121 insertions(+), 56 deletions(-) diff --git a/KREngine/KREngine/Classes/KRAABB.cpp b/KREngine/KREngine/Classes/KRAABB.cpp index a69e59a..e194c1f 100644 --- a/KREngine/KREngine/Classes/KRAABB.cpp +++ b/KREngine/KREngine/Classes/KRAABB.cpp @@ -73,6 +73,20 @@ KRVector3 KRAABB::size() const return max - min; } +void KRAABB::scale(const KRVector3 &s) +{ + KRVector3 prev_center = center(); + KRVector3 prev_size = size(); + KRVector3 new_scale = KRVector3(prev_size.x * s.x, prev_size.y * s.y, prev_size.z * s.z) * 0.5f; + min = prev_center - new_scale; + max = prev_center + new_scale; +} + +void KRAABB::scale(float s) +{ + scale(KRVector3(s)); +} + bool KRAABB::operator >(const KRAABB& b) const { // Comparison operators are implemented to allow insertion into sorted containers such as std::set diff --git a/KREngine/KREngine/Classes/KRAABB.h b/KREngine/KREngine/Classes/KRAABB.h index b9cbefb..6fa461f 100644 --- a/KREngine/KREngine/Classes/KRAABB.h +++ b/KREngine/KREngine/Classes/KRAABB.h @@ -22,6 +22,9 @@ public: KRAABB(const KRVector3 &corner1, const KRVector3 &corner2, const KRMat4 &modelMatrix); ~KRAABB(); + void scale(const KRVector3 &s); + void scale(float s); + KRVector3 center() const; KRVector3 size() const; bool intersects(const KRAABB& b) const; diff --git a/KREngine/KREngine/Classes/KRCamera.cpp b/KREngine/KREngine/Classes/KRCamera.cpp index ac77228..ee9d841 100644 --- a/KREngine/KREngine/Classes/KRCamera.cpp +++ b/KREngine/KREngine/Classes/KRCamera.cpp @@ -119,13 +119,13 @@ KRCamera::KRCamera(KRContext &context) : KRContextObject(context) { volumetric_environment_downsample = 2; volumetric_environment_max_distance = 1000.0f; volumetric_environment_quality = (50 - 5.0) / 495.0f; - volumetric_environment_intensity = 1.0f; + volumetric_environment_intensity = 0.9f; fog_near = 500.0f; - fog_far = 1000.0f; - fog_density = 0.01f; - fog_color = KRVector3(0.5, 0.5, 0.5); + fog_far = 5000.0f; + fog_density = 0.0005f; + fog_color = KRVector3(0.45, 0.45, 0.5); fog_type = 0; } @@ -244,7 +244,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { // Render the geometry - scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, false); + scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_DEFERRED_LIGHTS, false); // ----====---- Opaque Geometry, Deferred rendering Pass 3 ----====---- // Set render target @@ -288,13 +288,12 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { } else { // ----====---- Generate Shadowmaps for Lights ----====---- scene.render(this, m_viewport.getVisibleBounds(), m_viewport, KRNode::RENDER_PASS_GENERATE_SHADOWMAPS, true); - GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y)); - // ----====---- Opaque Geometry, Forward Rendering ----====---- // Set render target GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer)); GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0)); + GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y)); // Disable alpha blending GLDEBUG(glDisable(GL_BLEND)); @@ -421,7 +420,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glActiveTexture(GL_TEXTURE0)); GLDEBUG(glBindTexture(GL_TEXTURE_2D, compositeDepthTexture)); - glViewport(0, 0, volumetricLightingViewport.getSize().x, volumetricLightingViewport.getSize().y); + GLDEBUG(glViewport(0, 0, volumetricLightingViewport.getSize().x, volumetricLightingViewport.getSize().y)); } else { // Enable z-buffer test GLDEBUG(glEnable(GL_DEPTH_TEST)); @@ -436,7 +435,7 @@ void KRCamera::renderFrame(KRScene &scene, float deltaTime) { GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, compositeFramebuffer)); GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, compositeDepthTexture, 0)); - glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y); + GLDEBUG(glViewport(0, 0, m_viewport.getSize().x, m_viewport.getSize().y)); } } diff --git a/KREngine/KREngine/Classes/KRDirectionalLight.cpp b/KREngine/KREngine/Classes/KRDirectionalLight.cpp index 1ae676f..8472608 100644 --- a/KREngine/KREngine/Classes/KRDirectionalLight.cpp +++ b/KREngine/KREngine/Classes/KRDirectionalLight.cpp @@ -50,27 +50,48 @@ KRVector3 KRDirectionalLight::getLocalLightDirection() { int KRDirectionalLight::configureShadowBufferViewports(const KRViewport &viewport) { + + const float KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE = 1.25f; // Scale to apply to view frustrum bounds so that we don't need to refresh shadows on every frame int cShadows = 1; for(int iShadow=0; iShadow < cShadows; iShadow++) { GLfloat shadowMinDepths[3][3] = {{0.0, 0.0, 0.0},{0.0, 0.0, 0.0},{0.0, 0.05, 0.3}}; GLfloat shadowMaxDepths[3][3] = {{0.0, 0.0, 1.0},{0.1, 0.0, 0.0},{0.1, 0.3, 1.0}}; + float min_depth = 0.0f; + float max_depth = 1.0f; + + KRAABB worldSpacefrustrumSliceBounds = KRAABB(KRVector3(-1.0f, -max_depth, -1.0f), KRVector3(1.0f, -min_depth, 1.0f), KRMat4::Invert(viewport.getViewProjectionMatrix())); + worldSpacefrustrumSliceBounds.scale(KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE); + KRVector3 shadowLook = -KRVector3::Normalize(getWorldLightDirection()); KRVector3 shadowUp(0.0, 1.0, 0.0); if(KRVector3::Dot(shadowUp, shadowLook) > 0.99f) shadowUp = KRVector3(0.0, 0.0, 1.0); // Ensure shadow look direction is not parallel with the shadowUp direction - KRMat4 matShadowView = KRMat4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp); - +// KRMat4 matShadowView = KRMat4::LookAt(viewport.getCameraPosition() - shadowLook, viewport.getCameraPosition(), shadowUp); +// KRMat4 matShadowProjection = KRMat4(); +// matShadowProjection.scale(0.001, 0.001, 0.001); + KRMat4 matShadowView = KRMat4::LookAt(worldSpacefrustrumSliceBounds.center() - shadowLook, worldSpacefrustrumSliceBounds.center(), shadowUp); KRMat4 matShadowProjection = KRMat4(); - matShadowProjection.scale(0.001, 0.001, 0.001); + KRAABB shadowSpaceFrustrumSliceBounds = KRAABB(worldSpacefrustrumSliceBounds.min, worldSpacefrustrumSliceBounds.max, KRMat4::Invert(matShadowProjection)); + KRAABB shadowSpaceSceneBounds = KRAABB(getScene().getRootOctreeBounds().min, getScene().getRootOctreeBounds().max, KRMat4::Invert(matShadowProjection)); + if(shadowSpaceSceneBounds.min.z < shadowSpaceFrustrumSliceBounds.min.z) shadowSpaceFrustrumSliceBounds.min.z = shadowSpaceSceneBounds.min.z; // Include any potential shadow casters that are outside the view frustrum + matShadowProjection.scale(1.0f / shadowSpaceFrustrumSliceBounds.size().x, 1.0f / shadowSpaceFrustrumSliceBounds.size().y, 1.0f / shadowSpaceFrustrumSliceBounds.size().z); KRMat4 matBias; matBias.bias(); matShadowProjection *= matBias; - m_shadowViewports[iShadow] = KRViewport(KRVector2(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection); + KRViewport newShadowViewport = KRViewport(KRVector2(KRENGINE_SHADOW_MAP_WIDTH, KRENGINE_SHADOW_MAP_HEIGHT), matShadowView, matShadowProjection); + KRAABB prevShadowBounds = KRAABB(-KRVector3::One(), KRVector3::One(), KRMat4::Invert(m_shadowViewports[iShadow].getViewProjectionMatrix())); + KRAABB minimumShadowBounds = KRAABB(-KRVector3::One(), KRVector3::One(), KRMat4::Invert(newShadowViewport.getViewProjectionMatrix())); + minimumShadowBounds.scale(1.0f / KRENGINE_SHADOW_BOUNDS_EXTRA_SCALE); + if(!prevShadowBounds.contains(minimumShadowBounds) || !shadowValid[iShadow]) { + m_shadowViewports[iShadow] = newShadowViewport; + shadowValid[iShadow] = false; + fprintf(stderr, "Kraken - Generate shadow maps...\n"); + } } return 1; diff --git a/KREngine/KREngine/Classes/KREngine.mm b/KREngine/KREngine/Classes/KREngine.mm index 131e1bb..80c230b 100644 --- a/KREngine/KREngine/Classes/KREngine.mm +++ b/KREngine/KREngine/Classes/KREngine.mm @@ -578,8 +578,8 @@ float const PI = 3.141592653589793f; 1.0f, 10.0f, 2.0f, 1.0f, 1.0f, 1.0f, 5.0f, 1.0f, 0.5f, 1.0f, 2.0f, 2.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1000.0f, 10000.0f, - 1.0f, 5.0f, 10000.0f, 1.0f, 10.0f, - 3.0f, 10000.0f, 10000.0f, 0.10f, 1.0f, 1.0f, 1.0f + 1.0f, 5.0f, 10000.0f, 1.0f, 5.0f, + 3.0f, 10000.0f, 10000.0f, 0.01f, 1.0f, 1.0f, 1.0f }; return maxValues[i]; diff --git a/KREngine/KREngine/Classes/KRLight.cpp b/KREngine/KREngine/Classes/KRLight.cpp index bcbaab3..dd1a500 100644 --- a/KREngine/KREngine/Classes/KRLight.cpp +++ b/KREngine/KREngine/Classes/KRLight.cpp @@ -256,7 +256,9 @@ void KRLight::deleteBuffers() void KRLight::invalidateShadowBuffers() { - memset(shadowValid, sizeof(bool) * KRENGINE_MAX_SHADOW_BUFFERS, 0); + for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) { + shadowValid[iShadow] = false; + } } int KRLight::configureShadowBufferViewports(const KRViewport &viewport) @@ -265,43 +267,47 @@ int KRLight::configureShadowBufferViewports(const KRViewport &viewport) } void KRLight::renderShadowBuffers(KRCamera *pCamera) -{ +{ for(int iShadow=0; iShadow < m_cShadowBuffers; iShadow++) { - glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y); - - GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow])); - - GLDEBUG(glClearDepthf(0.0f)); - GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT)); - - glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y); - - GLDEBUG(glClearDepthf(1.0f)); - GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT)); - - glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2); - - GLDEBUG(glDisable(GL_DITHER)); - - GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts - GLDEBUG(glEnable(GL_CULL_FACE)); - - // Enable z-buffer test - GLDEBUG(glEnable(GL_DEPTH_TEST)); - GLDEBUG(glDepthFunc(GL_LESS)); - GLDEBUG(glDepthRangef(0.0, 1.0)); - - // Disable alpha blending as we are using alpha channel for packed depth info - GLDEBUG(glDisable(GL_BLEND)); - - // Use shader program - KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector(), false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); - - getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector(), KRNode::RENDER_PASS_SHADOWMAP); - - - getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true); + if(!shadowValid[iShadow]) { + shadowValid[iShadow] = true; + + GLDEBUG(glBindFramebuffer(GL_FRAMEBUFFER, shadowFramebuffer[iShadow])); + GLDEBUG(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowDepthTexture[iShadow], 0)); + + GLDEBUG(glViewport(0, 0, m_shadowViewports[iShadow].getSize().x, m_shadowViewports[iShadow].getSize().y)); + + + GLDEBUG(glClearDepthf(0.0f)); + GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT)); + + GLDEBUG(glViewport(1, 1, m_shadowViewports[iShadow].getSize().x - 2, m_shadowViewports[iShadow].getSize().y - 2)); + GLDEBUG(glClearDepthf(1.0f)); + + GLDEBUG(glClear(GL_DEPTH_BUFFER_BIT)); + + GLDEBUG(glDisable(GL_DITHER)); + + GLDEBUG(glCullFace(GL_BACK)); // Enable frontface culling, which eliminates some self-cast shadow artifacts + GLDEBUG(glEnable(GL_CULL_FACE)); + + // Enable z-buffer test + GLDEBUG(glEnable(GL_DEPTH_TEST)); + GLDEBUG(glDepthFunc(GL_LESS)); + GLDEBUG(glDepthRangef(0.0, 1.0)); + + // Disable alpha blending as we are using alpha channel for packed depth info + GLDEBUG(glDisable(GL_BLEND)); + + // Use shader program + KRShader *shadowShader = m_pContext->getShaderManager()->getShader("ShadowShader", pCamera, std::vector(), false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, KRNode::RENDER_PASS_FORWARD_TRANSPARENT); + + getContext().getShaderManager()->selectShader(*pCamera, shadowShader, m_shadowViewports[iShadow], KRMat4(), std::vector(), KRNode::RENDER_PASS_SHADOWMAP); + + + getScene().render(pCamera, m_shadowViewports[iShadow].getVisibleBounds(), m_shadowViewports[iShadow], KRNode::RENDER_PASS_SHADOWMAP, true); + } } } @@ -309,7 +315,15 @@ void KRLight::renderShadowBuffers(KRCamera *pCamera) int KRLight::getShadowBufferCount() { - return m_cShadowBuffers; + int cBuffers=0; + for(int iBuffer=0; iBuffer < m_cShadowBuffers; iBuffer++) { + if(shadowValid[iBuffer]) { + cBuffers++; + } else { + break; + } + } + return cBuffers; } GLuint *KRLight::getShadowTextures() diff --git a/KREngine/KREngine/Classes/KRScene.cpp b/KREngine/KREngine/Classes/KRScene.cpp index 1c0bd64..4689b83 100644 --- a/KREngine/KREngine/Classes/KRScene.cpp +++ b/KREngine/KREngine/Classes/KRScene.cpp @@ -424,6 +424,15 @@ void KRScene::addDefaultLights() { KRDirectionalLight *light1 = new KRDirectionalLight(*this, "default_light1"); - light1->setLocalRotation((KRQuaternion(KRVector3(0.0, M_PI * 0.25, 0.0)) * KRQuaternion(KRVector3(0.0, 0.0, -M_PI * 0.25))).euler()); + light1->setLocalRotation((KRQuaternion(KRVector3(0.0, M_PI * 0.10, 0.0)) * KRQuaternion(KRVector3(0.0, 0.0, -M_PI * 0.15))).euler()); m_pRootNode->addChild(light1); +} + +KRAABB KRScene::getRootOctreeBounds() +{ + if(m_nodeTree.getRootNode()) { + return m_nodeTree.getRootNode()->getBounds(); + } else { + return KRAABB(-KRVector3::One(), KRVector3::One()); + } } \ No newline at end of file diff --git a/KREngine/KREngine/Classes/KRScene.h b/KREngine/KREngine/Classes/KRScene.h index 58b7563..13878a1 100644 --- a/KREngine/KREngine/Classes/KRScene.h +++ b/KREngine/KREngine/Classes/KRScene.h @@ -76,6 +76,8 @@ public: void physicsUpdate(float deltaTime); void addDefaultLights(); + KRAABB getRootOctreeBounds(); + private: KRLight *findFirstLight(KRNode &node); diff --git a/KREngine/KREngine/Classes/KRShader.cpp b/KREngine/KREngine/Classes/KRShader.cpp index f39dbfd..40462be 100644 --- a/KREngine/KREngine/Classes/KRShader.cpp +++ b/KREngine/KREngine/Classes/KRShader.cpp @@ -258,7 +258,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 & GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); } - if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE2] != -1 && cShadowBuffers > 1) { + if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE2] != -1 && cShadowBuffers > 1 && camera.m_cShadowBuffers > 1) { m_pContext->getTextureManager()->selectTexture(4, NULL); GLDEBUG(glActiveTexture(GL_TEXTURE4)); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[1])); @@ -268,7 +268,7 @@ bool KRShader::bind(KRCamera &camera, const KRViewport &viewport, const KRMat4 & GLDEBUG(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); } - if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE3] != -1 && cShadowBuffers > 2) { + if(m_uniforms[KRENGINE_UNIFORM_SHADOWTEXTURE3] != -1 && cShadowBuffers > 2 && camera.m_cShadowBuffers > 2) { m_pContext->getTextureManager()->selectTexture(5, NULL); GLDEBUG(glActiveTexture(GL_TEXTURE5)); GLDEBUG(glBindTexture(GL_TEXTURE_2D, directional_light->getShadowTextures()[2])); diff --git a/KREngine/KREngine/Classes/KRShaderManager.cpp b/KREngine/KREngine/Classes/KRShaderManager.cpp index 04c991a..8481813 100644 --- a/KREngine/KREngine/Classes/KRShaderManager.cpp +++ b/KREngine/KREngine/Classes/KRShaderManager.cpp @@ -53,7 +53,7 @@ KRShaderManager::~KRShaderManager() { KRShader *KRShaderManager::getShader(const std::string &shader_name, KRCamera *pCamera, const std::vector &lights, bool bDiffuseMap, bool bNormalMap, bool bSpecMap, bool bReflectionMap, bool bReflectionCubeMap, bool bLightMap, bool bDiffuseMapScale,bool bSpecMapScale, bool bNormalMapScale, bool bReflectionMapScale, bool bDiffuseMapOffset, bool bSpecMapOffset, bool bNormalMapOffset, bool bReflectionMapOffset, bool bAlphaTest, bool bAlphaBlend, KRNode::RenderPass renderPass) { int iShadowQuality = 0; // FINDME - HACK - Placeholder code, need to iterate through lights and dynamically build shader - + int light_directional_count = 0; int light_point_count = 0; @@ -73,6 +73,9 @@ KRShader *KRShaderManager::getShader(const std::string &shader_name, KRCamera *p } } + if(iShadowQuality > pCamera->m_cShadowBuffers) { + iShadowQuality = pCamera->m_cShadowBuffers; + } char szKey[256]; sprintf(szKey, "%i_%i_%i_%i_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d_%i_%s_%i_%d_%d_%f_%f_%f_%f_%f_%f_%f", light_directional_count, light_point_count, light_spot_count, pCamera->fog_type, pCamera->bEnablePerPixel,bAlphaTest, bAlphaBlend, bDiffuseMap, bNormalMap, bSpecMap, bReflectionMap, bReflectionCubeMap, pCamera->bDebugPSSM, iShadowQuality, pCamera->bEnableAmbient, pCamera->bEnableDiffuse, pCamera->bEnableSpecular, bLightMap, bDiffuseMapScale, bSpecMapScale, bReflectionMapScale, bNormalMapScale, bDiffuseMapOffset, bSpecMapOffset, bReflectionMapOffset, bNormalMapOffset,pCamera->volumetric_environment_enable && pCamera->volumetric_environment_downsample != 0, renderPass, shader_name.c_str(),pCamera->dof_quality,pCamera->bEnableFlash,pCamera->bEnableVignette,pCamera->dof_depth,pCamera->dof_falloff,pCamera->flash_depth,pCamera->flash_falloff,pCamera->flash_intensity,pCamera->vignette_radius,pCamera->vignette_falloff);