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