diff --git a/libraries/graphics/src/graphics/Light.h b/libraries/graphics/src/graphics/Light.h index 37670176cc..81a6fddbd3 100755 --- a/libraries/graphics/src/graphics/Light.h +++ b/libraries/graphics/src/graphics/Light.h @@ -199,7 +199,7 @@ protected: float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off float _shadowsMaxDistance { 40.0f }; - float _shadowBias { 0.5f }; // 0.23f will roughly give the default constant and slope values + float _shadowBias { 0.5f }; bool _castShadows{ false }; void updateLightRadius(); diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index 524deaaad2..ccdf45cedc 100755 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -16,7 +16,8 @@ #include "ViewFrustum.h" std::string LightStage::_stageName { "LIGHT_STAGE"}; -const glm::mat4 LightStage::Shadow::_biasMatrix{ +// The bias matrix goes from homogeneous coordinates to UV coords (see http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#basic-shader) +const glm::mat4 LightStage::Shadow::_biasMatrix { 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, @@ -249,7 +250,7 @@ void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, } void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth, float farDepth, float fixedBias, float slopeBias) { + float nearDepth, float farDepth) { assert(nearDepth < farDepth); assert(cascadeIndex < _cascades.size()); @@ -300,7 +301,12 @@ void LightStage::Shadow::setKeylightCascadeFrustum(unsigned int cascadeIndex, co auto& schema = _schemaBuffer.edit(); auto& schemaCascade = schema.cascades[cascadeIndex]; schemaCascade.reprojection = _biasMatrix * ortho * shadowViewInverse.getMatrix(); - schemaCascade.fixedBias = fixedBias; +} + +void LightStage::Shadow::setKeylightCascadeBias(unsigned int cascadeIndex, float constantBias, float slopeBias) { + auto& schema = _schemaBuffer.edit(); + auto& schemaCascade = schema.cascades[cascadeIndex]; + schemaCascade.fixedBias = constantBias; schemaCascade.slopeBias = slopeBias; } diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h index 4da66843cc..36e62c614f 100755 --- a/libraries/render-utils/src/LightStage.h +++ b/libraries/render-utils/src/LightStage.h @@ -81,7 +81,8 @@ public: void setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth = 1.0f, float farDepth = 1000.0f); void setKeylightCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& viewFrustum, - float nearDepth = 1.0f, float farDepth = 1000.0f, float fixedBias = 0.005f, float slopeBias = 0.005f); + float nearDepth = 1.0f, float farDepth = 1000.0f); + void setKeylightCascadeBias(unsigned int cascadeIndex, float constantBias, float slopeBias); void setCascadeFrustum(unsigned int cascadeIndex, const ViewFrustum& shadowFrustum); const UniformBufferView& getBuffer() const { return _schemaBuffer; } diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 484064f73d..0d0b776074 100755 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -329,37 +329,31 @@ void RenderShadowSetup::configure(const Config& config) { } void RenderShadowSetup::calculateBiases(float biasInput) { - // slope scaling values derived from ratio between original constantBias and slopeBias pairs - const std::array SLOPE_SCALES = {{ 2.7f, 3.0f, 3.7f, 3.5f }}; - const float CONVERT_BIAS = 100.0f; - const float MIN_SCALE_DIVISOR = 0.5f; - - // the bias is relative to resolution - // to remain consistent with the constant and slope bias values, the biasInput - // value is in the 0.0 - 1.0 range but needs to be scaled up for further calculations - // TODO: expose variable resolution - int resolution = LightStage::Shadow::MAP_SIZE; - const int DEFAULT_RESOLUTION = LightStage::Shadow::MAP_SIZE; - float inverseResolution = 1.0f / (float)resolution; - int resolutionScale = DEFAULT_RESOLUTION * inverseResolution; - float convertedBias = biasInput * (CONVERT_BIAS / resolutionScale); - float scaleFactor = 1.0f; + const std::array CONSTANT_CASCADE_SCALE = {{ 0.01f, 0.01f, 0.015f, 0.02f }}; + const float SLOPE_BIAS_SCALE = 0.005f; for (int i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { - scaleFactor = convertedBias * (cacasdeDistances[0] / glm::max(MIN_SCALE_DIVISOR, cacasdeDistances[i + SHADOW_CASCADE_MAX_COUNT])) * inverseResolution; - float constantBias = cacasdeDistances[i] * scaleFactor; - float slopeBias = cacasdeDistances[i] * scaleFactor * SLOPE_SCALES[i]; + auto& cascade = _globalShadowObject->getCascade(i); + + // Constant bias is dependent on the depth precision + float cascadeDepth = cascade.getMaxDistance() - cascade.getMinDistance(); + float constantBias = CONSTANT_CASCADE_SCALE[i] * biasInput / cascadeDepth; setConstantBias(i, constantBias); - setSlopeBias(i, slopeBias); + + // Slope bias is dependent on the texel size + float cascadeWidth = cascade.getFrustum()->getWidth(); + float cascadeHeight = cascade.getFrustum()->getHeight(); + float cascadeTexelMaxDim = glm::max(cascadeWidth, cascadeHeight) / LightStage::Shadow::MAP_SIZE; // TODO: variable cascade resolution + setSlopeBias(i, cascadeTexelMaxDim * constantBias / SLOPE_BIAS_SCALE); } } void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) { - _bias[cascadeIndex]._constant = value * value * value * 0.004f; + _bias[cascadeIndex]._constant = value; } void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { - _bias[cascadeIndex]._slope = value * value * value * 0.001f; + _bias[cascadeIndex]._slope = value; } void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { @@ -398,9 +392,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c // Update our biases and maxDistance from the light or config _globalShadowObject->setMaxDistance(maxDistance > 0.0f ? maxDistance : currentKeyLight->getShadowsMaxDistance()); + // Adjust each cascade frustum for (unsigned int cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) { - cacasdeDistances[cascadeIndex] = _globalShadowObject->getCascade(cascadeIndex).getMaxDistance(); - cacasdeDistances[cascadeIndex + SHADOW_CASCADE_MAX_COUNT] = _globalShadowObject->getCascade(cascadeIndex).getMinDistance(); + _globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); } calculateBiases(biasInput > 0.0f ? biasInput : currentKeyLight->getShadowBias()); @@ -416,14 +410,9 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c if (slopeBias > 0.0f) { setSlopeBias(cascadeIndex, slopeBias); } - } - // Adjust each cascade frustum - for (unsigned int cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) { auto& bias = _bias[cascadeIndex]; - _globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), - SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, - bias._constant, bias._slope); + _globalShadowObject->setKeylightCascadeBias(cascadeIndex, bias._constant, bias._slope); } _shadowFrameCache->pushShadow(_globalShadowObject); diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index 23047ee179..98b5ac1e10 100755 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -138,7 +138,6 @@ private: float slopeBias3; float biasInput; float maxDistance; - std::array cacasdeDistances; // 4 max then 4 min distances void setConstantBias(int cascadeIndex, float value); void setSlopeBias(int cascadeIndex, float value); diff --git a/libraries/render-utils/src/directional_skybox_light_shadow.slf b/libraries/render-utils/src/directional_skybox_light_shadow.slf index 8716d60d54..48d59fa364 100644 --- a/libraries/render-utils/src/directional_skybox_light_shadow.slf +++ b/libraries/render-utils/src/directional_skybox_light_shadow.slf @@ -35,7 +35,6 @@ void main(void) { vec3 worldLightDirection = getLightDirection(shadowLight); float shadowAttenuation = evalShadowAttenuation(worldLightDirection, worldPos, -viewPos.z, frag.normal); - // Light mapped or not ? if (frag.mode == FRAG_MODE_UNLIT || frag.mode == FRAG_MODE_LIGHTMAPPED) { discard; } else { diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index ff50bf297c..6af0b21d1b 100755 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -156,7 +156,7 @@ Rectangle { integral: false config: shadowConfig property: "constantBias"+modelData - max: 3.0 + max: 1.0 min: 0.0 height: 38 width: 250 @@ -166,7 +166,7 @@ Rectangle { integral: false config: shadowConfig property: "slopeBias"+modelData - max: 3.0 + max: 1.0 min: 0.0 height: 38 width: 250