Fix SSR artifacts when ray goes towards the screen

This commit is contained in:
Wojtek Figat
2026-01-28 09:22:48 +01:00
parent b1b6953200
commit f105d6f84f
2 changed files with 12 additions and 6 deletions

View File

@@ -64,6 +64,9 @@ float3 TraceScreenSpaceReflection(
#endif
float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 50, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f)
{
#if SSR_USE_HZB
uncertainHit = false;
#endif
#ifndef SSR_SKIP_INVALID_CHECK
// Reject invalid pixels
if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance)
@@ -73,9 +76,9 @@ float3 TraceScreenSpaceReflection(
// Calculate view space normal vector
float3 normalVS = mul(gBuffer.Normal, (float3x3)viewMatrix);
float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS));
if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4)
return 0;
if (reflectVS.z < 0.001f)
return 0; // Ray goes towards the view
// Calculate ray path in UV space (z is raw depth)
float3 reflectWS = ScreenSpaceReflectionDirection(uv, gBuffer, viewPos, temporal, temporalTime, brdfBias);
#if SSR_USE_HZB
@@ -149,6 +152,9 @@ float3 TraceScreenSpaceReflection(
// Fade on distance
float distanceFade = saturate((drawDistance - gBuffer.ViewPos.z) / drawDistance);
// Fade on ray
float reflectFade = saturate(reflectVS.z * 8.0f);
// Output: xy: hitUV, z: hitMask
return float3(currOffset.xy, fadeOnBorder * roughnessFade * distanceFade);
return float3(currOffset.xy, fadeOnBorder * roughnessFade * distanceFade * reflectFade);
}

View File

@@ -107,14 +107,14 @@ float3 FFX_SSSR_HierarchicalRaymarch(Texture2D depthBuffer, uint hzbMips, float
FFX_SSSR_InitialAdvanceRay(origin, direction, inv_direction, current_mip_resolution, current_mip_resolution_inv, floor_offset, uv_offset, position, current_t);
uint overDiffError = 0;
int i = 0;
uint i = 0;
while (i < max_traversal_intersections && current_mip >= most_detailed_mip) {
float2 current_mip_position = current_mip_resolution * position.xy;
float surface_z = depthBuffer.Load(int3(current_mip_position, current_mip)).x;
if (position.z - surface_z > depthDiffError) overDiffError++; // Count number of times we were under the depth by more than the allowed error
bool skipped_tile = FFX_SSSR_AdvanceRay(origin, direction, inv_direction, current_mip_position, current_mip_resolution_inv, floor_offset, uv_offset, surface_z, position, current_t);
++i;
if (!skipped_tile || current_mip < hzbMips) // Never go too low depth resolution to avoid blocky artifacts
if (!skipped_tile || current_mip < (int)hzbMips) // Never go too low depth resolution to avoid blocky artifacts
{
current_mip += skipped_tile ? 1 : -1;
current_mip_resolution *= skipped_tile ? 0.5 : 2;