Skip to content

Commit cbe15a3

Browse files
SSR: properly handle depth vs camera z
Also, don't use isnan (fix #219)
1 parent 5b33a3f commit cbe15a3

File tree

7 files changed

+165
-157
lines changed

7 files changed

+165
-157
lines changed

Shaders/Common/public/PostFX_Common.fxh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,42 @@ float ComputeSpatialWeight(float Distance, float Sigma)
136136
return exp(-(Distance) / (2.0 * Sigma * Sigma));
137137
}
138138

139+
// Samples a depth buffer at the given unnormalized coordinates and returns the interpolated
140+
// camera space Z value.
141+
float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,
142+
int2 Dimensions,
143+
float2 Location,
144+
int MipLevel,
145+
float4x4 Proj)
146+
{
147+
Location -= float2(0.5, 0.5);
148+
149+
float2 Location00 = floor(Location);
150+
float2 Weights = Location - Location00;
151+
152+
int i0 = clamp(int(Location00.x), 0, Dimensions.x - 1);
153+
int j0 = clamp(int(Location00.y), 0, Dimensions.y - 1);
154+
int i1 = clamp(int(Location00.x) + 1, 0, Dimensions.x - 1);
155+
int j1 = clamp(int(Location00.y) + 1, 0, Dimensions.y - 1);
156+
157+
float Z00 = DepthToCameraZ(DepthBuffer.Load(int3(i0, j0, MipLevel)), Proj);
158+
float Z10 = DepthToCameraZ(DepthBuffer.Load(int3(i1, j0, MipLevel)), Proj);
159+
float Z01 = DepthToCameraZ(DepthBuffer.Load(int3(i0, j1, MipLevel)), Proj);
160+
float Z11 = DepthToCameraZ(DepthBuffer.Load(int3(i1, j1, MipLevel)), Proj);
161+
162+
return lerp(lerp(Z00, Z10, Weights.x),
163+
lerp(Z01, Z11, Weights.x),
164+
Weights.y);
165+
}
166+
167+
float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,
168+
float2 Location,
169+
int MipLevel,
170+
float4x4 Proj)
171+
{
172+
int2 Dimensions;
173+
DepthBuffer.GetDimensions(Dimensions.x, Dimensions.y);
174+
return SampleCameraZFromDepthUC(DepthBuffer, Dimensions, Location, MipLevel, Proj);
175+
}
176+
139177
#endif // _POST_FX_COMMON_FXH_

Shaders/PostProcess/ScreenSpaceReflection/private/SSR_ComputeBilateralCleanup.fx

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,47 +20,47 @@ Texture2D<float> g_TextureRoughness;
2020
Texture2D<float4> g_TextureRadiance;
2121
Texture2D<float> g_TextureVariance;
2222

23-
float SampleDepth(int2 PixelCoord)
23+
float LoadDepth(int2 PixelCoord)
2424
{
2525
return g_TextureDepth.Load(int3(PixelCoord, 0));
2626
}
2727

28-
float SampleRoughness(int2 PixelCoord)
28+
float LoadRoughness(int2 PixelCoord)
2929
{
3030
return g_TextureRoughness.Load(int3(PixelCoord, 0));
3131
}
3232

33-
float3 SampleNormalWS(int2 PixelCoord)
33+
float3 LoadNormalWS(int2 PixelCoord)
3434
{
3535
return g_TextureNormal.Load(int3(PixelCoord, 0));
3636
}
3737

38-
float4 SampleRadiance(int2 PixelCoord)
38+
float4 LoadRadiance(int2 PixelCoord)
3939
{
4040
return g_TextureRadiance.Load(int3(PixelCoord, 0));
4141
}
4242

43-
float SampleVariance(int2 PixelCoord)
43+
float LoadVariance(int2 PixelCoord)
4444
{
4545
return g_TextureVariance.Load(int3(PixelCoord, 0));
4646
}
4747

