diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index d334a53fa1..f8bb7b7b54 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -438,7 +438,7 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { - batch.setResourceTexture(Shadow, globalShadow->map); + batch.setResourceTexture(Shadow, globalShadow->getCascade(0).map); } if (linearDepthTarget) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index dcb16c08f8..a99eb5ffed 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -503,7 +503,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, // Bind the shadow buffer if (globalShadow) { - batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->map); + batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow->getCascade(0).map); } auto& program = deferredLightingEffect->_directionalSkyboxLight; diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index d5dfe92b1d..e53fe27836 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -28,20 +28,34 @@ LightStage::Shadow::Schema::Schema() { defaultTransform.bias = 0.005f; std::fill(cascades, cascades + SHADOW_CASCADE_MAX_COUNT, defaultTransform); invMapSize = 1.0f / MAP_SIZE; + cascadeCount = 1; } -LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared() } { +LightStage::Shadow::Cascade::Cascade() : _frustum{ std::make_shared() } { framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE)); map = framebuffer->getDepthStencilBuffer(); - Schema schema; - _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); } -void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, +const glm::mat4& LightStage::Shadow::Cascade::getView() const { + return _frustum->getView(); +} + +const glm::mat4& LightStage::Shadow::Cascade::getProjection() const { + return _frustum->getProjection(); +} + +LightStage::Shadow::Shadow(model::LightPointer light, unsigned int cascadeCount) : _light{ light } { + Schema schema; + _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); + _cascades.resize(cascadeCount); +} + +void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth, float farDepth) { assert(viewMinShadowDistance < viewMaxShadowDistance); assert(nearDepth < farDepth); + assert(cascadeIndex < _cascades.size()); // Orient the keylight frustum const auto& direction = glm::normalize(_light->getDirection()); @@ -55,12 +69,15 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, auto up = glm::normalize(glm::cross(side, direction)); orientation = glm::quat_cast(glm::mat3(side, up, -direction)); } - _frustum->setOrientation(orientation); + + auto& cascade = _cascades[cascadeIndex]; + + cascade._frustum->setOrientation(orientation); // Position the keylight frustum - _frustum->setPosition(viewFrustum.getPosition() - (nearDepth + farDepth)*direction); + cascade._frustum->setPosition(viewFrustum.getPosition() - (nearDepth + farDepth)*direction); - const Transform view{ _frustum->getView()}; + const Transform view{ cascade._frustum->getView()}; const Transform viewInverse{ view.getInverseMatrix() }; auto nearCorners = viewFrustum.getCorners(viewMinShadowDistance); @@ -92,30 +109,24 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, auto near = glm::max(max.z, -nearDepth); auto far = -min.z; glm::mat4 ortho = glm::ortho(min.x, max.x, min.y, max.y, near, far); - _frustum->setProjection(ortho); + cascade._frustum->setProjection(ortho); // Calculate the frustum's internal state - _frustum->calculate(); + cascade._frustum->calculate(); // Update the buffer - _schemaBuffer.edit().cascades[0].reprojection = _biasMatrix * ortho * viewInverse.getMatrix(); + _schemaBuffer.edit().cascades[cascadeIndex].reprojection = _biasMatrix * ortho * viewInverse.getMatrix(); } -void LightStage::Shadow::setFrustum(const ViewFrustum& shadowFrustum) { +void LightStage::Shadow::setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum) { + assert(cascadeIndex < _cascades.size()); const Transform view{ shadowFrustum.getView() }; const Transform viewInverse{ view.getInverseMatrix() }; + auto& cascade = _cascades[cascadeIndex]; - *_frustum = shadowFrustum; + *cascade._frustum = shadowFrustum; // Update the buffer - _schemaBuffer.edit().cascades[0].reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); -} - -const glm::mat4& LightStage::Shadow::getView() const { - return _frustum->getView(); -} - -const glm::mat4& LightStage::Shadow::getProjection() const { - return _frustum->getProjection(); + _schemaBuffer.edit().cascades[cascadeIndex].reprojection = _biasMatrix * shadowFrustum.getProjection() * viewInverse.getMatrix(); } LightStage::Index LightStage::findLight(const LightPointer& light) const { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 3324cfbe99..2f5699c28d 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -46,27 +46,43 @@ public: using UniformBufferView = gpu::BufferView; static const int MAP_SIZE = 1024; - Shadow(model::LightPointer light); + class Cascade { + friend Shadow; + public: - void setKeylightFrustum(const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f); + Cascade(); - void setFrustum(const ViewFrustum& shadowFrustum); - const std::shared_ptr getFrustum() const { return _frustum; } + gpu::FramebufferPointer framebuffer; + gpu::TexturePointer map; - const glm::mat4& getView() const; - const glm::mat4& getProjection() const; + const std::shared_ptr& getFrustum() const { return _frustum; } + + const glm::mat4& getView() const; + const glm::mat4& getProjection() const; + + private: + + std::shared_ptr _frustum; + }; + + Shadow(model::LightPointer light, unsigned int cascadeCount = 1); + + void setKeylightFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, float viewMinShadowDistance, float viewMaxShadowDistance, float nearDepth = 1.0f, float farDepth = 1000.0f); + void setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum); const UniformBufferView& getBuffer() const { return _schemaBuffer; } - gpu::FramebufferPointer framebuffer; - gpu::TexturePointer map; + unsigned int getCascadeCount() const { return (unsigned int)_cascades.size(); } + const Cascade& getCascade(unsigned int index) const { return _cascades[index]; } protected: + using Cascades = std::vector; + static const glm::mat4 _biasMatrix; model::LightPointer _light; - std::shared_ptr _frustum; + Cascades _cascades; #include "Shadows_shared.slh" diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 75af8506a2..0a80ca4ade 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -545,7 +545,7 @@ void DrawFrustums::run(const render::RenderContextPointer& renderContext) { const auto globalShadow = lightStage->getCurrentKeyShadow(); if (globalShadow) { - updateFrustum(*globalShadow->getFrustum(), _shadowFrustumMeshVertices); + updateFrustum(*globalShadow->getCascade(0).getFrustum(), _shadowFrustumMeshVertices); } } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 7a6e3dc74f..ce6e78093d 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -139,7 +139,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con auto shadow = lightStage->getCurrentKeyShadow(); if (!shadow) return; - const auto& fbo = shadow->framebuffer; + const auto& fbo = shadow->getCascade(0).framebuffer; RenderArgs* args = renderContext->args; ShapeKey::Builder defaultKeyBuilder; @@ -149,7 +149,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext, con // the minimal Z range. adjustNearFar(inShapeBounds, adjustedShadowFrustum); // Reapply the frustum as it has been adjusted - shadow->setFrustum(adjustedShadowFrustum); + shadow->setFrustum(0, adjustedShadowFrustum); args->popViewFrustum(); args->pushViewFrustum(adjustedShadowFrustum); @@ -252,10 +252,10 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O auto nearClip = args->getViewFrustum().getNearClip(); float nearDepth = -args->_boomOffset.z; const float SHADOW_MAX_DISTANCE = 20.0f; - globalShadow->setKeylightFrustum(args->getViewFrustum(), nearDepth, nearClip + SHADOW_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); + globalShadow->setKeylightFrustum(0, args->getViewFrustum(), nearDepth, nearClip + SHADOW_MAX_DISTANCE, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); // Set the keylight render args - args->pushViewFrustum(*(globalShadow->getFrustum())); + args->pushViewFrustum(*(globalShadow->getCascade(0).getFrustum())); args->_renderMode = RenderArgs::SHADOW_RENDER_MODE; } }