Atom/mriegger/normaloffsetbiasarealight (#4917)

* Adding directional light shadow bias
* Adding normal offset bias for projected shadows

Signed-off-by: mrieggeramzn <mriegger@amazon.com>
monroegm-disable-blank-issue-2
mrieggeramzn 4 years ago committed by GitHub
parent d468cbad85
commit dd1d515e37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,7 @@
#include <Atom/RPI/Math.azsli> #include <Atom/RPI/Math.azsli>
#include "BicubicPcfFilters.azsli" #include "BicubicPcfFilters.azsli"
#include "Shadow.azsli" #include "Shadow.azsli"
#include "NormalOffsetShadows.azsli"
// ProjectedShadow calculates shadowed area projected from a light. // ProjectedShadow calculates shadowed area projected from a light.
class ProjectedShadow class ProjectedShadow
@ -123,6 +124,7 @@ float ProjectedShadow::GetThickness(uint shadowIndex, float3 worldPosition)
ProjectedShadow shadow; ProjectedShadow shadow;
shadow.m_worldPosition = worldPosition; shadow.m_worldPosition = worldPosition;
shadow.m_normalVector = 0; // The normal vector is used to reduce acne, this is not an issue when using the shadowmap to determine thickness.
shadow.m_shadowIndex = shadowIndex; shadow.m_shadowIndex = shadowIndex;
shadow.SetShadowPosition(); shadow.SetShadowPosition();
return shadow.GetThickness(); return shadow.GetThickness();
@ -317,8 +319,13 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition)
void ProjectedShadow::SetShadowPosition() void ProjectedShadow::SetShadowPosition()
{ {
const float normalBias = ViewSrg::m_projectedShadows[m_shadowIndex].m_normalShadowBias;
const float shadowmapSize = ViewSrg::m_projectedFilterParams[m_shadowIndex].m_shadowmapSize;
const float3 shadowOffset = ComputeNormalShadowOffset(normalBias, m_normalVector, shadowmapSize);
const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix; const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix;
float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition, 1));
float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition + shadowOffset, 1));
m_shadowPosition = shadowPositionHomogeneous.xyz / shadowPositionHomogeneous.w; m_shadowPosition = shadowPositionHomogeneous.xyz / shadowPositionHomogeneous.w;
m_bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias / shadowPositionHomogeneous.w; m_bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias / shadowPositionHomogeneous.w;

@ -86,6 +86,8 @@ namespace AZ
virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0;
//! Sets the shadow bias //! Sets the shadow bias
virtual void SetShadowBias(LightHandle handle, float bias) = 0; virtual void SetShadowBias(LightHandle handle, float bias) = 0;
//! Sets the normal shadow bias
virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0;
//! Sets the shadowmap size (width and height) of the light. //! Sets the shadowmap size (width and height) of the light.
virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0;
//! Specifies filter method of shadows. //! Specifies filter method of shadows.

@ -74,6 +74,8 @@ namespace AZ
virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0;
//! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. //! 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 the normal shadow bias. Reduces acne by biasing the shadowmap lookup along the geometric normal.
virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0;
//! Sets all of the the point data for the provided LightHandle. //! Sets all of the the point data for the provided LightHandle.
virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0;
}; };

@ -313,6 +313,11 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias); SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias);
} }
void DiskLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias);
}
void DiskLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) void DiskLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize)
{ {
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize); SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize);

@ -51,6 +51,7 @@ namespace AZ
void SetConeAngles(LightHandle handle, float innerDegrees, float outerDegrees) override; void SetConeAngles(LightHandle handle, float innerDegrees, float outerDegrees) override;
void SetShadowsEnabled(LightHandle handle, bool enabled) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override;
void SetShadowBias(LightHandle handle, float bias) override; void SetShadowBias(LightHandle handle, float bias) override;
void SetNormalShadowBias(LightHandle handle, float bias) override;
void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override;
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;

@ -302,5 +302,10 @@ namespace AZ
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent); SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent);
} }
void PointLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias)
{
SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias);
}
} // namespace Render } // namespace Render
} // namespace AZ } // namespace AZ