4848
SSR_ATTRIBUTE_EARLY_DEPTH_STENCIL
4949
float4 ComputeBilateralCleanupPS(in FullScreenTriangleVSOutput VSOut) : SV_Target0
5050
{
51-
float4 Position = VSOut.f4PixelPos;
51+
int2 PixelCoord = int2(VSOut.f4PixelPos.xy);
5252

53-
float Roughness = SampleRoughness(int2(Position.xy));
54-
float Variance = SampleVariance(int2(Position.xy));
55-
float3 NormalWS = SampleNormalWS(int2(Position.xy));
56-
float LinearDepth = DepthToCameraZ(SampleDepth(int2(Position.xy)), g_Camera.mProj);
57-
float2 GradDepth = float2(ddx(LinearDepth), ddy(LinearDepth));
53+
float Roughness = LoadRoughness(PixelCoord);
54+
float Variance = LoadVariance(PixelCoord);
55+
float3 NormalWS = LoadNormalWS(PixelCoord);
56+
float CameraZ = DepthToCameraZ(LoadDepth(PixelCoord), g_Camera.mProj);
57+
float2 GradCamZ = float2(ddx(CameraZ), ddy(CameraZ));
5858

5959
float RoughnessTarget = saturate(float(SSR_BILATERAL_ROUGHNESS_FACTOR) * Roughness);
6060
float Radius = lerp(0.0, Variance > SSS_BILATERAL_VARIANCE_ESTIMATE_THRESHOLD ? 2.0 : 0.0, RoughnessTarget);
6161
float Sigma = g_SSRAttribs.BilateralCleanupSpatialSigmaFactor;
6262
int EffectiveRadius = int(min(2.0 * Sigma, Radius));
63-
float4 RadianceResult = SampleRadiance(int2(Position.xy));
63+
float4 RadianceResult = LoadRadiance(PixelCoord);
6464

6565
if (Variance > SSR_BILATERAL_VARIANCE_EXIT_THRESHOLD && EffectiveRadius > 0)
6666
{
@@ -70,24 +70,23 @@ float4 ComputeBilateralCleanupPS(in FullScreenTriangleVSOutput VSOut) : SV_Targe
7070
{
7171
for (int y = -EffectiveRadius; y <= EffectiveRadius; y++)
7272
{
73-
int2 Location = ClampScreenCoord(int2(Position.xy) + int2(x, y), int2(g_Camera.f4ViewportSize.xy));
74-
float SampledDepth = SampleDepth(Location);
75-
float SampledRoughness = SampleRoughness(Location);
76-
float4 SampledRadiance = SampleRadiance(Location);
77-
float3 SampledNormalWS = SampleNormalWS(Location);
73+
int2 Location = ClampScreenCoord(PixelCoord + int2(x, y), int2(g_Camera.f4ViewportSize.xy));
74+
float SampledDepth = LoadDepth(Location);
75+
float SampledRoughness = LoadRoughness(Location);
76+
float4 SampledRadiance = LoadRadiance(Location);
77+
float3 SampledNormalWS = LoadNormalWS(Location);
7878

7979
if (IsReflectionSample(SampledRoughness, SampledDepth, g_SSRAttribs.RoughnessThreshold))
8080
{
81-
float SampledLinearDepth = DepthToCameraZ(SampledDepth, g_Camera.mProj);
81+
float SampledCameraZ = DepthToCameraZ(SampledDepth, g_Camera.mProj);
8282
float WeightS = exp(-0.5 * dot(float2(x, y), float2(x, y)) / (Sigma * Sigma));
83-
float WeightZ = exp(-abs(LinearDepth - SampledLinearDepth) / (SSR_BILATERAL_SIGMA_DEPTH * (abs(dot(float2(x, y), GradDepth)) + 1e-6)));
83+
float WeightZ = exp(-abs(CameraZ - SampledCameraZ) / (SSR_BILATERAL_SIGMA_DEPTH * (abs(dot(float2(x, y), GradCamZ)) + 1e-6)));
8484
float WeightN = pow(max(0.0, dot(NormalWS, SampledNormalWS)), SSR_BILATERAL_SIGMA_NORMAL);
8585
float Weight = WeightS * WeightN * WeightZ;
8686

8787
WeightSum += Weight;
8888
ColorSum += Weight * SampledRadiance;
8989
}
90-
9190
}
9291
}
9392

Shaders/PostProcess/ScreenSpaceReflection/private/SSR_ComputeHierarchicalDepthBuffer.fx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,34 @@
55
Texture2D<float> g_TextureLastMip;
66
#else
77
Texture2D<float> g_TextureMips;
8-
SamplerState g_TextureMips_sampler;
98
#endif
109

1110
#if SUPPORTED_SHADER_SRV
12-
float SampleDepth(int2 Location, int2 Offset, int3 Dimension)
11+
float LoadDepth(int2 Location, int3 Dimension)
1312
{
14-
int2 Position = ClampScreenCoord(Location + Offset, Dimension.xy);
13+
int2 Position = ClampScreenCoord(Location, Dimension.xy);
1514
return g_TextureLastMip.Load(int3(Position, 0));
1615
}
1716
#else
18-
float SampleDepth(int2 Location, int2 Offset, int3 Dimension)
17+
float LoadDepth(int2 Location, int3 Dimension)
1918
{
20-
int2 Position = ClampScreenCoord(Location + Offset, Dimension.xy);
19+
int2 Position = ClampScreenCoord(Location, Dimension.xy);
2120
return g_TextureMips.Load(int3(Position, Dimension.z));
2221
}
2322
#endif
2423

24+
void UpdateClosestDepth(int2 Location, int3 LastMipDimension, inout float MinDepth)
25+
{
26+
float Depth = LoadDepth(Location, LastMipDimension);
27+
MinDepth = ClosestDepth(MinDepth, Depth);
28+
}
29+
2530
float ComputeHierarchicalDepthBufferPS(in FullScreenTriangleVSOutput VSOut) : SV_Target0
2631
{
2732
int3 LastMipDimension;
2833
#if SUPPORTED_SHADER_SRV
2934
g_TextureLastMip.GetDimensions(LastMipDimension.x, LastMipDimension.y);
35+
LastMipDimension.z = 0; // Unused
3036
#else
3137
int Dummy;
3238
g_TextureMips.GetDimensions(0, LastMipDimension.x, LastMipDimension.y, Dummy);
@@ -37,35 +43,30 @@ float ComputeHierarchicalDepthBufferPS(in FullScreenTriangleVSOutput VSOut) : SV
3743

3844
int2 RemappedPosition = int2(2.0 * floor(VSOut.f4PixelPos.xy));
3945

40-
float4 SampledPixels;
41-
SampledPixels.x = SampleDepth(RemappedPosition, int2(0, 0), LastMipDimension);
42-
SampledPixels.y = SampleDepth(RemappedPosition, int2(0, 1), LastMipDimension);
43-
SampledPixels.z = SampleDepth(RemappedPosition, int2(1, 0), LastMipDimension);
44-
SampledPixels.w = SampleDepth(RemappedPosition, int2(1, 1), LastMipDimension);
45-
46-
float MinDepth = ClosestDepth(ClosestDepth(SampledPixels.x, SampledPixels.y),
47-
ClosestDepth(SampledPixels.z, SampledPixels.w));
46+
float MinDepth = DepthFarPlane;
47+
UpdateClosestDepth(RemappedPosition + int2(0, 0), LastMipDimension, MinDepth);
48+
UpdateClosestDepth(RemappedPosition + int2(0, 1), LastMipDimension, MinDepth);
49+
UpdateClosestDepth(RemappedPosition + int2(1, 0), LastMipDimension, MinDepth);
50+
UpdateClosestDepth(RemappedPosition + int2(1, 1), LastMipDimension, MinDepth);
4851

4952
bool IsWidthOdd = (LastMipDimension.x & 1) != 0;
5053
bool IsHeightOdd = (LastMipDimension.y & 1) != 0;
5154

5255
if (IsWidthOdd)
5356
{
54-
SampledPixels.x = SampleDepth(RemappedPosition, int2(2, 0), LastMipDimension);
55-
SampledPixels.y = SampleDepth(RemappedPosition, int2(2, 1), LastMipDimension);
56-
MinDepth = ClosestDepth(MinDepth, ClosestDepth(SampledPixels.x, SampledPixels.y));
57+
UpdateClosestDepth(RemappedPosition + int2(2, 0), LastMipDimension, MinDepth);
58+
UpdateClosestDepth(RemappedPosition + int2(2, 1), LastMipDimension, MinDepth);
5759
}
5860

5961
if (IsHeightOdd)
6062
{
61-
SampledPixels.x = SampleDepth(RemappedPosition, int2(0, 2), LastMipDimension);
62-
SampledPixels.y = SampleDepth(RemappedPosition, int2(1, 2), LastMipDimension);
63-
MinDepth = ClosestDepth(MinDepth, ClosestDepth(SampledPixels.x, SampledPixels.y));
63+
UpdateClosestDepth(RemappedPosition + int2(0, 2), LastMipDimension, MinDepth);
64+
UpdateClosestDepth(RemappedPosition + int2(1, 2), LastMipDimension, MinDepth);
6465
}
6566

6667
if (IsWidthOdd && IsHeightOdd)
6768
{
68-
MinDepth = ClosestDepth(MinDepth, SampleDepth(RemappedPosition, int2(2, 2), LastMipDimension));
69+
UpdateClosestDepth(RemappedPosition + int2(2, 2), LastMipDimension, MinDepth);
6970
}
7071

7172
return MinDepth;

Shaders/PostProcess/ScreenSpaceReflection/private/SSR_ComputeIntersection.fx

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,49 +28,37 @@ Texture2D<float2> g_TextureMotion;
2828
Texture2D<float2> g_TextureBlueNoise;
2929
Texture2D<float> g_TextureDepthHierarchy;
3030

31-
SamplerState g_TextureDepthHierarchy_sampler;
32-
33-
float3 ScreenSpaceToViewSpace(float3 ScreenCoordUV)
34-
{
35-
return InvProjectPosition(ScreenCoordUV, g_Camera.mProjInv);
36-
}
37-
38-
float3 ScreenSpaceToWorldSpace(float3 ScreenCoordUV)
39-
{
40-
return InvProjectPosition(ScreenCoordUV, g_Camera.mViewProjInv);
41-
}
42-
4331
float2 GetMipResolution(float2 ScreenDimensions, int MipLevel)
4432
{
4533
return ScreenDimensions * rcp(float(1 << MipLevel));
4634
}
4735

48-
float2 SampleRandomVector2D(int2 PixelCoord)
36+
float2 LoadRandomVector2D(int2 PixelCoord)
4937
{
5038
return g_TextureBlueNoise.Load(int3(PixelCoord & 127, 0));
5139
}
5240

53-
float SampleRoughness(int2 PixelCoord)
41+
float LoadRoughness(int2 PixelCoord)
5442
{
5543
return g_TextureRoughness.Load(int3(PixelCoord, 0));
5644
}
5745

58-
float3 SampleNormalWS(int2 PixelCoord)
46+
float3 LoadNormalWS(int2 PixelCoord)
5947
{
6048
return g_TextureNormal.Load(int3(PixelCoord, 0));
6149
}
6250

63-
float SampleDepthHierarchy(int2 PixelCoord, int MipLevel)
51+
float LoadDepthHierarchy(int2 PixelCoord, int MipLevel)
6452
{
6553
return g_TextureDepthHierarchy.Load(int3(PixelCoord, MipLevel));
6654
}
6755

68-
float2 SampleMotion(int2 PixelCoord)
56+
float2 LoadMotion(int2 PixelCoord)
6957
{
7058
return g_TextureMotion.Load(int3(PixelCoord, 0)) * F3NDC_XYZ_TO_UVD_SCALE.xy;
7159
}
7260

73-
float3 SampleRadiance(int2 PixelCoord)
61+
float3 LoadRadiance(int2 PixelCoord)
7462
{
7563
return g_TextureRadiance.Load(int3(PixelCoord, 0));
7664
}
@@ -182,7 +170,7 @@ float3 HierarchicalRaymarch(float3 Origin, float3 Direction, float2 ScreenSize,
182170
while (Idx < MaxTraversalIntersections && CurrentMip >= MostDetailedMip)
183171
{
184172
float2 CurrentMipPosition = CurrentMipResolution * Position.xy;
185-
float SurfaceDepth = SampleDepthHierarchy(int2(CurrentMipPosition), CurrentMip);
173+
float SurfaceDepth = LoadDepthHierarchy(int2(CurrentMipPosition), CurrentMip);
186174
bool SkippedTile = AdvanceRay(Origin, Direction, InvDirection, CurrentMipPosition, InvCurrentMipResolution, FloorOffset, UVOffset, SurfaceDepth, Position, CurrentT);
187175

188176
// Don't increase mip further than this because we did not generate it
@@ -224,13 +212,13 @@ float ValidateHit(float3 Hit, float2 ScreenCoordUV, float3 RayDirectionWS, float
224212

225213
// Don't lookup radiance from the background.
226214
int2 TexelCoords = int2(ScreenSize * Hit.xy);
227-
float SurfaceDepth = SampleDepthHierarchy(TexelCoords, 0);
215+
float SurfaceDepth = LoadDepthHierarchy(TexelCoords, 0);
228216

229217
if (IsBackground(SurfaceDepth))
230218
return 0.0;
231219

232220
// We check if we hit the surface from the back, these should be rejected.
233-
float3 HitNormalWS = SampleNormalWS(TexelCoords);
221+
float3 HitNormalWS = LoadNormalWS(TexelCoords);
234222
if (dot(HitNormalWS, RayDirectionWS) > 0.0)
235223
return 0.0;
236224

@@ -271,7 +259,7 @@ float4 SampleReflectionVector(float3 View, float3 Normal, float Roughness, int2
271259
float3 B = cross(T, N);
272260
float3x3 TangentToWorld = MatrixFromRows(T, B, N);
273261

274-
float2 Xi = SampleRandomVector2D(PixelCoord);
262+
float2 Xi = LoadRandomVector2D(PixelCoord);
275263
Xi.y = lerp(Xi.y, 0.0, g_SSRAttribs.GGXImportanceSampleBias);
276264

277265
float3 ViewDirTS = mul(TangentToWorld, View);
@@ -300,15 +288,15 @@ PSOutput ComputeIntersectionPS(in FullScreenTriangleVSOutput VSOut)
300288
#endif
301289

302290
float2 ScreenCoordUV = Position * g_Camera.f4ViewportSize.zw;
303-
float3 NormalWS = SampleNormalWS(int2(Position));
291+
float3 NormalWS = LoadNormalWS(int2(Position));
304292
float3 NormalVS = mul(float4(NormalWS, 0.0), g_Camera.mView).xyz;
305-
float Roughness = SampleRoughness(int2(Position));
293+
float Roughness = LoadRoughness(int2(Position));
306294

307295
bool IsMirror = IsMirrorReflection(Roughness);
308296
int MostDetailedMip = IsMirror ? 0 : int(g_SSRAttribs.MostDetailedMip);
309297
float2 MipResolution = GetMipResolution(g_Camera.f4ViewportSize.xy, MostDetailedMip);
310298

311-
float3 RayOriginSS = float3(ScreenCoordUV, SampleDepthHierarchy(int2(ScreenCoordUV * MipResolution), MostDetailedMip));
299+
float3 RayOriginSS = float3(ScreenCoordUV, LoadDepthHierarchy(int2(ScreenCoordUV * MipResolution), MostDetailedMip));
312300
float3 RayOriginVS = ScreenXYDepthToViewSpace(RayOriginSS, g_Camera.mProj);
313301

314302
float4 RayDirectionVS = SampleReflectionVector(-normalize(RayOriginVS), NormalVS, Roughness, int2(VSOut.f4PixelPos.xy));
@@ -320,13 +308,13 @@ PSOutput ComputeIntersectionPS(in FullScreenTriangleVSOutput VSOut)
320308
float3 SurfaceHitVS = ScreenXYDepthToViewSpace(SurfaceHitSS, g_Camera.mProj);
321309

322310
#if SSR_OPTION_PREVIOUS_FRAME
323-
float2 Motion = SampleMotion(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSS.xy));
311+
float2 Motion = LoadMotion(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSS.xy));
324312
float2 SurfaceHitSSPrev = SurfaceHitSS.xy - Motion;
325313
float Confidence = ValidHit ? ValidateHit(SurfaceHitSS, SurfaceHitSSPrev, ScreenCoordUV, RayDirectionWS, g_Camera.f4ViewportSize.xy, g_SSRAttribs.DepthBufferThickness) : 0.0;
326-
float3 ReflectionRadiance = Confidence > 0.0f ? SampleRadiance(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSSPrev)) : float3(0.0, 0.0, 0.0);
314+
float3 ReflectionRadiance = Confidence > 0.0f ? LoadRadiance(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSSPrev)) : float3(0.0, 0.0, 0.0);
327315
#else
328316
float Confidence = ValidHit ? ValidateHit(SurfaceHitSS, ScreenCoordUV, RayDirectionWS, g_Camera.f4ViewportSize.xy, g_SSRAttribs.DepthBufferThickness) : 0.0;
329-
float3 ReflectionRadiance = Confidence > 0.0f ? SampleRadiance(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSS.xy)) : float3(0.0, 0.0, 0.0);
317+
float3 ReflectionRadiance = Confidence > 0.0f ? LoadRadiance(int2(g_Camera.f4ViewportSize.xy * SurfaceHitSS.xy)) : float3(0.0, 0.0, 0.0);
330318
#endif
331319

332320
//TODO: Try to store inverse RayDirectionWS for more accuracy.

0 commit comments

Comments
 (0)