Add CascadeBlendSize to Directional Light and fix sun shadow fade at distance
This commit is contained in:
@@ -48,6 +48,7 @@ void DirectionalLight::Draw(RenderContext& renderContext)
|
||||
data.Cascade2Spacing = Cascade2Spacing;
|
||||
data.Cascade3Spacing = Cascade3Spacing;
|
||||
data.Cascade4Spacing = Cascade4Spacing;
|
||||
data.CascadeBlendSize = CascadeBlendSize;
|
||||
data.PartitionMode = PartitionMode;
|
||||
data.ContactShadowsLength = ContactShadowsLength;
|
||||
data.StaticFlags = GetStaticFlags();
|
||||
@@ -69,6 +70,7 @@ void DirectionalLight::Serialize(SerializeStream& stream, const void* otherObj)
|
||||
SERIALIZE(Cascade2Spacing);
|
||||
SERIALIZE(Cascade3Spacing);
|
||||
SERIALIZE(Cascade4Spacing);
|
||||
SERIALIZE(CascadeBlendSize);
|
||||
SERIALIZE(PartitionMode);
|
||||
}
|
||||
|
||||
@@ -82,6 +84,7 @@ void DirectionalLight::Deserialize(DeserializeStream& stream, ISerializeModifier
|
||||
DESERIALIZE(Cascade2Spacing);
|
||||
DESERIALIZE(Cascade3Spacing);
|
||||
DESERIALIZE(Cascade4Spacing);
|
||||
DESERIALIZE(CascadeBlendSize);
|
||||
DESERIALIZE(PartitionMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,12 @@ public:
|
||||
API_FIELD(Attributes="EditorOrder(69), DefaultValue(1.0f), VisibleIf(nameof(ShowCascade4)), Limit(0, 1, 0.001f), EditorDisplay(\"Shadow\")")
|
||||
float Cascade4Spacing = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Percentage of the cascade distance over which cascades will blend together. This helps to hide the transition between cascades.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes = "EditorOrder(70), EditorDisplay(\"Shadow\", \"Cascade Blend Distance\"), Limit(0.0f, 1.0f)")
|
||||
float CascadeBlendSize = 0.1f;
|
||||
|
||||
public:
|
||||
// [LightWithShadow]
|
||||
void Draw(RenderContext& renderContext) override;
|
||||
|
||||
@@ -79,6 +79,7 @@ struct RenderDirectionalLightData : RenderLightData
|
||||
|
||||
PartitionMode PartitionMode;
|
||||
int32 CascadeCount;
|
||||
float CascadeBlendSize;
|
||||
|
||||
RenderDirectionalLightData()
|
||||
{
|
||||
|
||||
@@ -195,7 +195,7 @@ struct ShadowAtlasLight
|
||||
bool BlendCSM;
|
||||
mutable StaticStates StaticState;
|
||||
BoundingSphere Bounds;
|
||||
float Sharpness, Fade, NormalOffsetScale, Bias, FadeDistance, Distance, TileBorder;
|
||||
float Sharpness, Fade, NormalOffsetScale, Bias, FadeDistance, Distance, TileBorder, CascadeBlendSize;
|
||||
Float4 CascadeSplits;
|
||||
ShadowAtlasLightTile Tiles[SHADOWS_MAX_TILES];
|
||||
ShadowAtlasLightCache Cache;
|
||||
@@ -846,6 +846,7 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render
|
||||
cascadeSplits[i] = (cascadeSplits[i] - renderContext.View.Near) / viewRange;
|
||||
}
|
||||
atlasLight.CascadeSplits = renderContext.View.Near + Float4(cascadeSplits) * viewRange;
|
||||
atlasLight.CascadeBlendSize = Math::Saturate(light.CascadeBlendSize);
|
||||
|
||||
// Update cached state (invalidate it if the light changed)
|
||||
atlasLight.ValidateCache(renderContext.View, light);
|
||||
@@ -917,10 +918,10 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render
|
||||
|
||||
// Calculate cascade split frustum corners in view space
|
||||
Float3 cascadeCornersVs[8];
|
||||
float csmOverlap = atlasLight.BlendCSM ? 0.2f : 0.1f;
|
||||
float blendDistance = atlasLight.CascadeBlendSize;
|
||||
for (int32 j = 0; j < 4; j++)
|
||||
{
|
||||
float overlapWithPrevSplit = csmOverlap * (splitMinRatio - oldSplitMinRatio);
|
||||
float overlapWithPrevSplit = blendDistance * (splitMinRatio - oldSplitMinRatio);
|
||||
const Float3 frustumRangeVS = frustumCornersVs[j + 4] - frustumCornersVs[j];
|
||||
cascadeCornersVs[j] = frustumCornersVs[j] + frustumRangeVS * (splitMinRatio - overlapWithPrevSplit);
|
||||
cascadeCornersVs[j + 4] = frustumCornersVs[j] + frustumRangeVS * splitMaxRatio;
|
||||
@@ -1430,7 +1431,7 @@ RETRY_ATLAS_SETUP:
|
||||
{
|
||||
// Shadow info
|
||||
auto* packed = shadows.ShadowsBuffer.WriteReserve<Float4>(2);
|
||||
Color32 packed0x((byte)(atlasLight.Sharpness * (255.0f / 10.0f)), (byte)(atlasLight.Fade * 255.0f), (byte)atlasLight.TilesCount, 0);
|
||||
Color32 packed0x((byte)(atlasLight.Sharpness * (255.0f / 10.0f)), (byte)(atlasLight.Fade * 255.0f), (byte)atlasLight.TilesCount, (byte)(atlasLight.CascadeBlendSize * 255.0f));
|
||||
packed[0] = Float4(*(const float*)&packed0x, atlasLight.FadeDistance, atlasLight.NormalOffsetScale, atlasLight.Bias);
|
||||
packed[1] = atlasLight.CascadeSplits;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ struct ShadowData
|
||||
float FadeDistance;
|
||||
float NormalOffsetScale;
|
||||
float Bias;
|
||||
float CascadeBlendSize;
|
||||
uint TilesCount;
|
||||
float4 CascadeSplits;
|
||||
};
|
||||
@@ -43,6 +44,7 @@ ShadowData LoadShadowsBuffer(Buffer<float4> shadowsBuffer, uint shadowsBufferAdd
|
||||
shadow.Sharpness = (packed0x & 0x000000ff) * (10.0f / 255.0f);
|
||||
shadow.Fade = ((packed0x & 0x0000ff00) >> 8) * (1.0f / 255.0f);
|
||||
shadow.TilesCount = ((packed0x & 0x00ff0000) >> 16);
|
||||
shadow.CascadeBlendSize = ((packed0x & 0xff000000) >> 24) * (1.0f / 255.0f);
|
||||
shadow.FadeDistance = vector0.y;
|
||||
shadow.NormalOffsetScale = vector0.z;
|
||||
shadow.Bias = vector0.w;
|
||||
|
||||
@@ -293,11 +293,10 @@ ShadowSample SampleDirectionalLightShadow(LightData light, Buffer<float4> shadow
|
||||
float splitDist = (nextSplit - viewDepth) / splitSize;
|
||||
#endif
|
||||
#if SHADOWS_CSM_DITHERING && !SHADOWS_CSM_BLENDING
|
||||
const float BlendThreshold = 0.05f;
|
||||
if (splitDist <= BlendThreshold && cascadeIndex != shadow.TilesCount - 1)
|
||||
if (splitDist <= shadow.CascadeBlendSize && cascadeIndex != shadow.TilesCount - 1)
|
||||
{
|
||||
// Dither with the next cascade but with screen-space dithering (gets cleaned out by TAA)
|
||||
float lerpAmount = 1 - splitDist / BlendThreshold;
|
||||
float lerpAmount = 1 - splitDist / shadow.CascadeBlendSize;
|
||||
if (step(RandN2(gBuffer.ViewPos.xy + dither).x, lerpAmount))
|
||||
cascadeIndex++;
|
||||
}
|
||||
@@ -312,17 +311,19 @@ ShadowSample SampleDirectionalLightShadow(LightData light, Buffer<float4> shadow
|
||||
result = SampleDirectionalLightShadowCascade(light, shadowsBuffer, shadowMap, gBuffer, shadow, samplePosition, cascadeIndex);
|
||||
|
||||
#if SHADOWS_CSM_BLENDING
|
||||
const float BlendThreshold = 0.1f;
|
||||
if (splitDist <= BlendThreshold && cascadeIndex != shadow.TilesCount - 1)
|
||||
if (splitDist <= shadow.CascadeBlendSize && cascadeIndex != shadow.TilesCount - 1)
|
||||
{
|
||||
// Sample the next cascade, and blend between the two results to smooth the transition
|
||||
ShadowSample nextResult = SampleDirectionalLightShadowCascade(light, shadowsBuffer, shadowMap, gBuffer, shadow, samplePosition, cascadeIndex + 1);
|
||||
float blendAmount = splitDist / BlendThreshold;
|
||||
float blendAmount = splitDist / shadow.CascadeBlendSize;
|
||||
result.SurfaceShadow = lerp(nextResult.SurfaceShadow, result.SurfaceShadow, blendAmount);
|
||||
result.TransmissionShadow = lerp(nextResult.TransmissionShadow, result.TransmissionShadow, blendAmount);
|
||||
}
|
||||
#endif
|
||||
|
||||
result.SurfaceShadow = lerp(result.SurfaceShadow, 1, fade);
|
||||
result.TransmissionShadow = lerp(result.TransmissionShadow, 1, fade);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user