Atom/mriegger/normaloffsetbias (#4841)
* Adding directional light shadow bias Signed-off-by: mrieggeramzn <mriegger@amazon.com> * Adding normal offset bias to the directional shadow maps Signed-off-by: mrieggeramzn <mriegger@amazon.com> * not time yet for this Signed-off-by: mrieggeramzn <mriegger@amazon.com> * small comment fix Signed-off-by: mrieggeramzn <mriegger@amazon.com> * fixing tabs Signed-off-by: mrieggeramzn <mriegger@amazon.com>
This commit is contained in:
@@ -54,6 +54,7 @@ VSOutput ShadowCatcherVS(VSInput IN)
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
ViewSrg::m_shadowIndexDirectionalLight,
|
||||
worldPosition,
|
||||
OUT.m_worldNormal,
|
||||
OUT.m_shadowCoords);
|
||||
|
||||
return OUT;
|
||||
|
||||
@@ -112,13 +112,15 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
|
||||
// ------- Tangents & Bitangets -------
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
|
||||
|
||||
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering) || o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture) || o_detail_normal_useTexture)
|
||||
{
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
PrepareGeneratedTangent(vertexNormal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
}
|
||||
|
||||
// ------- Depth & Parallax -------
|
||||
@@ -137,7 +139,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_heightmapScale, MaterialSrg::m_heightmapOffset,
|
||||
GetParallaxInput(vertexNormal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_heightmapScale, MaterialSrg::m_heightmapOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth, IN.m_position.w, displacementIsClipped);
|
||||
|
||||
@@ -150,7 +152,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +187,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
|
||||
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
|
||||
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = GetDetailedNormalInputWS(
|
||||
isFrontFace, IN.m_normal,
|
||||
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_normalFactor, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, uvMatrix, o_normal_useTexture,
|
||||
|
||||
+4
-3
@@ -302,6 +302,7 @@ ProcessedMaterialInputs ProcessStandardMaterialInputs(StandardMaterialInputs inp
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
depthNDC = IN.m_position.z;
|
||||
|
||||
s_blendMaskFromVertexStream = IN.m_blendMask;
|
||||
@@ -321,7 +322,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|| o_layer3_o_clearCoat_normal_useTexture
|
||||
)
|
||||
{
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
PrepareGeneratedTangent(vertexNormal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
}
|
||||
|
||||
// ------- Debug Modes -------
|
||||
@@ -368,7 +369,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,7 +446,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS);
|
||||
}
|
||||
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
|
||||
|
||||
// ------- Combine Albedo, roughness, specular, roughness ---------
|
||||
|
||||
@@ -98,6 +98,8 @@ VSOutput StandardPbr_ForwardPassVS(VSInput IN)
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
|
||||
// ------- Tangents & Bitangets -------
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
|
||||
@@ -128,7 +130,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +148,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
|
||||
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal,
|
||||
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], uvMatrix, o_normal_useTexture, MaterialSrg::m_normalFactor);
|
||||
|
||||
|
||||
+12
-6
@@ -14,6 +14,7 @@
|
||||
#include "ShadowmapAtlasLib.azsli"
|
||||
#include "BicubicPcfFilters.azsli"
|
||||
#include "ReceiverPlaneDepthBias.azsli"
|
||||
#include "NormalOffsetShadows.azsli"
|
||||
|
||||
// Before including this azsli file, a PassSrg must be defined with the following members:
|
||||
// Texture2DArray<float> m_directionalLightShadowmap;
|
||||
@@ -45,6 +46,7 @@ class DirectionalLightShadow
|
||||
static void GetShadowCoords(
|
||||
uint lightIndex,
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
out float3 shadowCoords[ViewSrg::MaxCascadeCount]);
|
||||
|
||||
//! This calculates visibility ratio of the surface from the light origin.
|
||||
@@ -109,18 +111,22 @@ class DirectionalLightShadow
|
||||
void DirectionalLightShadow::GetShadowCoords(
|
||||
uint lightIndex,
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
out float3 shadowCoords[ViewSrg::MaxCascadeCount])
|
||||
{
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
|
||||
const float shadowBias = ViewSrg::m_directionalLightShadows[lightIndex].m_shadowBias;
|
||||
|
||||
const float4x4 lightViewToShadowmapMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_lightViewToShadowmapMatrices;
|
||||
const float4x4 worldToLightViewMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_worldToLightViewMatrices;
|
||||
|
||||
for (uint index = 0; index < cascadeCount; ++index)
|
||||
{
|
||||
float4 lightSpacePos = mul(worldToLightViewMatrices[index], float4(worldPosition, 1.));
|
||||
lightSpacePos.z += shadowBias;
|
||||
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
|
||||
const float3 shadowOffset = ComputeNormalShadowOffset(ViewSrg::m_directionalLightShadows[lightIndex].m_normalShadowBias, worldNormal, ViewSrg::m_directionalLightShadows[lightIndex].m_shadowmapSize);
|
||||
|
||||
for (uint index = 0; index < cascadeCount; ++index)
|
||||
{
|
||||
float4 lightSpacePos = mul(worldToLightViewMatrices[index], float4(worldPosition + shadowOffset, 1.));
|
||||
lightSpacePos.z += shadowBias;
|
||||
|
||||
const float4 clipSpacePos = mul(lightViewToShadowmapMatrices[index], lightSpacePos);
|
||||
shadowCoords[index] = clipSpacePos.xyz / clipSpacePos.w;
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Helper functions for normal offset shadow mapping.
|
||||
// Normal Offset is an alternative to slope-scale depth bias.
|
||||
// We bias the shadow map lookup by transforming the world-position along the geometric normal before hand.
|
||||
// http://web.archive.org/web/20140810230446/https://www.dissidentlogic.com/old/#Normal%20Offset%20Shadows
|
||||
//
|
||||
|
||||
// Apply the following to the world position. Then use this modified world position to look up in the shadow map
|
||||
float3 ComputeNormalShadowOffset(const float normalOffsetBias, const float3 worldNormal, const float shadowMapDimension)
|
||||
{
|
||||
const float shadowmapSize = 2.0f / shadowMapDimension;
|
||||
return float3(worldNormal * normalOffsetBias * shadowmapSize);
|
||||
}
|
||||
@@ -47,6 +47,7 @@ void VertexHelper(in VSInput IN, inout VSOutput OUT, float3 worldPosition, bool
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
shadowIndex,
|
||||
worldPosition,
|
||||
OUT.m_normal,
|
||||
OUT.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +81,10 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_shadowmapArraySlice; // array slice who has shadowmap in the atlas.
|
||||
uint m_shadowFilterMethod;
|
||||
float m_boundaryScale;
|
||||
uint m_predictionSampleCount;
|
||||
uint m_filteringSampleCount;
|
||||
float2 m_unprojectConstants;
|
||||
float m_bias;
|
||||
float m_normalShadowBias;
|
||||
float m_esmExponent;
|
||||
float3 m_padding;
|
||||
};
|
||||
@@ -109,7 +109,7 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_shadowmapSize; // width and height of shadowmap
|
||||
uint m_cascadeCount;
|
||||
float m_shadowBias;
|
||||
uint m_predictionSampleCount;
|
||||
float m_normalShadowBias;
|
||||
uint m_filteringSampleCount;
|
||||
uint m_debugFlags;
|
||||
uint m_shadowFilterMethod;
|
||||
|
||||
+3
@@ -160,6 +160,9 @@ namespace AZ
|
||||
|
||||
//! Reduces acne by applying a small amount of bias along shadow-space z.
|
||||
virtual void SetShadowBias(LightHandle handle, float bias) = 0;
|
||||
|
||||
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
virtual void SetNormalShadowBias(LightHandle handle, float normalShadowBias) = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+5
-3
@@ -48,11 +48,13 @@ namespace AZ::Render
|
||||
virtual void SetAspectRatio(ShadowId id, float aspectRatio) = 0;
|
||||
//! Sets the field of view for the shadow in radians in the Y direction.
|
||||
virtual void SetFieldOfViewY(ShadowId id, float fieldOfView) = 0;
|
||||
//! Sets the maximum resolution of the shadow map
|
||||
//! Sets the maximum resolution of the shadow map.
|
||||
virtual void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) = 0;
|
||||
//! Sets the shadow bias
|
||||
//! Sets the shadow bias.
|
||||
virtual void SetShadowBias(ShadowId id, float bias) = 0;
|
||||
//! Sets the shadow filter method
|
||||
//! Sets the normal shadow bias.
|
||||
virtual void SetNormalShadowBias(ShadowId id, float normalShadowBias) = 0;
|
||||
//! Sets the shadow filter method.
|
||||
virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0;
|
||||
//! Sets the sample count for filtering of the shadow boundary, max 64.
|
||||
virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0;
|
||||
|
||||
@@ -598,6 +598,15 @@ namespace AZ
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float normalShadowBias)
|
||||
{
|
||||
for (auto& it : m_shadowData)
|
||||
{
|
||||
it.second.GetData(handle.GetIndex()).m_normalShadowBias = normalShadowBias;
|
||||
}
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
|
||||
{
|
||||
PrepareForChangingRenderPipelineAndCameraView();
|
||||
|
||||
@@ -92,8 +92,9 @@ namespace AZ
|
||||
uint32_t m_shadowmapSize = 1; // width and height of shadowmap
|
||||
uint32_t m_cascadeCount = 1;
|
||||
// Reduce acne by applying a small amount of bias to apply along shadow-space z.
|
||||
float m_shadowBias = 0.0f;
|
||||
uint32_t m_predictionSampleCount = 0;
|
||||
float m_shadowBias = 0.0f;
|
||||
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
float m_normalShadowBias;
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
uint32_t m_debugFlags = 0;
|
||||
uint32_t m_shadowFilterMethod = 0;
|
||||
@@ -101,6 +102,8 @@ namespace AZ
|
||||
float m_padding[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(DirectionalLightShadowData) % 16 == 0); // Structured buffers need alignment to be a multiple of 16 bytes.
|
||||
|
||||
class DirectionalLightFeatureProcessor final
|
||||
: public DirectionalLightFeatureProcessorInterface
|
||||
{
|
||||
@@ -216,6 +219,7 @@ namespace AZ
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override;
|
||||
void SetShadowBias(LightHandle handle, float bias) override;
|
||||
void SetNormalShadowBias(LightHandle handle, float normalShadowBias) override;
|
||||
|
||||
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
|
||||
uint32_t GetLightCount() const;
|
||||
|
||||
@@ -151,6 +151,14 @@ namespace AZ::Render
|
||||
shadowProperty.m_bias = bias;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetNormalShadowBias(ShadowId id, float normalShadowBias)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias().");
|
||||
|
||||
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id);
|
||||
shadowProperty.m_normalShadowBias = normalShadowBias;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution().");
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace AZ::Render
|
||||
void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override;
|
||||
void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override;
|
||||
void SetShadowBias(ShadowId id, float bias) override;
|
||||
void SetNormalShadowBias(ShadowId id, float normalShadowBias) override;
|
||||
void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override;
|
||||
void SetFilteringSampleCount(ShadowId id, uint16_t count) override;
|
||||
void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override;
|
||||
@@ -64,10 +65,10 @@ namespace AZ::Render
|
||||
uint32_t m_shadowmapArraySlice = 0; // array slice who has shadowmap in the atlas.
|
||||
uint32_t m_shadowFilterMethod = 0; // filtering method of shadows.
|
||||
float m_boundaryScale = 0.f; // the half of boundary of lit/shadowed areas. (in degrees)
|
||||
uint32_t m_predictionSampleCount = 0; // sample count to judge whether it is on the shadow boundary or not.
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
AZStd::array<float, 2> m_unprojectConstants = { {0, 0} };
|
||||
float m_bias;
|
||||
float m_normalShadowBias;
|
||||
float m_esmExponent = 87.0f;
|
||||
float m_padding[3];
|
||||
};
|
||||
@@ -78,6 +79,7 @@ namespace AZ::Render
|
||||
ProjectedShadowDescriptor m_desc;
|
||||
RPI::ViewPtr m_shadowmapView;
|
||||
float m_bias = 0.1f;
|
||||
float m_normalShadowBias = 0.0f;
|
||||
ShadowId m_shadowId;
|
||||
};
|
||||
|
||||
|
||||
+8
@@ -176,6 +176,14 @@ namespace AZ
|
||||
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
|
||||
//! @param Sets the amount of bias to apply.
|
||||
virtual void SetShadowBias(float bias) = 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;
|
||||
};
|
||||
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
|
||||
|
||||
|
||||
+3
@@ -101,6 +101,9 @@ namespace AZ
|
||||
//! Method of shadow's filtering.
|
||||
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
|
||||
|
||||
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
float m_normalShadowBias = 0.0f;
|
||||
|
||||
//! Sample Count for filtering (from 4 to 64)
|
||||
//! It is used only when the pixel is predicted as on the boundary.
|
||||
uint16_t m_filteringSampleCount = 32;
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ namespace AZ
|
||||
->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod)
|
||||
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
|
||||
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled)
|
||||
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias);
|
||||
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias)
|
||||
->Field("Normal Shadow Bias", &DirectionalLightComponentConfig::m_normalShadowBias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -86,6 +86,8 @@ namespace AZ
|
||||
->Event("SetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::SetShadowReceiverPlaneBiasEnabled)
|
||||
->Event("GetShadowBias", &DirectionalLightRequestBus::Events::GetShadowBias)
|
||||
->Event("SetShadowBias", &DirectionalLightRequestBus::Events::SetShadowBias)
|
||||
->Event("GetNormalShadowBias", &DirectionalLightRequestBus::Events::GetNormalShadowBias)
|
||||
->Event("SetNormalShadowBias", &DirectionalLightRequestBus::Events::SetNormalShadowBias)
|
||||
->VirtualProperty("Color", "GetColor", "SetColor")
|
||||
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
|
||||
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
|
||||
@@ -101,7 +103,8 @@ namespace AZ
|
||||
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
|
||||
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
|
||||
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled")
|
||||
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias");
|
||||
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
|
||||
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias");
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -423,6 +426,20 @@ namespace AZ
|
||||
return m_configuration.m_shadowBias;
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetNormalShadowBias(float bias)
|
||||
{
|
||||
m_configuration.m_normalShadowBias = bias;
|
||||
if (m_featureProcessor)
|
||||
{
|
||||
m_featureProcessor->SetNormalShadowBias(m_lightHandle, bias);
|
||||
}
|
||||
}
|
||||
|
||||
float DirectionalLightComponentController::GetNormalShadowBias() const
|
||||
{
|
||||
return m_configuration.m_normalShadowBias;
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetFilteringSampleCount(uint32_t count)
|
||||
{
|
||||
const uint16_t count16 = GetMin(Shadow::MaxPcfSamplingCount, aznumeric_cast<uint16_t>(count));
|
||||
@@ -517,6 +534,7 @@ namespace AZ
|
||||
SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled);
|
||||
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
|
||||
SetShadowBias(m_configuration.m_shadowBias);
|
||||
SetNormalShadowBias(m_configuration.m_normalShadowBias);
|
||||
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
|
||||
SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled);
|
||||
|
||||
|
||||
+3
-1
@@ -81,7 +81,9 @@ namespace AZ
|
||||
bool GetShadowReceiverPlaneBiasEnabled() const override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(bool enable) override;
|
||||
float GetShadowBias() const override;
|
||||
void SetShadowBias(float width) override;
|
||||
void SetShadowBias(float bias) override;
|
||||
float GetNormalShadowBias() const override;
|
||||
void SetNormalShadowBias(float bias) override;
|
||||
|
||||
private:
|
||||
friend class EditorDirectionalLightComponent;
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(Edit::Attributes::Max, 100.0f)
|
||||
->Attribute(Edit::Attributes::SoftMin, 0.0f)
|
||||
->Attribute(Edit::Attributes::SoftMax, 1.0f)
|
||||
->Attribute(Edit::Attributes::SoftMax, 2.0f)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
|
||||
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
|
||||
|
||||
+8
-1
@@ -134,7 +134,7 @@ namespace AZ
|
||||
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count\n",
|
||||
"This is used only when the pixel is predicted as on the boundary.\n"
|
||||
"This is used only when the pixel is predicted to be on the boundary.\n"
|
||||
"Specific to PCF and ESM+PCF.")
|
||||
->Attribute(Edit::Attributes::Min, 4)
|
||||
->Attribute(Edit::Attributes::Max, 64)
|
||||
@@ -154,6 +154,13 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::Min, 0.f)
|
||||
->Attribute(Edit::Attributes::Max, 0.2)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(
|
||||
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::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)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +465,7 @@ void ApplyLighting(inout Surface surface, inout LightingData lightingData)
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, surface.position, lightingData.shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, surface.position, surface.vertexNormal, lightingData.shadowCoords);
|
||||
}
|
||||
|
||||
// Light loops application.
|
||||
|
||||
@@ -59,6 +59,7 @@ VSOutput TerrainPBR_MainPassVS(VertexInput IN)
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
shadowIndex,
|
||||
worldPosition,
|
||||
OUT.m_normal,
|
||||
OUT.m_shadowCoords);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user