diff --git a/Source/Engine/Level/Actors/Light.h b/Source/Engine/Level/Actors/Light.h
index f8bb353f1..63b78a6b3 100644
--- a/Source/Engine/Level/Actors/Light.h
+++ b/Source/Engine/Level/Actors/Light.h
@@ -162,7 +162,7 @@ public:
///
/// 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.
///
- 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;
///
diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp
index 7065e33dd..a3fd7d625 100644
--- a/Source/Engine/Renderer/ShadowsPass.cpp
+++ b/Source/Engine/Renderer/ShadowsPass.cpp
@@ -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;
diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader
index 6c4e65572..4e3541554 100644
--- a/Source/Shaders/GI/DDGI.shader
+++ b/Source/Shaders/GI/DDGI.shader
@@ -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);
diff --git a/Source/Shaders/Shadows.shader b/Source/Shaders/Shadows.shader
index 7f5b81511..c7f3e6741 100644
--- a/Source/Shaders/Shadows.shader
+++ b/Source/Shaders/Shadows.shader
@@ -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);