@ -52,6 +52,7 @@ namespace AZ
void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override;
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
void SetEsmExponent(LightHandle handle, float esmExponent) override; void SetEsmExponent(LightHandle handle, float esmExponent) override;
void SetNormalShadowBias(LightHandle handle, float bias) override;
void SetPointData(LightHandle handle, const PointLightData& data) override; void SetPointData(LightHandle handle, const PointLightData& data) override;
const Data::Instance<RPI::Buffer> GetLightBuffer() const; const Data::Instance<RPI::Buffer> GetLightBuffer() const;

@ -155,8 +155,9 @@ namespace AZ::Render
{ {
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias()."); AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias().");
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id); ShadowData& shadowData = m_shadowData.GetElement<ShadowDataIndex>(id.GetIndex());
shadowProperty.m_normalShadowBias = normalShadowBias; shadowData.m_normalShadowBias = normalShadowBias;
m_deviceBufferNeedsUpdate = true;
} }
void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size)

@ -68,7 +68,7 @@ namespace AZ::Render
uint32_t m_filteringSampleCount = 0; uint32_t m_filteringSampleCount = 0;
AZStd::array<float, 2> m_unprojectConstants = { {0, 0} }; AZStd::array<float, 2> m_unprojectConstants = { {0, 0} };
float m_bias; float m_bias;
float m_normalShadowBias; float m_normalShadowBias = 0;
float m_esmExponent = 87.0f; float m_esmExponent = 87.0f;
float m_padding[3]; float m_padding[3];
}; };
@ -79,7 +79,6 @@ namespace AZ::Render
ProjectedShadowDescriptor m_desc; ProjectedShadowDescriptor m_desc;
RPI::ViewPtr m_shadowmapView; RPI::ViewPtr m_shadowmapView;
float m_bias = 0.1f; float m_bias = 0.1f;
float m_normalShadowBias = 0.0f;
ShadowId m_shadowId; ShadowId m_shadowId;
}; };

@ -132,6 +132,13 @@ namespace AZ
//! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow. //! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow.
virtual void SetEsmExponent(float exponent) = 0; virtual void SetEsmExponent(float exponent) = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @return Returns the amount of bias to apply.
virtual float GetNormalShadowBias() const = 0;
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
}; };
//! The EBus for requests to for setting and getting light component properties. //! The EBus for requests to for setting and getting light component properties.

@ -57,6 +57,7 @@ namespace AZ
// Shadows (only used for supported shapes) // Shadows (only used for supported shapes)
bool m_enableShadow = false; bool m_enableShadow = false;
float m_bias = 0.1f; float m_bias = 0.1f;
float m_normalShadowBias = 0.0f;
ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256; ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
uint16_t m_filteringSampleCount = 12; uint16_t m_filteringSampleCount = 12;

@ -34,6 +34,7 @@ namespace AZ
// Shadows // Shadows
->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow) ->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow)
->Field("Shadow Bias", &AreaLightComponentConfig::m_bias) ->Field("Shadow Bias", &AreaLightComponentConfig::m_bias)
->Field("Normal Shadow Bias", &AreaLightComponentConfig::m_normalShadowBias)
->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize) ->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize)
->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod) ->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod)
->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount)

