diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli index 97862b6f6e..2fea4650b3 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli @@ -62,6 +62,7 @@ class ProjectedShadow float3 m_lightDirection; float3 m_normalVector; float3 m_shadowPosition; + float m_bias; }; float ProjectedShadow::GetVisibility( @@ -238,7 +239,7 @@ float ProjectedShadow::GetVisibilityEsm() } const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy); const float depth = PerspectiveDepthToLinear( - m_shadowPosition.z, + m_shadowPosition.z - m_bias, coefficients); const float occluder = shadowmap.SampleLevel( PassSrg::LinearSampler, @@ -280,7 +281,7 @@ float ProjectedShadow::GetVisibilityEsmPcf() } const float3 atlasPosition = GetAtlasPosition(m_shadowPosition.xy); const float depth = PerspectiveDepthToLinear( - m_shadowPosition.z, + m_shadowPosition.z - m_bias, coefficients); const float occluder = shadowmap.SampleLevel( PassSrg::LinearSampler, @@ -346,7 +347,7 @@ float ProjectedShadow::SamplePcfBicubic() param.shadowPos = float3(atlasPosition.xy * ViewSrg::m_invShadowmapAtlasSize, atlasPosition.z); param.shadowMapSize = ViewSrg::m_shadowmapAtlasSize; param.invShadowMapSize = ViewSrg::m_invShadowmapAtlasSize; - param.comparisonValue = m_shadowPosition.z - ViewSrg::m_projectedShadows[m_shadowIndex].m_bias; + param.comparisonValue = m_shadowPosition.z - m_bias; param.samplerState = SceneSrg::m_hwPcfSampler; if (filteringSampleCount <= 4) @@ -384,8 +385,8 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition) PassSrg::LinearSampler, float3(atlasPosition.xy * invAtlasSize, atlasPosition.z), /*LOD=*/0).r; const float depthDiff = depthInShadowmap - shadowPosition.z; - float bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias; - if (depthDiff < -bias) + + if (depthDiff < -m_bias) { return true; } @@ -428,6 +429,8 @@ void ProjectedShadow::SetShadowPosition() const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix; float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition, 1)); m_shadowPosition = shadowPositionHomogeneous.xyz / shadowPositionHomogeneous.w; + + m_bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias / shadowPositionHomogeneous.w; } float3 ProjectedShadow::GetAtlasPosition(float2 texturePosition) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index 9248add6f5..e4986eee93 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -84,6 +84,8 @@ namespace AZ //! Sets if shadows are enabled virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; + //! Sets the shadow bias + virtual void SetShadowBias(LightHandle handle, float bias) = 0; //! Sets the shadowmap size (width and height) of the light. virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; //! Specifies filter method of shadows. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 8ad4fb89de..3383378dc7 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -66,6 +66,8 @@ namespace AZ virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; //! Sets the shadowmap size (width and height) of the light. virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; + //! Sets the shadow bias + virtual void SetShadowBias(LightHandle handle, float bias) = 0; //! Specifies filter method of shadows. virtual void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) = 0; //! Specifies the width of boundary between shadowed area and lit area in radians. The degree ofshadowed gradually changes on diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h index c0cfff3dd5..6cbb0cfef1 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Shadows/ProjectedShadowFeatureProcessorInterface.h @@ -50,6 +50,8 @@ namespace AZ::Render virtual void SetFieldOfViewY(ShadowId id, float fieldOfView) = 0; //! Sets the maximum resolution of the shadow map virtual void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) = 0; + //! Sets the shadow bias + virtual void SetShadowBias(ShadowId id, float bias) = 0; //! Sets the shadowmap Pcf method. virtual void SetPcfMethod(ShadowId id, PcfMethod method) = 0; //! Sets the shadow filter method diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index 54410544a7..55be9d232e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -308,6 +308,11 @@ namespace AZ AZStd::invoke(AZStd::forward(functor), m_shadowFeatureProcessor, shadowId, AZStd::forward(param)); } } + + void DiskLightFeatureProcessor::SetShadowBias(LightHandle handle, float bias) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias); + } void DiskLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 0ff8efb1b1..2e97ae1ded 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -50,6 +50,7 @@ namespace AZ void SetConstrainToConeLight(LightHandle handle, bool useCone) override; void SetConeAngles(LightHandle handle, float innerDegrees, float outerDegrees) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override; + void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index 2b54b6ede1..9baa2ae1c2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -277,6 +277,11 @@ namespace AZ } } } + + void PointLightFeatureProcessor::SetShadowBias(LightHandle handle, float bias) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias); + } void PointLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) { diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index d7bb25c71c..b7b644da9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -47,6 +47,7 @@ namespace AZ void SetAttenuationRadius(LightHandle handle, float attenuationRadius) override; void SetBulbRadius(LightHandle handle, float bulbRadius) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override; + void SetShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetSofteningBoundaryWidthAngle(LightHandle handle, float boundaryWidthRadians) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 10dcffcf74..03ee176fd0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -143,7 +143,15 @@ namespace AZ::Render shadowProperty.m_desc.m_fieldOfViewYRadians = fieldOfViewYRadians; UpdateShadowView(shadowProperty); } - + + void ProjectedShadowFeatureProcessor::SetShadowBias(ShadowId id, float bias) + { + AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowBias()."); + + ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id); + shadowProperty.m_bias = bias; + } + void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution()."); @@ -265,23 +273,20 @@ namespace AZ::Render view->SetCameraTransform(Matrix3x4::CreateFromTransform(desc.m_transform)); ShadowData& shadowData = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - shadowData.m_bias = (nearDist / farDist) * 0.1f; + + // Adjust the manually set bias to a more appropriate range for the shader. Scale the bias by the + // near plane so that the bias appears consistent as other light properties change. + shadowData.m_bias = nearDist * shadowProperty.m_bias * 0.01f; FilterParameter& esmData = m_shadowData.GetElement(shadowProperty.m_shadowId.GetIndex()); - if (FilterMethodIsEsm(shadowData)) - { - // Set parameters to calculate linear depth if ESM is used. - m_filterParameterNeedsUpdate = true; - esmData.m_isEnabled = true; - esmData.m_n_f_n = nearDist / (farDist - nearDist); - esmData.m_n_f = nearDist - farDist; - esmData.m_f = farDist; - } - else - { - // Reset enabling flag if ESM is not used. - esmData.m_isEnabled = false; - } + + // Set parameters to calculate linear depth if ESM is used. + esmData.m_n_f_n = nearDist / (farDist - nearDist); + esmData.m_n_f = nearDist - farDist; + esmData.m_f = farDist; + + esmData.m_isEnabled = FilterMethodIsEsm(shadowData); + m_filterParameterNeedsUpdate = m_filterParameterNeedsUpdate || esmData.m_isEnabled; for (EsmShadowmapsPass* esmPass : m_esmShadowmapsPasses) { diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index 4da4e2ff1e..3dbf88addb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -47,6 +47,7 @@ namespace AZ::Render void SetAspectRatio(ShadowId id, float aspectRatio) override; void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override; void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override; + void SetShadowBias(ShadowId id, float bias) override; void SetPcfMethod(ShadowId id, PcfMethod method); void SetEsmExponent(ShadowId id, float exponent); void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override; @@ -79,6 +80,7 @@ namespace AZ::Render { ProjectedShadowDescriptor m_desc; RPI::ViewPtr m_shadowmapView; + float m_bias = 0.1f; ShadowId m_shadowId; }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h index 9286db2817..06b00a6b84 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -101,6 +101,12 @@ namespace AZ //! Sets if shadows should be enabled. virtual void SetEnableShadow(bool enabled) = 0; + + //! Returns the shadow bias. + virtual float GetShadowBias() const = 0; + + //! Sets the shadow bias. + virtual void SetShadowBias(float bias) = 0; //! Returns the maximum width and height of shadowmap. virtual ShadowmapSize GetShadowmapMaxSize() const = 0; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index 8a3bb337a2..b890b3e264 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -56,6 +56,7 @@ namespace AZ // Shadows (only used for supported shapes) bool m_enableShadow = false; + float m_bias = 0.1f; ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256; ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; PcfMethod m_pcfMethod = PcfMethod::Bicubic; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index c442ee39ae..b9da5ccff4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -18,7 +18,7 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(6) // ATOM-15654 + ->Version(7) // ATOM-16034 ->Field("LightType", &AreaLightComponentConfig::m_lightType) ->Field("Color", &AreaLightComponentConfig::m_color) ->Field("IntensityMode", &AreaLightComponentConfig::m_intensityMode) @@ -33,6 +33,7 @@ namespace AZ ->Field("OuterShutterAngleDegrees", &AreaLightComponentConfig::m_outerShutterAngleDegrees) // Shadows ->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow) + ->Field("Shadow Bias", &AreaLightComponentConfig::m_bias) ->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize) ->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod) ->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index a6bf66d20e..b90b145320 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -68,6 +68,8 @@ namespace AZ::Render ->Event("GetEnableShadow", &AreaLightRequestBus::Events::GetEnableShadow) ->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow) + ->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias) + ->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias) ->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize) ->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize) ->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod) @@ -94,6 +96,7 @@ namespace AZ::Render ->VirtualProperty("OuterShutterAngle", "GetOuterShutterAngle", "SetOuterShutterAngle") ->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow") + ->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias") ->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") ->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle") @@ -307,6 +310,7 @@ namespace AZ::Render m_lightShapeDelegate->SetEnableShadow(m_configuration.m_enableShadow); if (m_configuration.m_enableShadow) { + m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias); m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize); m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); m_lightShapeDelegate->SetSofteningBoundaryWidthAngle(m_configuration.m_boundaryWidthInDegrees); @@ -467,6 +471,20 @@ namespace AZ::Render m_lightShapeDelegate->SetEnableShadow(enabled); } } + + float AreaLightComponentController::GetShadowBias() const + { + return m_configuration.m_bias; + } + + void AreaLightComponentController::SetShadowBias(float bias) + { + m_configuration.m_bias = bias; + if (m_lightShapeDelegate) + { + m_lightShapeDelegate->SetShadowBias(bias); + } + } ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index 0a835a75d0..d290beb81d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -76,6 +76,8 @@ namespace AZ bool GetEnableShadow() const override; void SetEnableShadow(bool enabled) override; + float GetShadowBias() const override; + void SetShadowBias(float bias) override; ShadowmapSize GetShadowmapMaxSize() const override; void SetShadowmapMaxSize(ShadowmapSize size) override; ShadowFilterMethod GetShadowFilterMethod() const override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index 06d0b39981..c6e4441d57 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -123,6 +123,14 @@ namespace AZ::Render } } + void DiskLightDelegate::SetShadowBias(float bias) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetShadowBias(GetLightHandle(), bias); + } + } + void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index 53ddae669b..6931068635 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -41,6 +41,7 @@ namespace AZ void SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees) override; void SetEnableShadow(bool enabled) override; + void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetSofteningBoundaryWidthAngle(float widthInDegrees) override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index b58ca6448a..e45f460f18 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -131,6 +131,15 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_bias, "Bias", "How deep in shadow a surface must be before being affected by it.") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Min, 0.0f) + ->Attribute(Edit::Attributes::Max, 100.0f) + ->Attribute(Edit::Attributes::SoftMin, 0.0f) + ->Attribute(Edit::Attributes::SoftMax, 1.0f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowFilterMethod, "Shadow filter method", "Filtering method of edge-softening of shadows.\n" " None: no filtering\n" diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index 18d88b72af..415878081c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -53,6 +53,7 @@ namespace AZ void SetShutterAngles([[maybe_unused]]float innerAngleDegrees, [[maybe_unused]]float outerAngleDegrees) override {}; void SetEnableShadow(bool enabled) override { m_shadowsEnabled = enabled; }; + void SetShadowBias([[maybe_unused]] float bias) override {}; void SetShadowmapMaxSize([[maybe_unused]] ShadowmapSize size) override {}; void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {}; void SetSofteningBoundaryWidthAngle([[maybe_unused]] float widthInDegrees) override {}; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 52f9958d40..f18c3ef9af 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -67,8 +67,10 @@ namespace AZ // Shadows - //! Sets if shadows should be enabled + //! Sets if shadows should be enabled virtual void SetEnableShadow(bool enabled) = 0; + //! Sets the shadow bias + virtual void SetShadowBias(float bias) = 0; //! Sets the maximum resolution of the shadow map virtual void SetShadowmapMaxSize(ShadowmapSize size) = 0; //! Sets the filter method for the shadow diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index 1da6847269..edf08ba8c9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -11,121 +11,124 @@ #include #include -namespace AZ +namespace AZ::Render { - namespace Render + SphereLightDelegate::SphereLightDelegate(LmbrCentral::SphereShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible) + : LightDelegateBase(entityId, isVisible) + , m_shapeBus(shapeBus) { - SphereLightDelegate::SphereLightDelegate(LmbrCentral::SphereShapeComponentRequests* shapeBus, EntityId entityId, bool isVisible) - : LightDelegateBase(entityId, isVisible) - , m_shapeBus(shapeBus) - { - InitBase(entityId); - } + InitBase(entityId); + } - float SphereLightDelegate::CalculateAttenuationRadius(float lightThreshold) const - { - // Calculate the radius at which the irradiance will be equal to cutoffIntensity. - float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen); - return sqrt(intensity / lightThreshold); - } + float SphereLightDelegate::CalculateAttenuationRadius(float lightThreshold) const + { + // Calculate the radius at which the irradiance will be equal to cutoffIntensity. + float intensity = GetPhotometricValue().GetCombinedIntensity(PhotometricUnit::Lumen); + return sqrt(intensity / lightThreshold); + } - void SphereLightDelegate::HandleShapeChanged() + void SphereLightDelegate::HandleShapeChanged() + { + if (GetLightHandle().IsValid()) { - if (GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation()); - GetFeatureProcessor()->SetBulbRadius(GetLightHandle(), GetRadius()); - } + GetFeatureProcessor()->SetPosition(GetLightHandle(), GetTransform().GetTranslation()); + GetFeatureProcessor()->SetBulbRadius(GetLightHandle(), GetRadius()); } + } - float SphereLightDelegate::GetSurfaceArea() const - { - float radius = GetRadius(); - return 4.0f * Constants::Pi * radius * radius; - } + float SphereLightDelegate::GetSurfaceArea() const + { + float radius = GetRadius(); + return 4.0f * Constants::Pi * radius * radius; + } - float SphereLightDelegate::GetRadius() const - { - return m_shapeBus->GetRadius() * GetTransform().GetUniformScale(); - } + float SphereLightDelegate::GetRadius() const + { + return m_shapeBus->GetRadius() * GetTransform().GetUniformScale(); + } - void SphereLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const + void SphereLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const + { + if (isSelected) { - if (isSelected) - { - debugDisplay.SetColor(color); + debugDisplay.SetColor(color); - // Draw a sphere for the attenuation radius - debugDisplay.DrawWireSphere(transform.GetTranslation(), GetConfig()->m_attenuationRadius); - } + // Draw a sphere for the attenuation radius + debugDisplay.DrawWireSphere(transform.GetTranslation(), GetConfig()->m_attenuationRadius); } + } - void SphereLightDelegate::SetEnableShadow(bool enabled) + void SphereLightDelegate::SetEnableShadow(bool enabled) + { + Base::SetEnableShadow(enabled); + + if (GetLightHandle().IsValid()) { - Base::SetEnableShadow(enabled); - - if (GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); - } + GetFeatureProcessor()->SetShadowsEnabled(GetLightHandle(), enabled); } - - void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) + } + + void SphereLightDelegate::SetShadowBias(float bias) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); - } + GetFeatureProcessor()->SetShadowBias(GetLightHandle(), bias); } + } - void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) + void SphereLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); - } + GetFeatureProcessor()->SetShadowmapMaxResolution(GetLightHandle(), size); } + } - void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) + void SphereLightDelegate::SetShadowFilterMethod(ShadowFilterMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); - } + GetFeatureProcessor()->SetShadowFilterMethod(GetLightHandle(), method); } + } - void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) + void SphereLightDelegate::SetSofteningBoundaryWidthAngle(float widthInDegrees) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); - } + GetFeatureProcessor()->SetSofteningBoundaryWidthAngle(GetLightHandle(), DegToRad(widthInDegrees)); } + } - void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) + void SphereLightDelegate::SetPredictionSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); - } + GetFeatureProcessor()->SetPredictionSampleCount(GetLightHandle(), count); } + } - void SphereLightDelegate::SetPcfMethod(PcfMethod method) + void SphereLightDelegate::SetFilteringSampleCount(uint32_t count) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method); - } + GetFeatureProcessor()->SetFilteringSampleCount(GetLightHandle(), count); } + } - void SphereLightDelegate::SetEsmExponent(float esmExponent) + void SphereLightDelegate::SetPcfMethod(PcfMethod method) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) { - if (GetShadowsEnabled() && GetLightHandle().IsValid()) - { - GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); - } + GetFeatureProcessor()->SetPcfMethod(GetLightHandle(), method); } + } - - } // namespace Render -} // namespace AZ + void SphereLightDelegate::SetEsmExponent(float esmExponent) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); + } + } +} // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 6dd872d693..984af56c17 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -31,6 +31,7 @@ namespace AZ float GetSurfaceArea() const override; float GetEffectiveSolidAngle() const override { return PhotometricValue::OmnidirectionalSteradians; } void SetEnableShadow(bool enabled) override; + void SetShadowBias(float bias) override; void SetShadowmapMaxSize(ShadowmapSize size) override; void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetSofteningBoundaryWidthAngle(float widthInDegrees) override;