Merge pull request #1302 from aws-lumberyard-dev/Atom/mriegger/esmexponent2106
Atom/mriegger/esmexponent2106
This commit is contained in:
+10
-6
@@ -226,7 +226,7 @@ float ProjectedShadow::GetVisibilityEsm()
|
||||
}
|
||||
|
||||
const float invAtlasSize = ViewSrg::m_invShadowmapAtlasSize;
|
||||
const Texture2DArray<float> expShadowmap = PassSrg::m_projectedExponentialShadowmap;
|
||||
const Texture2DArray<float> 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<float> expShadowmap = PassSrg::m_projectedExponentialShadowmap;
|
||||
const Texture2DArray<float> 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)
|
||||
|
||||
@@ -92,6 +92,8 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_filteringSampleCount;
|
||||
float2 m_unprojectConstants;
|
||||
float m_bias;
|
||||
float m_esmExponent;
|
||||
float3 m_padding;
|
||||
};
|
||||
|
||||
StructuredBuffer<ProjectedShadow> m_projectedShadows;
|
||||
|
||||
@@ -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,9 +67,15 @@ 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
|
||||
// ATOM-15775
|
||||
const float outValue = exp(EsmExponentialShift * depth);
|
||||
PassSrg::m_outputShadowmap[dispatchId].r = outValue;
|
||||
break;
|
||||
}
|
||||
case ShadowmapLightType::Spot:
|
||||
{
|
||||
const float3 coefficients = float3(
|
||||
@@ -84,12 +89,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;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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
|
||||
|
||||
+2
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<RPI::Buffer> GetLightBuffer() const;
|
||||
|
||||
@@ -162,12 +162,21 @@ 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<ShadowDataIndex>(id.GetIndex());
|
||||
shadowData.m_pcfMethod = method;
|
||||
|
||||
m_deviceBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetEsmExponent().");
|
||||
ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(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().");
|
||||
|
||||
@@ -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<float, 2> m_unprojectConstants = { {0, 0} };
|
||||
float m_bias;
|
||||
float m_esmExponent = 87.0f;
|
||||
float m_padding[3];
|
||||
};
|
||||
|
||||
// CPU data used for constructing & updating ShadowData
|
||||
|
||||
+7
@@ -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.
|
||||
|
||||
+3
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+9
-2
@@ -21,7 +21,7 @@ namespace AZ
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AreaLightComponentConfig, ComponentConfig>()
|
||||
->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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+21
-3
@@ -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)
|
||||
|
||||
+2
@@ -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,
|
||||
|
||||
@@ -175,5 +175,13 @@ namespace AZ::Render
|
||||
}
|
||||
}
|
||||
|
||||
void DiskLightDelegate::SetEsmExponent(float exponent)
|
||||
{
|
||||
if (GetShadowsEnabled() && GetLightHandle().IsValid())
|
||||
{
|
||||
GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), exponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace AZ::Render
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
+13
-2
@@ -179,8 +179,19 @@ 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)
|
||||
->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.05f)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
|
||||
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -122,5 +122,14 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
void SphereLightDelegate::SetEsmExponent(float esmExponent)
|
||||
{
|
||||
if (GetShadowsEnabled() && GetLightHandle().IsValid())
|
||||
{
|
||||
GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user