From ac0e816f8cc4f68ca79f1dd8c5c816c74d2deae1 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Mon, 13 Nov 2017 18:42:34 +0100 Subject: [PATCH] Cascade selection working on shadow but not in Luci debug mode --- .../gpu-gl/src/gpu/gl/GLBackendShader.cpp | 5 +- .../render-utils/src/DebugDeferredBuffer.cpp | 43 ++++++++-- .../render-utils/src/DebugDeferredBuffer.h | 9 +- libraries/render-utils/src/LightStage.cpp | 2 + libraries/render-utils/src/LightStage.h | 4 +- .../render-utils/src/RenderShadowTask.cpp | 5 +- libraries/render-utils/src/Shadow.slh | 69 ++++----------- libraries/render-utils/src/ShadowCore.slh | 86 +++++++++++++++++++ .../src/debug_deferred_buffer.slf | 3 +- .../src/directional_ambient_light_shadow.slf | 5 +- .../src/directional_skybox_light_shadow.slf | 5 +- .../utilities/render/deferredLighting.qml | 1 + 12 files changed, 162 insertions(+), 75 deletions(-) create mode 100644 libraries/render-utils/src/ShadowCore.slh diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp index 0c1b6880cb..9adfd550ef 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackendShader.cpp @@ -318,7 +318,10 @@ int GLBackend::makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slot if (requestedBinding != slotBindings.end()) { if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; - glProgramUniform1i(glprogram, location, binding); + for (auto i = 0; i < size; i++) { + // If we are working with an array of textures, reserve for each elemet + glProgramUniform1i(glprogram, location+i, binding+i); + } } } diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index 1a95329724..55c945549c 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -126,12 +126,14 @@ static const std::string DEFAULT_DEPTH_SHADER { " return vec4(vec3(texture(depthMap, uv).x), 1.0);" " }" }; + static const std::string DEFAULT_LIGHTING_SHADER { "vec4 getFragmentColor() {" " return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);" " }" }; -static const std::string DEFAULT_SHADOW_SHADER { + +static const std::string DEFAULT_SHADOW_SHADER{ "uniform sampler2DShadow shadowMap;" "vec4 getFragmentColor() {" " for (int i = 255; i >= 0; --i) {" @@ -144,6 +146,25 @@ static const std::string DEFAULT_SHADOW_SHADER { " }" }; +static const std::string DEFAULT_SHADOW_CASCADE_SHADER{ + "vec3 cascadeColors[4] = vec3[4]( vec3(1,0,0), vec3(0,1,0), vec3(0,0,1), vec3(0,0,0) );" + "vec4 getFragmentColor() {" + " DeferredFrameTransform deferredTransform = getDeferredFrameTransform();" + " DeferredFragment frag = unpackDeferredFragment(deferredTransform, uv);" + " vec4 viewPosition = vec4(frag.position.xyz, 1.0);" + " vec4 worldPosition = getViewInverse() * viewPosition;" + " vec4 cascadeShadowCoords[4] = vec4[4](" + " evalShadowTexcoord(0, worldPosition)," + " evalShadowTexcoord(1, worldPosition)," + " evalShadowTexcoord(2, worldPosition)," + " evalShadowTexcoord(3, worldPosition)" + " );" + " ivec2 cascadeIndices;" + " float cascadeMix = evalCascadeIndicesAndMix(viewPosition, cascadeShadowCoords, cascadeIndices);" + " return vec4(mix(cascadeColors[cascadeIndices.x], cascadeColors[cascadeIndices.y], cascadeMix), 1.0);" + " }" +}; + static const std::string DEFAULT_LINEAR_DEPTH_SHADER { "vec4 getFragmentColor() {" " return vec4(vec3(1.0 - texture(linearDepthMap, uv).x * 0.01), 1.0);" @@ -284,11 +305,13 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return DEFAULT_SCATTERING_SHADER; case LightingMode: return DEFAULT_LIGHTING_SHADER; - case Shadow0Mode: - case Shadow1Mode: - case Shadow2Mode: - case Shadow3Mode: + case ShadowCascade0Mode: + case ShadowCascade1Mode: + case ShadowCascade2Mode: + case ShadowCascade3Mode: return DEFAULT_SHADOW_SHADER; + case ShadowCascadeIndicesMode: + return DEFAULT_SHADOW_CASCADE_SHADER; case LinearDepthMode: return DEFAULT_LINEAR_DEPTH_SHADER; case HalfLinearDepthMode: @@ -424,8 +447,8 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I // TODO REMOVE: Temporary until UI auto first = _customPipelines.begin()->first; - - batch.setPipeline(getPipeline(_mode, first)); + auto pipeline = getPipeline(_mode, first); + batch.setPipeline(pipeline); if (deferredFramebuffer) { batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture()); @@ -441,8 +464,12 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I auto lightAndShadow = lightStage->getCurrentKeyLightAndShadow(); const auto& globalShadow = lightAndShadow.second; if (globalShadow) { - const auto cascadeIndex = glm::clamp(_mode - Mode::Shadow0Mode, 0, (int)globalShadow->getCascadeCount() - 1); + const auto cascadeIndex = glm::clamp(_mode - Mode::ShadowCascade0Mode, 0, (int)globalShadow->getCascadeCount() - 1); + const auto shadowBufferLoc = pipeline->getProgram()->getUniformBuffers().findLocation("shadowTransformBuffer"); batch.setResourceTexture(Shadow, globalShadow->getCascade(cascadeIndex).map); + if (shadowBufferLoc >= 0) { + batch.setUniformBuffer(shadowBufferLoc, globalShadow->getBuffer()); + } } if (linearDepthTarget) { diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index 49e53c4617..104b161720 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -64,10 +64,11 @@ protected: LightmapMode, ScatteringMode, LightingMode, - Shadow0Mode, - Shadow1Mode, - Shadow2Mode, - Shadow3Mode, + ShadowCascade0Mode, + ShadowCascade1Mode, + ShadowCascade2Mode, + ShadowCascade3Mode, + ShadowCascadeIndicesMode, LinearDepthMode, HalfLinearDepthMode, HalfNormalMode, diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index bfc4805413..1820076545 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -126,6 +126,8 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie schemaCascade.reprojection = _biasMatrix * ortho * viewInverse.getMatrix(); schemaCascade.minDistance = viewMinShadowDistance; schemaCascade.maxDistance = viewMaxShadowDistance; + cascade.minDistance = viewMinShadowDistance; + cascade.maxDistance = viewMaxShadowDistance; } void LightStage::Shadow::setFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum) { diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 60c4a49678..07ef0c25b6 100644 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -56,6 +56,8 @@ public: gpu::FramebufferPointer framebuffer; gpu::TexturePointer map; + float minDistance; + float maxDistance; const std::shared_ptr& getFrustum() const { return _frustum; } @@ -95,8 +97,6 @@ public: }; UniformBufferView _schemaBuffer = nullptr; - - void setupCascades(); friend class Light; }; diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index d9af9659e5..0c4e5d4a61 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -253,8 +253,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O output.edit0() = args->_renderMode; const auto globalShadow = lightStage->getCurrentKeyShadow(); - const auto globalShadowCascadeCount = globalShadow->getCascadeCount(); - if (globalShadow && _cascadeIndexgetCascadeCount()) { output.edit1() = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); const auto nearClip = args->getViewFrustum().getNearClip(); @@ -263,7 +262,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O static const float SHADOW_MAX_DISTANCE = 25.0f; static const float SHADOW_OVERLAP_DISTANCE = 1.0f; - float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(2.0f, globalShadowCascadeCount - 1 - _cascadeIndex); + float maxCascadeDistance = SHADOW_MAX_DISTANCE / powf(2.0f, globalShadow->getCascadeCount() - 1 - _cascadeIndex); float minCascadeDistance = maxCascadeDistance / 2.0f - SHADOW_OVERLAP_DISTANCE; if (_cascadeIndex == 0) { diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 95d7b5193e..18a39782b6 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -11,43 +11,11 @@ <@if not SHADOW_SLH@> <@def SHADOW_SLH@> -<@include Shadows_shared.slh@> +<@include ShadowCore.slh@> // the shadow texture uniform sampler2DShadow shadowMaps[SHADOW_CASCADE_MAX_COUNT]; -uniform shadowTransformBuffer { - ShadowParameters shadow; -}; - -int getShadowCascadeCount() { - return shadow.cascadeCount; -} - -float getShadowCascadeMinDistance(int cascadeIndex) { - return shadow.cascades[cascadeIndex].minDistance; -} - -mat4 getShadowReprojection(int cascadeIndex) { - return shadow.cascades[cascadeIndex].reprojection; -} - -float getShadowScale() { - return shadow.invMapSize; -} - -float getShadowBias(int cascadeIndex) { - return shadow.cascades[cascadeIndex].bias; -} - -// Compute the texture coordinates from world coordinates -vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) { - float bias = -getShadowBias(cascadeIndex); - - vec4 shadowCoord = getShadowReprojection(cascadeIndex) * position; - return vec4(shadowCoord.xy, shadowCoord.z + bias, 1.0); -} - // Sample the shadowMap with PCF (built-in) float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) { return texture(shadowMaps[cascadeIndex], shadowTexcoord); @@ -109,8 +77,7 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve return shadowAttenuation; } -float evalShadowCascadeAttenuation(int cascadeIndex, vec4 position, ShadowSampleOffsets offsets) { - vec4 shadowTexcoord = evalShadowTexcoord(cascadeIndex, position); +float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord) { if (shadowTexcoord.x < 0.0 || shadowTexcoord.x > 1.0 || shadowTexcoord.y < 0.0 || shadowTexcoord.y > 1.0 || shadowTexcoord.z < 0.0 || shadowTexcoord.z > 1.0) { @@ -120,25 +87,23 @@ float evalShadowCascadeAttenuation(int cascadeIndex, vec4 position, ShadowSample return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord); } -float evalShadowAttenuation(vec4 position) { - ShadowSampleOffsets offsets = evalShadowFilterOffsets(position); - - // Cascade selection based on : - // https://msdn.microsoft.com/en-us/library/windows/desktop/ee416307(v=vs.85).aspx - vec4 currentPixelDepth = position.zzzz; - vec4 cascadeDepthLimits = vec4( - getShadowCascadeMinDistance(0), - getShadowCascadeMinDistance(1), - getShadowCascadeMinDistance(2), - getShadowCascadeMinDistance(3) +float evalShadowAttenuation(vec4 worldPosition, vec4 viewPosition) { + ShadowSampleOffsets offsets = evalShadowFilterOffsets(worldPosition); + vec4 cascadeShadowCoords[4] = vec4[4] ( + evalShadowTexcoord(0, worldPosition), + evalShadowTexcoord(1, worldPosition), + evalShadowTexcoord(2, worldPosition), + evalShadowTexcoord(3, worldPosition) ); - bvec4 comparison = greaterThan( currentPixelDepth, cascadeDepthLimits); - int cascadeCount = getShadowCascadeCount(); - bvec4 cascadeCountMask = greaterThan(ivec4(cascadeCount), ivec4(0,1,2,3)); - int cascadeIndex = int(dot(ivec4(cascadeCountMask), ivec4(comparison))); - cascadeIndex = min( cascadeIndex, cascadeCount-1 ); + ivec2 cascadeIndices; + float cascadeMix = evalCascadeIndicesAndMix(viewPosition, cascadeShadowCoords, cascadeIndices); - return evalShadowCascadeAttenuation(cascadeIndex, position, offsets); + vec2 cascadeAttenuations = vec2(1.0, 1.0); + cascadeAttenuations.x = evalShadowCascadeAttenuation(cascadeIndices.x, offsets, cascadeShadowCoords[cascadeIndices.x]); + if (cascadeMix > 0.0) { + cascadeAttenuations.y = evalShadowCascadeAttenuation(cascadeIndices.y, offsets, cascadeShadowCoords[cascadeIndices.y]); + } + return mix(cascadeAttenuations.x, cascadeAttenuations.y, cascadeMix); } <@endif@> diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh new file mode 100644 index 0000000000..3e2fc3a8b8 --- /dev/null +++ b/libraries/render-utils/src/ShadowCore.slh @@ -0,0 +1,86 @@ + +<@if not SHADOW_CORE_SLH@> +<@def SHADOW_CORE_SLH@> + +<@include Shadows_shared.slh@> + +uniform shadowTransformBuffer { + ShadowParameters shadow; +}; + +int getShadowCascadeCount() { + return shadow.cascadeCount; +} + +float getShadowCascadeMinDistance(int cascadeIndex) { + return shadow.cascades[cascadeIndex].minDistance; +} + +mat4 getShadowReprojection(int cascadeIndex) { + return shadow.cascades[cascadeIndex].reprojection; +} + +float getShadowScale() { + return shadow.invMapSize; +} + +float getShadowBias(int cascadeIndex) { + return shadow.cascades[cascadeIndex].bias; +} + +// Compute the texture coordinates from world coordinates +vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) { + float bias = -getShadowBias(cascadeIndex); + + vec4 shadowCoord = getShadowReprojection(cascadeIndex) * position; + return vec4(shadowCoord.xy, shadowCoord.z + bias, 1.0); +} + +int getFirstValidShadowTexcoord(vec4 cascadeShadowCoords[4]) { + int cascadeIndex; + for (cascadeIndex=0 ; cascadeIndex diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index e9750f0054..426de623a1 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -16,7 +16,6 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> - uniform sampler2D linearDepthMap; uniform sampler2D halfLinearDepthMap; uniform sampler2D halfNormalMap; @@ -24,6 +23,8 @@ uniform sampler2D occlusionMap; uniform sampler2D occlusionBlurredMap; uniform sampler2D scatteringMap; +<@include ShadowCore.slh@> + <$declareDeferredCurvature()$> float curvatureAO(float k) { diff --git a/libraries/render-utils/src/directional_ambient_light_shadow.slf b/libraries/render-utils/src/directional_ambient_light_shadow.slf index d3778c9228..5f71809249 100644 --- a/libraries/render-utils/src/directional_ambient_light_shadow.slf +++ b/libraries/render-utils/src/directional_ambient_light_shadow.slf @@ -26,8 +26,9 @@ void main(void) { DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - vec4 worldPos = getViewInverse() * vec4(frag.position.xyz, 1.0); - float shadowAttenuation = evalShadowAttenuation(worldPos); + vec4 viewPos = vec4(frag.position.xyz, 1.0); + vec4 worldPos = getViewInverse() * viewPos; + float shadowAttenuation = evalShadowAttenuation(worldPos, viewPos); if (frag.mode == FRAG_MODE_UNLIT) { discard; diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index 3ca0f71df5..5c549df95d 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -26,8 +26,9 @@ void main(void) { DeferredFrameTransform deferredTransform = getDeferredFrameTransform(); DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0); - vec4 worldPos = getViewInverse() * vec4(frag.position.xyz, 1.0); - float shadowAttenuation = evalShadowAttenuation(worldPos); + vec4 viewPos = vec4(frag.position.xyz, 1.0); + vec4 worldPos = getViewInverse() * viewPos; + float shadowAttenuation = evalShadowAttenuation(worldPos, viewPos); // Light mapped or not ? if (frag.mode == FRAG_MODE_UNLIT) { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index def8b1fcd1..1da7871172 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -188,6 +188,7 @@ Rectangle { ListElement { text: "Shadow Cascade 1"; color: "White" } ListElement { text: "Shadow Cascade 2"; color: "White" } ListElement { text: "Shadow Cascade 3"; color: "White" } + ListElement { text: "Shadow Cascade Indices"; color: "White" } ListElement { text: "Linear Depth"; color: "White" } ListElement { text: "Half Linear Depth"; color: "White" } ListElement { text: "Half Normal"; color: "White" }