@ -70,6 +70,8 @@ namespace AZ::Render
->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow) ->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow)
->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias) ->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias)
->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias) ->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias)
->Event("GetNormalShadowBias", &AreaLightRequestBus::Events::GetNormalShadowBias)
->Event("SetNormalShadowBias", &AreaLightRequestBus::Events::SetNormalShadowBias)
->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize) ->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize)
->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize) ->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize)
->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod) ->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod)
@ -91,6 +93,7 @@ namespace AZ::Render
->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow") ->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow")
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias") ->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias")
->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize") ->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize")
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
@ -302,6 +305,7 @@ namespace AZ::Render
if (m_configuration.m_enableShadow) if (m_configuration.m_enableShadow)
{ {
m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias); m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias);
m_lightShapeDelegate->SetNormalShadowBias(m_configuration.m_normalShadowBias);
m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize); m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize);
m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
@ -474,6 +478,20 @@ namespace AZ::Render
} }
} }
void AreaLightComponentController::SetNormalShadowBias(float bias)
{
m_configuration.m_normalShadowBias = bias;
if (m_lightShapeDelegate)
{
m_lightShapeDelegate->SetNormalShadowBias(bias);
}
}
float AreaLightComponentController::GetNormalShadowBias() const
{
return m_configuration.m_normalShadowBias;
}
ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const
{ {
return m_configuration.m_shadowmapMaxSize; return m_configuration.m_shadowmapMaxSize;

@ -86,6 +86,8 @@ namespace AZ
void SetFilteringSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override;
float GetEsmExponent() const override; float GetEsmExponent() const override;
void SetEsmExponent(float exponent) override; void SetEsmExponent(float exponent) override;
float GetNormalShadowBias() const override;
void SetNormalShadowBias(float bias) override;
void HandleDisplayEntityViewport( void HandleDisplayEntityViewport(
const AzFramework::ViewportInfo& viewportInfo, const AzFramework::ViewportInfo& viewportInfo,

@ -138,6 +138,14 @@ namespace AZ::Render
} }
} }
void DiskLightDelegate::SetNormalShadowBias(float bias)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias);
}
}
void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size)
{ {
if (GetShadowsEnabled() && GetLightHandle().IsValid()) if (GetShadowsEnabled() && GetLightHandle().IsValid())

@ -46,6 +46,7 @@ namespace AZ
void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetFilteringSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float exponent) override; void SetEsmExponent(float exponent) override;
void SetNormalShadowBias(float bias) override;
private: private:

@ -136,7 +136,7 @@ namespace AZ
->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Min, 0.0f)
->Attribute(Edit::Attributes::Max, 100.0f) ->Attribute(Edit::Attributes::Max, 100.0f)
->Attribute(Edit::Attributes::SoftMin, 0.0f) ->Attribute(Edit::Attributes::SoftMin, 0.0f)
->Attribute(Edit::Attributes::SoftMax, 2.0f) ->Attribute(Edit::Attributes::SoftMax, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
@ -171,7 +171,16 @@ namespace AZ
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled)
; ->DataElement(
Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n",
"Reduces acne by biasing the shadowmap lookup along the geometric normal.\n"
"If this is 0, no biasing is applied.")
->Attribute(Edit::Attributes::Min, 0.f)
->Attribute(Edit::Attributes::Max, 10.0f)
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
;
} }
} }

@ -58,7 +58,8 @@ namespace AZ
void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {}; void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {};
void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {};
void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; void SetEsmExponent([[maybe_unused]] float esmExponent) override{};
void SetNormalShadowBias([[maybe_unused]] float bias) override{};
protected: protected:
void InitBase(EntityId entityId); void InitBase(EntityId entityId);

@ -79,6 +79,8 @@ namespace AZ
virtual void SetFilteringSampleCount(uint32_t count) = 0; virtual void SetFilteringSampleCount(uint32_t count) = 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; virtual void SetEsmExponent(float exponent) = 0;
//! Sets the normal bias. Reduces acne by biasing the shadowmap lookup along the geometric normal.
virtual void SetNormalShadowBias(float bias) = 0;
}; };
} // namespace Render } // namespace Render
} // namespace AZ } // namespace AZ

@ -107,4 +107,13 @@ namespace AZ::Render
GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent);
} }
} }
void SphereLightDelegate::SetNormalShadowBias(float bias)
{
if (GetShadowsEnabled() && GetLightHandle().IsValid())
{
GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias);
}
}
} // namespace AZ::Render } // namespace AZ::Render

@ -36,6 +36,7 @@ namespace AZ
void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetShadowFilterMethod(ShadowFilterMethod method) override;
void SetFilteringSampleCount(uint32_t count) override; void SetFilteringSampleCount(uint32_t count) override;
void SetEsmExponent(float esmExponent) override; void SetEsmExponent(float esmExponent) override;
void SetNormalShadowBias(float bias) override;
private: private:

Loading…
Cancel
Save