Exposing esm exponent

main
mriegger 5 years ago
parent 4818d1ce80
commit 959ec14df6

@ -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;

@ -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;
}

@ -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

@ -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;

@ -168,6 +168,13 @@ namespace AZ::Render
m_deviceBufferNeedsUpdate = true;
}
void ProjectedShadowFeatureProcessor::SetEsmExponent(ShadowId id, float exponent)
{
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

@ -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.

@ -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;
};
}
}

@ -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);
}
}
}

@ -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)

@ -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:

@ -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)
;
}
}

@ -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:

Loading…
Cancel
Save