Add temporal dithering and more accurate blending for contact shadows

This commit is contained in:
2026-06-22 23:55:16 +02:00
parent af886ca483
commit 4ac28b7d8a
4 changed files with 17 additions and 10 deletions
+1 -1
View File
@@ -162,7 +162,7 @@ public:
/// <summary>
/// The length of the rays for contact shadows computed via the screen-space tracing. Set this to values higher than 0 to enable screen-space shadows rendering for this light. This improves the shadowing details. Actual ray distance is based on the pixel distance from the camera.
/// </summary>
API_FIELD(Attributes="EditorOrder(99), EditorDisplay(\"Shadow\"), Limit(0.0f, 0.1f, 0.001f)")
API_FIELD(Attributes="EditorOrder(99), EditorDisplay(\"Shadow\"), Limit(0.0f, 0.4f, 0.001f)")
float ContactShadowsLength = 0.0f;
/// <summary>
+2 -1
View File
@@ -34,7 +34,7 @@ GPU_CB_STRUCT(Data {
ShaderLightData Light;
Matrix WVP;
Matrix ViewProjectionMatrix;
float Dummy0;
uint32 FrameIndexMod8;
float TemporalTime;
float ContactShadowsDistance;
float ContactShadowsLength;
@@ -1718,6 +1718,7 @@ void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, Rende
else if (light.IsSpotLight)
((RenderSpotLightData&)light).SetShaderData(sperLight.Light, true);
Matrix::Transpose(view.ViewProjection(), sperLight.ViewProjectionMatrix);
sperLight.FrameIndexMod8 = renderContext.List->Setup.UseTemporalAAJitter ? (int32)(Engine::FrameCount % 8) : 0;
sperLight.TemporalTime = renderContext.List->Setup.UseTemporalAAJitter ? RenderTools::ComputeTemporalTime() : 0.0f;
sperLight.ContactShadowsDistance = light.ShadowsDistance;
sperLight.ContactShadowsLength = EnumHasAnyFlags(view.Flags, ViewFlags::ContactShadows) ? light.ContactShadowsLength : 0.0f;
+1 -1
View File
@@ -863,7 +863,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
result = float4(lerp(result.rgb, previous.rgb, historyWeight), 1.0f);
// Apply quantization error to reduce yellowish artifacts due to R11G11B10 format
float noise = InterleavedGradientNoise(octahedralCoords, FrameIndexMod8);
float noise = InterleavedGradientNoise(octahedralCoords * 10, FrameIndexMod8);
result.rgb = QuantizeColor(result.rgb, noise, QuantizationError);
#else
result = float4(lerp(result.rg, previous.rg, historyWeight), 0.0f, 1.0f);
+13 -7
View File
@@ -13,7 +13,7 @@ GBufferData GBuffer;
LightData Light;
float4x4 WVP;
float4x4 ViewProjectionMatrix;
float Dummy0;
uint FrameIndexMod8;
float TemporalTime;
float ContactShadowsDistance;
float ContactShadowsLength;
@@ -26,7 +26,9 @@ DECLARE_GBUFFERDATA_ACCESS(GBuffer)
#if CONTACT_SHADOWS
float RayCastScreenSpaceShadow(GBufferData gBufferData, GBufferSample gBuffer, float3 rayStartWS, float3 rayDirWS, float rayLength)
#include "./Flax/Noise.hlsl"
float RayCastScreenSpaceShadow(GBufferData gBufferData, GBufferSample gBuffer, float3 rayStartWS, float3 rayDirWS, float rayLength, float dither = 0.5f)
{
uint2 depthSize;
Depth.GetDimensions(depthSize.x, depthSize.y);
@@ -53,7 +55,7 @@ float RayCastScreenSpaceShadow(GBufferData gBufferData, GBufferSample gBuffer, f
float rayStepDstMin = min(rayStepDst.x, rayStepDst.y);
float3 rayStepMin = raySize / max(min(maxSteps, rayStepDstMin), 1);
float3 rayStep = raySize / maxSteps;
float3 ray = rayStart + rayStepMin * 1.5f;
float3 ray = rayStart + rayStepMin * (dither * 2 + 1.0f);
// Sample over the ray
float lightAmountMax = 0;
@@ -113,8 +115,10 @@ float4 PS_DirLight(Quad_VS2PS input) : SV_Target0
ShadowSample shadow = SampleDirectionalLightShadow(Light, ShadowsBuffer, ShadowMap, gBuffer, TemporalTime);
#if CONTACT_SHADOWS
// Calculate screen-space contact shadow
shadow.SurfaceShadow *= RayCastScreenSpaceShadow(gBufferData, gBuffer, gBuffer.WorldPos, Light.Direction, ContactShadowsLength);
// Calculate screen-space contact shadow
float dither = InterleavedGradientNoise(input.Position.xy, FrameIndexMod8);
float contactShadow = RayCastScreenSpaceShadow(gBufferData, gBuffer, gBuffer.WorldPos, Light.Direction, ContactShadowsLength, dither);
shadow.SurfaceShadow = min(shadow.SurfaceShadow, contactShadow);
#endif
return GetShadowMask(shadow);
@@ -155,8 +159,10 @@ float4 PS_LocalLight(Model_VS2PS input) : SV_Target0
#endif
#if CONTACT_SHADOWS
// Calculate screen-space contact shadow
shadow.SurfaceShadow *= RayCastScreenSpaceShadow(gBufferData, gBuffer, gBuffer.WorldPos, normalize(Light.Position - gBuffer.WorldPos), ContactShadowsLength);
// Calculate screen-space contact shadow
float dither = InterleavedGradientNoise(input.ScreenPos.xy, FrameIndexMod8);
float contactShadow = RayCastScreenSpaceShadow(gBufferData, gBuffer, gBuffer.WorldPos, normalize(Light.Position - gBuffer.WorldPos), ContactShadowsLength, dither);
shadow.SurfaceShadow = min(shadow.SurfaceShadow, contactShadow);
#endif
return GetShadowMask(shadow);