From 959ec14df63280f116297c1444ad37c69b1e54f9 Mon Sep 17 00:00:00 2001 From: mriegger Date: Thu, 10 Jun 2021 15:29:38 -0700 Subject: [PATCH 01/18] Exposing esm exponent --- .../Features/Shadow/ProjectedShadow.azsli | 16 ++++++++----- .../CoreLights/ViewSrg.azsli | 2 ++ .../Shaders/Shadow/DepthExponentiation.azsl | 16 ++++++++----- .../DiskLightFeatureProcessorInterface.h | 5 +++- .../PointLightFeatureProcessorInterface.h | 2 ++ .../CoreLights/DiskLightFeatureProcessor.cpp | 5 ++++ .../CoreLights/DiskLightFeatureProcessor.h | 1 + .../CoreLights/PointLightFeatureProcessor.cpp | 5 ++++ .../CoreLights/PointLightFeatureProcessor.h | 1 + .../ProjectedShadowFeatureProcessor.cpp | 7 ++++++ .../Shadows/ProjectedShadowFeatureProcessor.h | 3 +++ .../CommonFeatures/CoreLights/AreaLightBus.h | 7 ++++++ .../CoreLights/AreaLightComponentConfig.h | 3 +++ .../CoreLights/AreaLightComponentConfig.cpp | 11 +++++++-- .../AreaLightComponentController.cpp | 24 ++++++++++++++++--- .../CoreLights/AreaLightComponentController.h | 2 ++ .../Source/CoreLights/DiskLightDelegate.cpp | 8 +++++++ .../Source/CoreLights/DiskLightDelegate.h | 1 + .../CoreLights/EditorAreaLightComponent.cpp | 16 +++++++++++-- .../Source/CoreLights/LightDelegateBase.h | 1 + .../CoreLights/LightDelegateInterface.h | 2 ++ .../Source/CoreLights/SphereLightDelegate.cpp | 9 +++++++ .../Source/CoreLights/SphereLightDelegate.h | 1 + 23 files changed, 128 insertions(+), 20 deletions(-) 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 e4cb87802a..8668ac10d8 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 @@ -226,7 +226,7 @@ float ProjectedShadow::GetVisibilityEsm() } const float invAtlasSize = ViewSrg::m_invShadowmapAtlasSize; - const Texture2DArray expShadowmap = PassSrg::m_projectedExponentialShadowmap; + const Texture2DArray shadowmap = PassSrg::m_projectedExponentialShadowmap; if (m_shadowPosition.x >= 0 && m_shadowPosition.x * size < size - PixelMargin && m_shadowPosition.y >= 0 && m_shadowPosition.y * size < size - PixelMargin) @@ -243,10 +243,12 @@ float ProjectedShadow::GetVisibilityEsm() const float depth = PerspectiveDepthToLinear( m_shadowPosition.z, coefficients); - const float expDepthInShadowmap = expShadowmap.Sample( + const float occluder = shadowmap.Sample( PassSrg::LinearSampler, float3(atlasPosition.xy * invAtlasSize, atlasPosition.z)).r; - const float ratio = exp(-EsmExponentialShift * depth) * expDepthInShadowmap; + + const float exponent = -ViewSrg::m_projectedShadows[m_shadowIndex].m_esmExponent * (depth - occluder); + const float ratio = exp(exponent); // pow() mitigates light bleeding to shadows from near shadow casters. return saturate( pow(ratio, 8) ); } @@ -265,7 +267,7 @@ float ProjectedShadow::GetVisibilityEsmPcf() } const float invAtlasSize = ViewSrg::m_invShadowmapAtlasSize; - const Texture2DArray expShadowmap = PassSrg::m_projectedExponentialShadowmap; + const Texture2DArray shadowmap = PassSrg::m_projectedExponentialShadowmap; if (m_shadowPosition.x >= 0 && m_shadowPosition.x * size < size - PixelMargin && m_shadowPosition.y >= 0 && m_shadowPosition.y * size < size - PixelMargin) @@ -282,10 +284,12 @@ float ProjectedShadow::GetVisibilityEsmPcf() const float depth = PerspectiveDepthToLinear( m_shadowPosition.z, coefficients); - const float expDepthInShadowmap = expShadowmap.Sample( + const float occluder = shadowmap.Sample( PassSrg::LinearSampler, float3(atlasPosition.xy * invAtlasSize, atlasPosition.z)).r; - float ratio = exp(-EsmExponentialShift * depth) * expDepthInShadowmap; + + const float exponent = -ViewSrg::m_projectedShadows[m_shadowIndex].m_esmExponent * (depth - occluder); + float ratio = exp(exponent); static const float pcfFallbackThreshold = 1.04; if (ratio > pcfFallbackThreshold) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli index 7a51d4c629..37b021e148 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderResourceGroups/CoreLights/ViewSrg.azsli @@ -92,6 +92,8 @@ partial ShaderResourceGroup ViewSrg uint m_filteringSampleCount; float2 m_unprojectConstants; float m_bias; + float m_esmExponent; + float3 m_padding; }; StructuredBuffer m_projectedShadows; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl index bea63c6b0b..c212718bf5 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl @@ -69,8 +69,15 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) // So this converts it to "depth" to emphasize the difference // within the frustum. depth = (depthInClip - distanceMin) / (1. - distanceMin); - } + + // Todo: Expose Esm exponent slider for directional lights + // This would remove the exp calculation below, collapsing it into a subtraction in DirectionalLightShadow.azsli + // ATOM-15775 + const float outValue = exp(EsmExponentialShift * depth); + PassSrg::m_outputShadowmap[dispatchId].r = outValue; break; + + } case ShadowmapLightType::Spot: { const float3 coefficients = float3( @@ -84,12 +91,9 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) // and it often causes light bleeding with ESM. // So this converts it to a linear depth to emphasize the // difference like a orthogonal depth. - depth = PerspectiveDepthToLinear(depthInClip, coefficients); - } + PassSrg::m_outputShadowmap[dispatchId].r = PerspectiveDepthToLinear(depthInClip, coefficients); break; + } } - - const float outValue = exp(EsmExponentialShift * depth); - PassSrg::m_outputShadowmap[dispatchId].r = outValue; } 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 ce911fecf7..f777cbbc27 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 @@ -100,10 +100,13 @@ namespace AZ virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the shadowmap Pcf (percentage closer filtering) method. virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0; + //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. + virtual void SetEsmExponent(LightHandle handle, float exponent) = 0; //! Sets all of the the disk data for the provided LightHandle. virtual void SetDiskData(LightHandle handle, const DiskLightData& data) = 0; - + + }; } // namespace Render } // namespace AZ 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 30d88cb839..c781030220 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 @@ -82,6 +82,8 @@ namespace AZ virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the shadowmap Pcf (percentage closer filtering) method. virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0; + //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. + virtual void SetEsmExponent(LightHandle handle, float exponent) = 0; //! Sets all of the the point data for the provided LightHandle. virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index d0fb702d5a..b3a39e8fe3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -343,6 +343,11 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); } + void DiskLightFeatureProcessor::SetEsmExponent(LightHandle handle, float exponent) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, exponent); + } + void DiskLightFeatureProcessor::UpdateShadow(LightHandle handle) { const DiskLightData& diskLight = m_diskLightData.GetData(handle.GetIndex()); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 8391506f63..1147272204 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -60,6 +60,7 @@ namespace AZ void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetPcfMethod(LightHandle handle, PcfMethod method) override; + void SetEsmExponent(LightHandle handle, float esmExponent) override; void SetDiskData(LightHandle handle, const DiskLightData& data) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index bb81c52b15..a5cb59e73c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -312,5 +312,10 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetPcfMethod, method); } + void PointLightFeatureProcessor::SetEsmExponent(LightHandle handle, float esmExponent) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index c0c377e960..897bf6dc3e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -57,6 +57,7 @@ namespace AZ void SetPredictionSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetPcfMethod(LightHandle handle, PcfMethod method) override; + void SetEsmExponent(LightHandle handle, float esmExponent) override; void SetPointData(LightHandle handle, const PointLightData& data) override; const Data::Instance GetLightBuffer() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index da174ab0d5..98b2fb9574 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -168,6 +168,13 @@ namespace AZ::Render m_deviceBufferNeedsUpdate = true; } + void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent) + { + ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); + shadowData.m_esmExponent = exponent; + m_deviceBufferNeedsUpdate = true; + } + void ProjectedShadowFeatureProcessor::SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowFilterMethod()."); diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index a131c914f2..bf03e490a6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -52,6 +52,7 @@ namespace AZ::Render void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override; void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override; void SetPcfMethod(ShadowId id, PcfMethod method); + void SetEsmExponent(ShadowId id, float exponent); void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override; void SetSofteningBoundaryWidthAngle(ShadowId id, float boundaryWidthRadians) override; void SetPredictionSampleCount(ShadowId id, uint16_t count) override; @@ -73,6 +74,8 @@ namespace AZ::Render uint32_t m_filteringSampleCount = 0; AZStd::array m_unprojectConstants = { {0, 0} }; float m_bias; + float m_esmExponent = 87.0f; + float m_padding[3]; }; // CPU data used for constructing & updating ShadowData 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 f4cb319c2f..9279326333 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -143,6 +143,13 @@ namespace AZ //! Sets the type of Pcf (percentage-closer filtering) to use. virtual void SetPcfMethod(PcfMethod method) = 0; + + //! Gets the Esm exponent. Higher values produce a steeper falloff between light and shadow. + virtual float GetEsmExponent() const = 0; + + //! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow. + virtual void SetEsmExponent(float exponent) = 0; + }; //! The EBus for requests to for setting and getting light component properties. 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 31cdb34ddd..e003d6a178 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -66,6 +66,7 @@ namespace AZ float m_boundaryWidthInDegrees = 0.25f; uint16_t m_predictionSampleCount = 4; uint16_t m_filteringSampleCount = 12; + float m_esmExponent = 87.0f; // The following functions provide information to an EditContext... @@ -124,6 +125,8 @@ namespace AZ //! Returns true if pcf boundary search is disabled. bool IsPcfBoundarySearchDisabled() const; + //! Returns true if exponential shadow maps are disabled. + bool IsEsmDisabled() const; }; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index 8f10204ae9..c9211e87a0 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -21,7 +21,7 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(5) // ATOM-14637 + ->Version(6) // ATOM-15654 ->Field("LightType", &AreaLightComponentConfig::m_lightType) ->Field("Color", &AreaLightComponentConfig::m_color) ->Field("IntensityMode", &AreaLightComponentConfig::m_intensityMode) @@ -41,7 +41,8 @@ namespace AZ ->Field("Softening Boundary Width", &AreaLightComponentConfig::m_boundaryWidthInDegrees) ->Field("Prediction Sample Count", &AreaLightComponentConfig::m_predictionSampleCount) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) - ->Field("Pcf Method", &AreaLightComponentConfig::m_pcfMethod); + ->Field("Pcf Method", &AreaLightComponentConfig::m_pcfMethod) + ->Field("Esm Exponent", &AreaLightComponentConfig::m_esmExponent) ; } } @@ -200,5 +201,11 @@ namespace AZ return m_pcfMethod != PcfMethod::BoundarySearch; } + + bool AreaLightComponentConfig::IsEsmDisabled() const + { + return !(m_shadowFilterMethod == ShadowFilterMethod::Esm || m_shadowFilterMethod == ShadowFilterMethod::EsmPcf); + } + } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index c1c957ed4c..f7e0d15c92 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -84,7 +84,9 @@ namespace AZ::Render ->Event("SetFilteringSampleCount", &AreaLightRequestBus::Events::SetFilteringSampleCount) ->Event("GetPcfMethod", &AreaLightRequestBus::Events::GetPcfMethod) ->Event("SetPcfMethod", &AreaLightRequestBus::Events::SetPcfMethod) - + ->Event("GetEsmExponent", &AreaLightRequestBus::Events::GetEsmExponent) + ->Event("SetEsmExponent", &AreaLightRequestBus::Events::SetEsmExponent) + ->VirtualProperty("AttenuationRadius", "GetAttenuationRadius", "SetAttenuationRadius") ->VirtualProperty("Color", "GetColor", "SetColor") ->VirtualProperty("EmitsLightBothDirections", "GetEmitsLightBothDirections", "SetEmitsLightBothDirections") @@ -101,8 +103,9 @@ namespace AZ::Render ->VirtualProperty("SofteningBoundaryWidthAngle", "GetSofteningBoundaryWidthAngle", "SetSofteningBoundaryWidthAngle") ->VirtualProperty("PredictionSampleCount", "GetPredictionSampleCount", "SetPredictionSampleCount") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") - ->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod"); - ; + ->VirtualProperty("PcfMethod", "GetPcfMethod", "SetPcfMethod") + ->VirtualProperty("EsmExponent", "GetEsmExponent", "SetEsmExponent"); + ; } } @@ -314,6 +317,7 @@ namespace AZ::Render m_lightShapeDelegate->SetPredictionSampleCount(m_configuration.m_predictionSampleCount); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); m_lightShapeDelegate->SetPcfMethod(m_configuration.m_pcfMethod); + m_lightShapeDelegate->SetEsmExponent(m_configuration.m_esmExponent); } } } @@ -565,6 +569,20 @@ namespace AZ::Render } } + float AreaLightComponentController::GetEsmExponent() const + { + return m_configuration.m_esmExponent; + } + + void AreaLightComponentController::SetEsmExponent(float esmExponent) + { + m_configuration.m_esmExponent = esmExponent; + if (m_lightShapeDelegate) + { + m_lightShapeDelegate->SetEsmExponent(esmExponent); + } + } + void AreaLightComponentController::CreateLightShapeDelegate() { switch (m_configuration.m_lightType) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index b5f342a522..a65f0be45f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -92,6 +92,8 @@ namespace AZ void SetFilteringSampleCount(uint32_t count) override; PcfMethod GetPcfMethod() const override; void SetPcfMethod(PcfMethod method) override; + float GetEsmExponent() const override; + void SetEsmExponent(float exponent) override; void HandleDisplayEntityViewport( const AzFramework::ViewportInfo& viewportInfo, diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index 8abc790ada..b8b82bc8bb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -175,5 +175,13 @@ namespace AZ::Render } } + void DiskLightDelegate::SetEsmExponent(float exponent) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), exponent); + } + } + } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index 5511b435d4..3e2704fd61 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -51,6 +51,7 @@ namespace AZ void SetPredictionSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override; void SetPcfMethod(PcfMethod method) override; + void SetEsmExponent(float exponent) override; private: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 69bec21a6c..9f6a427bf4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -179,8 +179,20 @@ namespace AZ ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary search") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled); - ; + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) + ->DataElement( + Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_esmExponent, "Esm Exponent", + "Exponent used by Esm shadows." + "Larger values increase the sharpness of the border between lit and unlit areas.") + ->Attribute(Edit::Attributes::Min, 50.0f) + ->Attribute(Edit::Attributes::Max, 5000.0f) + ->Attribute(AZ::Edit::Attributes::Decimals, 0) + ->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.05) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) + ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index da221341c3..d106a13c07 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -63,6 +63,7 @@ namespace AZ void SetPredictionSampleCount([[maybe_unused]] uint32_t count) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetPcfMethod([[maybe_unused]] PcfMethod method) override {}; + void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; protected: void InitBase(EntityId entityId); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index b3f5fb6014..7d6096d65f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -85,6 +85,8 @@ namespace AZ virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Pcf (Percentage closer filtering) method to use. virtual void SetPcfMethod(PcfMethod method) = 0; + //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. + virtual void SetEsmExponent(float exponent) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index afb63dce9b..e701e3c22a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -122,5 +122,14 @@ namespace AZ } } + void SphereLightDelegate::SetEsmExponent(float esmExponent) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); + } + } + + } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 178540fd01..f964254d76 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -41,6 +41,7 @@ namespace AZ void SetPredictionSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override; void SetPcfMethod(PcfMethod method) override; + void SetEsmExponent(float esmExponent) override; private: From f340189075b990fb925b5b83a00b29eb8ec469e4 Mon Sep 17 00:00:00 2001 From: mriegger Date: Thu, 10 Jun 2021 15:48:49 -0700 Subject: [PATCH 02/18] remove tabs --- .../Feature/CoreLights/DiskLightFeatureProcessorInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f777cbbc27..fc261fb57b 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 @@ -101,7 +101,7 @@ namespace AZ //! Sets the shadowmap Pcf (percentage closer filtering) method. virtual void SetPcfMethod(LightHandle handle, PcfMethod method) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. - virtual void SetEsmExponent(LightHandle handle, float exponent) = 0; + virtual void SetEsmExponent(LightHandle handle, float exponent) = 0; //! Sets all of the the disk data for the provided LightHandle. virtual void SetDiskData(LightHandle handle, const DiskLightData& data) = 0; From 86223703e4730d74dad1169c6bc739607ba1eac8 Mon Sep 17 00:00:00 2001 From: mriegger Date: Thu, 10 Jun 2021 16:15:44 -0700 Subject: [PATCH 03/18] removing tabs --- .../Code/Source/CoreLights/LightDelegateInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 7d6096d65f..3ebf3802fa 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -85,7 +85,7 @@ namespace AZ virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Pcf (Percentage closer filtering) method to use. virtual void SetPcfMethod(PcfMethod method) = 0; - //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. + //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. virtual void SetEsmExponent(float exponent) = 0; }; } // namespace Render From 4ac846383aa7253a93638557a093586b822405ac Mon Sep 17 00:00:00 2001 From: mriegger Date: Thu, 10 Jun 2021 19:02:08 -0700 Subject: [PATCH 04/18] Fixes from feedback --- .../Assets/Shaders/Shadow/DepthExponentiation.azsl | 4 +--- .../Source/Shadows/ProjectedShadowFeatureProcessor.cpp | 2 ++ .../Code/Source/CoreLights/EditorAreaLightComponent.cpp | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl index c212718bf5..1954605656 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Shadow/DepthExponentiation.azsl @@ -56,7 +56,6 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) return; // Early return if filter is disabled. } - float depth = 0.; switch (o_shadowmapLightType) { case ShadowmapLightType::Directional: @@ -68,7 +67,7 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) // and it often causes light bleeding with ESM. // So this converts it to "depth" to emphasize the difference // within the frustum. - depth = (depthInClip - distanceMin) / (1. - distanceMin); + const float depth = (depthInClip - distanceMin) / (1. - distanceMin); // Todo: Expose Esm exponent slider for directional lights // This would remove the exp calculation below, collapsing it into a subtraction in DirectionalLightShadow.azsli @@ -76,7 +75,6 @@ void MainCS(uint3 dispatchId: SV_DispatchThreadID) const float outValue = exp(EsmExponentialShift * depth); PassSrg::m_outputShadowmap[dispatchId].r = outValue; break; - } case ShadowmapLightType::Spot: { diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 98b2fb9574..ac723508c0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -162,6 +162,7 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::SetPcfMethod(ShadowId id, PcfMethod method) { + AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetPcfMethod()."); ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); shadowData.m_pcfMethod = method; @@ -170,6 +171,7 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent) { + AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetEsmExponent()."); ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); shadowData.m_esmExponent = exponent; m_deviceBufferNeedsUpdate = true; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 9f6a427bf4..184f64849f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -180,15 +180,14 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) - ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) - ->DataElement( + ->DataElement( Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_esmExponent, "Esm Exponent", - "Exponent used by Esm shadows." - "Larger values increase the sharpness of the border between lit and unlit areas.") + "Exponent used by Esm shadows. " + "Larger values increase the sharpness of the border between lit and unlit areas.") ->Attribute(Edit::Attributes::Min, 50.0f) ->Attribute(Edit::Attributes::Max, 5000.0f) ->Attribute(AZ::Edit::Attributes::Decimals, 0) - ->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.05) + ->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.05f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) From c158ca178fb780497d446513ca8a4a97f10f32a8 Mon Sep 17 00:00:00 2001 From: Chris Santora Date: Tue, 15 Jun 2021 19:26:11 -0700 Subject: [PATCH 05/18] Added new shader reinitialization signaling. This was done while working on "ATOM-15728 Shader Hot Reload Fails in Debug Build", but it turned out these changes did not actually fix the issue (or any other known hot-reload issue). Still, these improvements are appropriate as they correct logical oversights. ShaderVariant was not listening to asset reloads. It needs to know when the ShaderVariantAsset reload happens so it can reinitialize it's members as well as propagate reinitialization messages. I added a member for the ShaderAsset as the class needs this to reinitialize itself. So now the class listens for reloads of both the ShaderVariantAsset and the ShaderAsset. Shader was not listening for ShaderAsset reinitialization events. Updated the API for ShaderReloadNotificationBus's OnShaderVariantReinitialized to include the ShaderVariant which is the most relevant information (the other information wasn't really being used anyway). --- .../LightCullingTilePreparePass.cpp | 4 +- .../CoreLights/LightCullingTilePreparePass.h | 2 +- .../MorphTargets/MorphTargetDispatchItem.cpp | 4 +- .../MorphTargets/MorphTargetDispatchItem.h | 4 +- .../Code/Source/RayTracing/RayTracingPass.cpp | 4 +- .../Code/Source/RayTracing/RayTracingPass.h | 2 +- .../SkinnedMesh/SkinnedMeshComputePass.cpp | 8 +++- .../SkinnedMesh/SkinnedMeshComputePass.h | 2 +- .../Atom/RPI.Public/Material/Material.h | 2 +- .../Atom/RPI.Public/Pass/ComputePass.h | 2 +- .../RPI.Public/Pass/FullscreenTrianglePass.h | 2 +- .../Include/Atom/RPI.Public/PipelineState.h | 2 +- .../Shader/ShaderReloadNotificationBus.h | 9 ++-- .../Atom/RPI.Public/Shader/ShaderVariant.h | 15 ++++++- .../Source/RPI.Public/Material/Material.cpp | 4 +- .../Source/RPI.Public/Pass/ComputePass.cpp | 3 +- .../Pass/FullscreenTrianglePass.cpp | 2 +- .../Code/Source/RPI.Public/PipelineState.cpp | 7 +-- .../Code/Source/RPI.Public/Shader/Shader.cpp | 30 ++++++++----- .../RPI.Public/Shader/ShaderVariant.cpp | 45 ++++++++++++++++--- 20 files changed, 103 insertions(+), 50 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp index 4f2a4f0346..7742036171 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.cpp @@ -192,9 +192,7 @@ namespace AZ OnShaderReloaded(); } - void LightCullingTilePreparePass::OnShaderVariantReinitialized( - const AZ::RPI::Shader&, const AZ::RPI::ShaderVariantId&, - AZ::RPI::ShaderVariantStableId) + void LightCullingTilePreparePass::OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant&) { OnShaderReloaded(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h index 0febb66e3d..674f5d9914 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/LightCullingTilePreparePass.h @@ -56,7 +56,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const AZ::RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const AZ::RPI::Shader& shader, const AZ::RPI::ShaderVariantId& shaderVariantId, AZ::RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const AZ::RPI::ShaderVariant& shaderVariant) override; // Scope producer functions... void CompileResources(const RHI::FrameGraphCompileContext& context) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp index 7b3aedd64e..55a6d5d87a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.cpp @@ -199,7 +199,7 @@ namespace AZ } } - void MorphTargetDispatchItem::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) + void MorphTargetDispatchItem::OnShaderAssetReinitialized([[maybe_unused]] const Data::Asset& shaderAsset) { if (!Init()) { @@ -207,7 +207,7 @@ namespace AZ } } - void MorphTargetDispatchItem::OnShaderVariantReinitialized([[maybe_unused]] const RPI::Shader& shader, [[maybe_unused]] const RPI::ShaderVariantId& shaderVariantId, [[maybe_unused]] RPI::ShaderVariantStableId shaderVariantStableId) + void MorphTargetDispatchItem::OnShaderVariantReinitialized(const RPI::ShaderVariant&) { if (!Init()) { diff --git a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h index ad1fd969a5..e7d78caf5f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h +++ b/Gems/Atom/Feature/Common/Code/Source/MorphTargets/MorphTargetDispatchItem.h @@ -72,8 +72,8 @@ namespace AZ // ShaderInstanceNotificationBus::Handler overrides void OnShaderReinitialized(const RPI::Shader& shader) override; - void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; RHI::DispatchItem m_dispatchItem; diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp index 988870cc0e..6e11ba838b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.cpp @@ -354,9 +354,9 @@ namespace AZ Init(); } - void RayTracingPass::OnShaderVariantReinitialized([[maybe_unused]] const RPI::Shader& shader, [[maybe_unused]] const RPI::ShaderVariantId& shaderVariantId, [[maybe_unused]] RPI::ShaderVariantStableId shaderVariantStableId) + void RayTracingPass::OnShaderVariantReinitialized(const RPI::ShaderVariant&) { Init(); } - } // namespace RPI + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h index 6ad082e894..92da052d09 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingPass.h @@ -53,7 +53,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides void OnShaderReinitialized(const RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; // load the raytracing shaders and setup pipeline states void Init(); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp index a3feddb0b6..b0d08314b1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.cpp @@ -65,9 +65,13 @@ namespace AZ } } - void SkinnedMeshComputePass::OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId&, RPI::ShaderVariantStableId) + void SkinnedMeshComputePass::OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) { - OnShaderReinitialized(shader); + ComputePass::OnShaderVariantReinitialized(shaderVariant); + if (m_skinnedMeshFeatureProcessor) + { + m_skinnedMeshFeatureProcessor->OnSkinningShaderReinitialized(m_shader); + } } } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h index 5f7ff08e47..dbd8704c54 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshComputePass.h @@ -44,7 +44,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides... void OnShaderReinitialized(const RPI::Shader& shader) override; - void OnShaderVariantReinitialized(const RPI::Shader& shader, const RPI::ShaderVariantId& shaderVariantId, RPI::ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const RPI::ShaderVariant& shaderVariant) override; SkinnedMeshFeatureProcessor* m_skinnedMeshFeatureProcessor = nullptr; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h index d93f7acc85..fa1bb57166 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h @@ -145,7 +145,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// template diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h index a4130deed1..450a9ce834 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ComputePass.h @@ -78,7 +78,7 @@ namespace AZ // ShaderReloadNotificationBus::Handler overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; void LoadShader(); PassDescriptor m_passDescriptor; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h index 616fc4639a..e168a07f08 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/FullscreenTrianglePass.h @@ -78,7 +78,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// void LoadShader(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h index f0fa39d20f..815fc28cb6 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/PipelineState.h @@ -88,7 +88,7 @@ namespace AZ // ShaderReloadNotificationBus overrides... void OnShaderReinitialized(const AZ::RPI::Shader& shader) override; void OnShaderAssetReinitialized(const Data::Asset& shaderAsset) override; - void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) override; + void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) override; /////////////////////////////////////////////////////////////////// // Update shader variant from m_shader. It's called whenever shader, shader asset or shader variant were changed. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h index 58b9809e2b..c63ba8f5b5 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadNotificationBus.h @@ -22,10 +22,11 @@ namespace AZ { class Shader; class ShaderAsset; + class ShaderVariant; /** - * Connect to this EBus to get notifications whenever a Data::Instance reloads its ShaderAsset. - * The bus address is the AssetId of the ShaderAsset. + * Connect to this EBus to get notifications whenever a shader system class reinitializes itself. + * The bus address is the AssetId of the ShaderAsset, even when the thing being reinitialized is a ShaderVariant or other shader related class. */ class ShaderReloadNotifications : public EBusTraits @@ -35,7 +36,7 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById; - typedef Data::AssetId BusIdType; + typedef Data::AssetId BusIdType; ////////////////////////////////////////////////////////////////////////// virtual ~ShaderReloadNotifications() {} @@ -47,7 +48,7 @@ namespace AZ virtual void OnShaderReinitialized(const Shader& shader) { AZ_UNUSED(shader); } //! Called when a particular shader variant is reinitialized. - virtual void OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) { AZ_UNUSED(shader); AZ_UNUSED(shaderVariantId); AZ_UNUSED(shaderVariantStableId); } + virtual void OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { AZ_UNUSED(shaderVariant); } }; typedef EBus ShaderReloadNotificationBus; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h index d189d26b13..7363ab4d1a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariant.h @@ -23,10 +23,12 @@ namespace AZ //! the RHI::PipelineStateType of the parent Shader instance. For shaders on the raster //! pipeline, the RHI::DrawFilterTag is also provided. class ShaderVariant final + : public Data::AssetBus::MultiHandler { friend class Shader; public: ShaderVariant() = default; + virtual ~ShaderVariant(); AZ_DEFAULT_COPY_MOVE(ShaderVariant); //! Fills a pipeline state descriptor with settings provided by the ShaderVariant. (Note that @@ -54,12 +56,21 @@ namespace AZ bool IsRootVariant() const { return m_shaderVariantAsset->IsRootVariant(); } ShaderVariantStableId GetStableId() const { return m_shaderVariantAsset->GetStableId(); } + + const Data::Asset& GetShaderAsset() const { return m_shaderAsset; } + const Data::Asset& GetShaderVariantAsset() const { return m_shaderVariantAsset; } private: // Called by Shader. Initializes runtime data from asset data. Returns whether the call succeeded. bool Init( - const ShaderAsset& shaderAsset, - Data::Asset shaderVariantAsset); + const Data::Asset& shaderAsset, + const Data::Asset& shaderVariantAsset); + + // AssetBus overrides... + void OnAssetReloaded(Data::Asset asset) override; + + //! A reference to the shader asset that this is a variant of. + Data::Asset m_shaderAsset; // Cached state from the asset to avoid an indirection. RHI::PipelineStateType m_pipelineStateType = RHI::PipelineStateType::Count; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp index d9691ca175..e134b701ac 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp @@ -268,9 +268,9 @@ namespace AZ OnAssetReloaded(m_materialAsset); } - void Material::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& /*shaderVariantId*/, ShaderVariantStableId shaderVariantStableId) + void Material::OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { - ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s variant %u", this, shader.GetAsset().GetHint().c_str(), shaderVariantStableId.GetIndex()); + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->Material::OnShaderVariantReinitialized %s", this, shaderVariant.GetShaderVariantAsset().GetHint().c_str()); // Note that it would be better to check the shaderVariantId to see if that variant is relevant to this particular material before reinitializing it. // There could be hundreds or even thousands of variants for a shader, but only one of those variants will be used by any given material. So we could diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp index 5077ccaa51..5902c208c6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp @@ -241,9 +241,8 @@ namespace AZ LoadShader(); } - void ComputePass::OnShaderVariantReinitialized(const Shader& shader, const ShaderVariantId& shaderVariantId, ShaderVariantStableId shaderVariantStableId) + void ComputePass::OnShaderVariantReinitialized(const ShaderVariant&) { - AZ_UNUSED(shader); AZ_UNUSED(shaderVariantId); AZ_UNUSED(shaderVariantStableId); LoadShader(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index a854867998..aee4fc4f48 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -57,7 +57,7 @@ namespace AZ LoadShader(); } - void FullscreenTrianglePass::OnShaderVariantReinitialized(const Shader&, const ShaderVariantId&, ShaderVariantStableId) + void FullscreenTrianglePass::OnShaderVariantReinitialized(const ShaderVariant&) { LoadShader(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp index 545e71e117..8b13817897 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/PipelineState.cpp @@ -124,12 +124,9 @@ namespace AZ RefreshShaderVariant(); } - void PipelineStateForDraw::OnShaderVariantReinitialized( - [[maybe_unused]] const Shader& shader, - const ShaderVariantId& shaderVariantId, - [[maybe_unused]] ShaderVariantStableId shaderVariantStableId) + void PipelineStateForDraw::OnShaderVariantReinitialized(const ShaderVariant& shaderVariant) { - if(shaderVariantId == m_shaderVariantId) + if(shaderVariant.GetShaderVariantId() == m_shaderVariantId) { RefreshShaderVariant(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index 3a79f32b05..6f65bd75c9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -68,7 +68,7 @@ namespace AZ AZStd::unique_lock lock(m_variantCacheMutex); m_shaderVariants.clear(); } - m_rootVariant.Init(shaderAsset, shaderAsset.GetRootVariant()); + m_rootVariant.Init(Data::Asset{&shaderAsset, AZ::Data::AssetLoadBehavior::PreLoad}, shaderAsset.GetRootVariant()); if (m_pipelineLibraryHandle.IsNull()) { @@ -154,7 +154,14 @@ namespace AZ { AZ_Assert(shaderVariantAsset, "Reloaded ShaderVariantAsset is null"); const ShaderVariantStableId stableId = shaderVariantAsset->GetStableId(); - const ShaderVariantId& shaderVariantId = shaderVariantAsset->GetShaderVariantId(); + + // We make a copy of the updated variant because OnShaderVariantReinitialized must not be called inside + // m_variantCacheMutex or deadlocks may occur. + // Or if there is an error, we leave this object in its default state to indicate there was an error. + // [GFX TODO] We really should have a dedicated message/event for this, but that will be covered by a future task where + // we will merge ShaderReloadNotificationBus messages into one. For now, we just indicate the error by passing an empty ShaderVariant, + // all our call sites don't use this data anyway. + ShaderVariant updatedVariant; if (isError) { @@ -165,7 +172,7 @@ namespace AZ return; } AZStd::unique_lock lock(m_variantCacheMutex); - m_shaderVariants.erase(stableId); + m_shaderVariants.erase(stableId); } else { @@ -178,23 +185,26 @@ namespace AZ { ShaderVariant& shaderVariant = iter->second; - if (!shaderVariant.Init(*m_asset.Get(), shaderVariantAsset)) + if (!shaderVariant.Init(m_asset, shaderVariantAsset)) { AZ_Error("Shader", false, "Failed to init shaderVariant with StableId=%u", shaderVariantAsset->GetStableId()); m_shaderVariants.erase(stableId); } + else + { + updatedVariant = shaderVariant; + } } else { //This is the first time the shader variant asset comes to life. - ShaderVariant newVariant; - newVariant.Init(*m_asset, shaderVariantAsset); - m_shaderVariants.emplace(stableId, newVariant); + updatedVariant.Init(m_asset, shaderVariantAsset); + m_shaderVariants.emplace(stableId, updatedVariant); } } - //Even if there was an error, the interested parties should be notified. - ShaderReloadNotificationBus::Event(m_asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this, shaderVariantId, stableId); + // [GFX TODO] It might make more sense to call OnShaderReinitialized here + ShaderReloadNotificationBus::Event(m_asset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, updatedVariant); } /////////////////////////////////////////////////////////////////// @@ -340,7 +350,7 @@ namespace AZ } ShaderVariant newVariant; - newVariant.Init(*m_asset, shaderVariantAsset); + newVariant.Init(m_asset, shaderVariantAsset); m_shaderVariants.emplace(shaderVariantStableId, newVariant); return m_shaderVariants.at(shaderVariantStableId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp index 4d50f10c9c..acd9922b68 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariant.cpp @@ -9,11 +9,13 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ + #include +#include +#include #include #include - #include namespace AZ @@ -21,15 +23,26 @@ namespace AZ namespace RPI { bool ShaderVariant::Init( - const ShaderAsset& shaderAsset, - Data::Asset shaderVariantAsset) - { - m_pipelineStateType = shaderAsset.GetPipelineStateType(); - m_pipelineLayoutDescriptor = shaderAsset.GetPipelineLayoutDescriptor(); + const Data::Asset& shaderAsset, + const Data::Asset& shaderVariantAsset) + { + Data::AssetBus::MultiHandler::BusDisconnect(); + Data::AssetBus::MultiHandler::BusConnect(shaderAsset.GetId()); + Data::AssetBus::MultiHandler::BusConnect(shaderVariantAsset.GetId()); + + m_shaderAsset = shaderAsset; + m_pipelineStateType = shaderAsset->GetPipelineStateType(); + m_pipelineLayoutDescriptor = shaderAsset->GetPipelineLayoutDescriptor(); m_shaderVariantAsset = shaderVariantAsset; + return true; } + ShaderVariant::~ShaderVariant() + { + Data::AssetBus::MultiHandler::BusDisconnect(); + } + void ShaderVariant::ConfigurePipelineState(RHI::PipelineStateDescriptor& descriptor) const { descriptor.m_pipelineLayoutDescriptor = m_pipelineLayoutDescriptor; @@ -78,5 +91,25 @@ namespace AZ { return m_shaderVariantAsset->GetOutputContract(); } + + void ShaderVariant::OnAssetReloaded(Data::Asset asset) + { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->ShaderVariant::OnAssetReloaded %s", this, asset.GetHint().c_str()); + + if (asset.GetAs()) + { + Data::Asset shaderVariantAsset = { asset.GetAs(), AZ::Data::AssetLoadBehavior::PreLoad }; + Init(m_shaderAsset, shaderVariantAsset); + ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this); + } + + if (asset.GetAs()) + { + Data::Asset shaderAsset = { asset.GetAs(), AZ::Data::AssetLoadBehavior::PreLoad }; + Init(shaderAsset, m_shaderVariantAsset); + ShaderReloadNotificationBus::Event(m_shaderAsset.GetId(), &ShaderReloadNotificationBus::Events::OnShaderVariantReinitialized, *this); + } + } + } // namespace RPI } // namespace AZ From bcd008df20b7695540e6e758bc97685cf769be86 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 15 Jun 2021 21:22:45 -0700 Subject: [PATCH 06/18] Allowing network properties to generate event bindings while staying hidden from script by using a new ExposeToScript attribute. This was useful in hiding NetworkTransformComponent properties which needed event binding in order to update the normal transform, but remain hidden from scripters who should still be using the normal transform component --- .../Code/Source/AutoGen/AutoComponent_Source.jinja | 2 +- ...lPredictionPlayerInputComponent.AutoComponent.xml | 2 +- .../NetworkTransformComponent.AutoComponent.xml | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index 21bf6ab69b..92ad524711 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -826,7 +826,7 @@ enum class NetworkProperties #} {% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassName) %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %} -{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['GenerateEventBindings'] | booleanTrue == true) -%} +{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['ExposeToScript'] | booleanTrue == true) -%} // {{ UpperFirst(Property.attrib['Name']) }}: Replicate from {{ ReplicateFrom }} to {{ ReplicateTo }} {% if Property.attrib['Container'] == 'Vector' or Property.attrib['Container'] == 'Array' %} ->Method("Get{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id, int32_t index) -> {{ Property.attrib['Type'] }} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml index b6edd0e3be..0c799a7b3f 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml @@ -17,7 +17,7 @@ - + diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml index a112cde4e6..8abc874aa6 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkTransformComponent.AutoComponent.xml @@ -12,12 +12,12 @@ - - - - - - + + + + + +