diff --git a/libraries/graphics/src/graphics/Light.cpp b/libraries/graphics/src/graphics/Light.cpp index 8a7281880e..a5d03beda1 100755 --- a/libraries/graphics/src/graphics/Light.cpp +++ b/libraries/graphics/src/graphics/Light.cpp @@ -89,6 +89,14 @@ float Light::getShadowsBiasScale() const { return _shadowsBiasScale; } +void Light::setBiasInput(float bias) { + _biasInput = bias; +} + +float Light::getBiasInput() const { + return _biasInput; +} + void Light::setColor(const Color& color) { _lightSchemaBuffer.edit().irradiance.color = color; updateLightRadius(); diff --git a/libraries/graphics/src/graphics/Light.h b/libraries/graphics/src/graphics/Light.h index 824a9138c0..9b431b3e26 100755 --- a/libraries/graphics/src/graphics/Light.h +++ b/libraries/graphics/src/graphics/Light.h @@ -112,6 +112,9 @@ public: void setShadowsBiasScale(const float scale); float getShadowsBiasScale() const; + void setBiasInput(float bias); + float getBiasInput() const; + void setOrientation(const Quat& orientation); const glm::quat& getOrientation() const { return _transform.getRotation(); } @@ -200,6 +203,7 @@ protected: float _shadowsMaxDistance{ 40.0f }; float _shadowsBiasScale{ 1.0f }; + float _biasInput{ 0.5f }; // 0.23f will roughly give the default constant and slope values bool _castShadows{ false }; void updateLightRadius(); diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp old mode 100644 new mode 100755 diff --git a/libraries/render-utils/src/LightStage.h b/libraries/render-utils/src/LightStage.h old mode 100644 new mode 100755 diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp old mode 100644 new mode 100755 index 5de89a11b5..f54b2e563e --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -56,7 +56,6 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); } - const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); @@ -318,16 +317,76 @@ RenderShadowSetup::RenderShadowSetup() : } void RenderShadowSetup::configure(const Config& configuration) { - setConstantBias(0, configuration.constantBias0); - setSlopeBias(0, configuration.slopeBias0); -#if SHADOW_CASCADE_MAX_COUNT>1 - setConstantBias(1, configuration.constantBias1); - setSlopeBias(1, configuration.slopeBias1); - setConstantBias(2, configuration.constantBias2); - setSlopeBias(2, configuration.slopeBias2); - setConstantBias(3, configuration.constantBias3); - setSlopeBias(3, configuration.slopeBias3); -#endif + distanceTriggeredByConfig = _globalMaxDistance != configuration.globalMaxDistance; + biasTriggeredByConfig = _biasInput != configuration.biasInput; + + // go back to using the config's default bias values if a change to any of those is triggered + if (constant0 != configuration.constantBias0 || slope0 != configuration.slopeBias0 || + constant1 != configuration.constantBias1 || slope1 != configuration.slopeBias1 || + constant2 != configuration.constantBias2 || slope2 != configuration.slopeBias2 || + constant3 != configuration.constantBias3 || slope3 != configuration.slopeBias3) { + constant0 = configuration.constantBias0; + slope0 = configuration.slopeBias0; + constant1 = configuration.constantBias1; + slope1 = configuration.slopeBias1; + constant2 = configuration.constantBias2; + slope2 = configuration.slopeBias2; + constant3 = configuration.constantBias3; + slope3 = configuration.slopeBias3; + changeInDefaultConfigValues = true; + distanceTriggeredByConfig = false; + biasTriggeredByConfig = false; + + setConstantBias(0, constant0); + setSlopeBias(0, slope0); + + #if SHADOW_CASCADE_MAX_COUNT > 1 + setConstantBias(1, constant1); + setConstantBias(2, constant2); + setConstantBias(3, constant3); + + setSlopeBias(1, slope1); + setSlopeBias(2, slope2); + setSlopeBias(3, slope3); + #endif + } + + // modify bias using single input and work in calculateBias() + if (distanceTriggeredByConfig) { + changeInDefaultConfigValues = false; + _globalMaxDistance = configuration.globalMaxDistance; + calculateBiases(); + } + if (biasTriggeredByConfig) { + changeInDefaultConfigValues = false; + _biasInput = configuration.biasInput; + calculateBiases(); + } +} + +void RenderShadowSetup::calculateBiases() { + // 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 + float inverseResolution = 1.0f / (float)resolution; + int resolutionScale = DEFAULT_RESOLUTION * inverseResolution; + float convertedBias = _biasInput * (CONVERT_BIAS / resolutionScale); + std::array localConstants; + std::array localSlopes; + float scaleFactor = 1.0f; + + for (int i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { + scaleFactor = convertedBias * (cacasdeDistances[0] / glm::max(MIN_SCALE_DIVISOR, cacasdeDistances[i + 4])) * inverseResolution; + localConstants[i] = cacasdeDistances[i] * scaleFactor; + localSlopes[i] = cacasdeDistances[i] * scaleFactor * SLOPE_SCALES[i]; + setConstantBias(i, localConstants[i]); + setSlopeBias(i, localSlopes[i]); + } } void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) { @@ -368,20 +427,35 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c if (!_globalShadowObject) { _globalShadowObject = std::make_shared(currentKeyLight, SHADOW_CASCADE_COUNT); } - + resolution = _globalShadowObject->MAP_SIZE; _globalShadowObject->setLight(currentKeyLight); _globalShadowObject->setKeylightFrustum(args->getViewFrustum(), SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR); - + // if the max distance isn't altered externally, grab the value from the light + if (!distanceTriggeredByConfig && !biasTriggeredByConfig) { + _globalMaxDistance = currentKeyLight->getShadowsMaxDistance(); + } + _globalShadowObject->setMaxDistance(_globalMaxDistance); + auto& firstCascade = _globalShadowObject->getCascade(0); auto& firstCascadeFrustum = firstCascade.getFrustum(); unsigned int cascadeIndex; + for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) { + cacasdeDistances[cascadeIndex] = _globalShadowObject->getCascade(cascadeIndex).getMaxDistance(); + cacasdeDistances[cascadeIndex + 4] = _globalShadowObject->getCascade(cascadeIndex).getMinDistance(); + } + + if (!biasTriggeredByConfig && !distanceTriggeredByConfig && !changeInDefaultConfigValues) { + setBiasInput(currentKeyLight->getBiasInput()); + calculateBiases(); + } + // Adjust each cascade frustum const auto biasScale = currentKeyLight->getShadowsBiasScale(); for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) { auto& bias = _bias[cascadeIndex]; - _globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), - SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, + _globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), + SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, bias._constant, bias._slope * biasScale); } diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h old mode 100644 new mode 100755 index ef469a7247..ceca28cec8 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -50,7 +50,6 @@ signals: class RenderShadowTask { public: - // There is one AABox per shadow cascade using CascadeBoxes = render::VaryingArray; using Input = render::VaryingSet2; @@ -74,9 +73,11 @@ public: }; CullFunctor _cullFunctor; - }; +const float DEFAULT_BIAS_INPUT = 0.5f; +const float DEFAULT_MAX_DISTANCE = 40.0f; + class RenderShadowSetupConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(float constantBias0 MEMBER constantBias0 NOTIFY dirty) @@ -87,7 +88,12 @@ class RenderShadowSetupConfig : public render::Job::Config { Q_PROPERTY(float slopeBias1 MEMBER slopeBias1 NOTIFY dirty) Q_PROPERTY(float slopeBias2 MEMBER slopeBias2 NOTIFY dirty) Q_PROPERTY(float slopeBias3 MEMBER slopeBias3 NOTIFY dirty) + Q_PROPERTY(float biasInput MEMBER biasInput NOTIFY dirty) + Q_PROPERTY(float globalMaxDistance MEMBER globalMaxDistance NOTIFY dirty) + public: + float biasInput{ DEFAULT_BIAS_INPUT }; + float globalMaxDistance{ DEFAULT_MAX_DISTANCE }; float constantBias0{ 0.15f }; float constantBias1{ 0.15f }; @@ -114,7 +120,6 @@ public: void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); private: - ViewFrustumPointer _cameraFrustum; ViewFrustumPointer _coarseShadowFrustum; struct { @@ -125,8 +130,29 @@ private: LightStage::ShadowFrame::Object _globalShadowObject; LightStage::ShadowFramePointer _shadowFrameCache; + const int DEFAULT_RESOLUTION = 1024; + float _biasInput{ DEFAULT_BIAS_INPUT }; + float _globalMaxDistance{ DEFAULT_MAX_DISTANCE }; + int resolution{ DEFAULT_RESOLUTION }; + + // initialize with values from RenderShadowSetupConfig + float constant0{ 0.15f }; + float constant1{ 0.15f }; + float constant2{ 0.175f }; + float constant3{ 0.2f }; + float slope0{ 0.4f }; + float slope1{ 0.45f }; + float slope2{ 0.65f }; + float slope3{ 0.7f }; + bool changeInDefaultConfigValues{ false }; + bool distanceTriggeredByConfig{ false }; + bool biasTriggeredByConfig{ false }; + std::array cacasdeDistances; // 4 max then 4 min distances + void setConstantBias(int cascadeIndex, float value); void setSlopeBias(int cascadeIndex, float value); + void setBiasInput(float input) { _biasInput = input; } + void calculateBiases(); }; class RenderShadowCascadeSetup { diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh old mode 100644 new mode 100755 index 94bec86b34..ac55bc95e5 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -63,7 +63,7 @@ ShadowSampleOffsets evalShadowFilterOffsets(vec4 position) { coords.y += (index & 2) >> 1; #endif - // Offset for efficient PCF, see http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html + // Offset for efficient PCF, see https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch11.html ivec2 offset = coords & ivec2(1,1); offset.y = (offset.x+offset.y) & 1;