Skip to content

Commit 66cfd30

Browse files
SSR: reworked temporal accumulation
1 parent cbe15a3 commit 66cfd30

File tree

3 files changed

+85
-64
lines changed

3 files changed

+85
-64
lines changed

Shaders/Common/public/PostFX_Common.fxh

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -144,24 +144,16 @@ float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,
144144
int MipLevel,
145145
float4x4 Proj)
146146
{
147-
Location -= float2(0.5, 0.5);
147+
int4 FetchCoords;
148+
float4 Weights;
149+
GetBilinearSamplingInfoUC(Location, Dimensions, FetchCoords, Weights);
150+
151+
float Z00 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.xy, MipLevel)), Proj);
152+
float Z10 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.zy, MipLevel)), Proj);
153+
float Z01 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.xw, MipLevel)), Proj);
154+
float Z11 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.zw, MipLevel)), Proj);
148155

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);
156+
return dot(float4(Z00, Z10, Z01, Z11), Weights);
165157
}
166158

167159
float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,

Shaders/Common/public/ShaderUtilities.fxh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,37 @@ void BasisFromNormal(in float3 N,
108108
T = normalize(cross(N, abs(N.y) > 0.5 ? float3(1.0, 0.0, 0.0) : float3(0.0, 1.0, 0.0)));
109109
B = cross(T, N);
110110
}
111+
112+
/// Returns bilinear sampling information for unnormailzed coordinates.
113+
///
114+
/// \param [in] Location - Unnormalized location in the texture space.
115+
/// \param [in] Dimensions - Texture dimensions.
116+
/// \param [out] FetchCoords - Texture coordinates to fetch the data from:
117+
/// (x, y) - lower left corner
118+
/// (z, w) - upper right corner
119+
/// \param [out] Weights - Bilinear interpolation weights.
120+
///
121+
/// \remarks The filtering should be done as follows:
122+
/// Tex.Load(FetchCoords.xy) * Weights.x +
123+
/// Tex.Load(FetchCoords.zy) * Weights.y +
124+
/// Tex.Load(FetchCoords.xw) * Weights.z +
125+
/// Tex.Load(FetchCoords.zw) * Weights.w
126+
void GetBilinearSamplingInfoUC(in float2 Location,
127+
in int2 Dimensions,
128+
out int4 FetchCoords,
129+
out float4 Weights)
130+
{
131+
Location -= float2(0.5, 0.5);
132+
float2 Location00 = floor(Location);
133+
134+
FetchCoords.xy = int2(Location00);
135+
FetchCoords.zw = FetchCoords.xy + int2(1, 1);
136+
Dimensions -= int2(1, 1);
137+
FetchCoords = clamp(FetchCoords, int4(0, 0, 0, 0), Dimensions.xyxy);
138+
139+
float x = Location.x - Location00.x;
140+
float y = Location.y - Location00.y;
141+
Weights = float4(1.0 - x, x, 1.0 - x, x) * float4(1.0 - y, 1.0 - y, y, y);
142+
}
143+
111144
#endif //_SHADER_UTILITIES_FXH_

Shaders/PostProcess/ScreenSpaceReflection/private/SSR_ComputeTemporalAccumulation.fx

Lines changed: 43 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -161,64 +161,60 @@ ProjectionDesc ComputeReprojection(float2 PrevPos, float CurrDepth)
161161
g_TextureCurrDepth.GetDimensions(DepthDim.x, DepthDim.y);
162162
if (!Desc.IsSuccess)
163163
{
164-
float Disocclusion = 0.0;
165-
const int SearchRadius = 1;
164+
float4 BestWeights = float4(0.0, 0.0, 0.0, 0.0);
165+
int4 BestFetchCoords = int4(0, 0, 0, 0);
166+
float BestTotalWeight = 0.0;
167+
168+
const int SearchRadius = 1;
169+
const float BestTotalWeightEarlyExitThreshold = 0.9;
166170
for (int y = -SearchRadius; y <= SearchRadius; y++)
167171
{
168172
for (int x = -SearchRadius; x <= SearchRadius; x++)
169173
{
170-
float2 Location = PrevPos + float2(x, y);
171-
float PrevCameraZ = SampleCameraZFromDepthUC(g_TexturePrevDepth, DepthDim, Location, 0, g_PrevCamera.mProj);
172-
float Weight = ComputeDisocclusion(CurrCamZ, PrevCameraZ);
173-
if (Weight > Disocclusion)
174+
float2 Location = PrevPos + float2(x, y);
175+
176+
int4 FetchCoords;
177+
float4 Weights;
178+
GetBilinearSamplingInfoUC(Location, DepthDim, FetchCoords, Weights);
179+
180+
float PrevZ00 = DepthToCameraZ(LoadPrevDepth(FetchCoords.xy), g_PrevCamera.mProj);
181+
float PrevZ10 = DepthToCameraZ(LoadPrevDepth(FetchCoords.zy), g_PrevCamera.mProj);
182+
float PrevZ01 = DepthToCameraZ(LoadPrevDepth(FetchCoords.xw), g_PrevCamera.mProj);
183+
float PrevZ11 = DepthToCameraZ(LoadPrevDepth(FetchCoords.zw), g_PrevCamera.mProj);
184+
185+
Weights.x *= ComputeDisocclusion(CurrCamZ, PrevZ00) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
186+
Weights.y *= ComputeDisocclusion(CurrCamZ, PrevZ10) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
187+
Weights.z *= ComputeDisocclusion(CurrCamZ, PrevZ01) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
188+
Weights.w *= ComputeDisocclusion(CurrCamZ, PrevZ11) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
189+
190+
float TotalWeight = dot(Weights, float4(1.0, 1.0, 1.0, 1.0));
191+
if (TotalWeight > BestTotalWeight)
174192
{
175-
Disocclusion = Weight;
176-
Desc.PrevCoord = Location;
193+
BestTotalWeight = TotalWeight;
194+
BestWeights = Weights;
195+
BestFetchCoords = FetchCoords;
196+
Desc.PrevCoord = Location;
197+
198+
if (BestTotalWeight > BestTotalWeightEarlyExitThreshold)
199+
break;
177200
}
178201
}
202+
203+
if (BestTotalWeight > BestTotalWeightEarlyExitThreshold)
204+
break;
179205
}
180206

181-
Desc.IsSuccess = Disocclusion > SSR_DISOCCLUSION_THRESHOLD;
182-
Desc.Color = SamplePrevRadianceLinear(Desc.PrevCoord);
183-
}
184-
185-
if (!Desc.IsSuccess)
186-
{
187-
float2 PrevCoord = Desc.PrevCoord - float2(0.5, 0.5);
188-
float2 PrevCoord00 = floor(PrevCoord);
189-
int2 PrevCoord00i = int2(PrevCoord00);
190-
float x = PrevCoord.x - PrevCoord00.x;
191-
float y = PrevCoord.y - PrevCoord00.y;
192-
193-
float Weight[4];
194-
Weight[0] = (1.0 - x) * (1.0 - y);
195-
Weight[1] = x * (1.0 - y);
196-
Weight[2] = (1.0 - x) * y;
197-
Weight[3] = x * y;
198-
199-
float WeightSum = 0.0;
200-
float WeightedCamZ = 0.0;
201-
float4 WeightedColor = float4(0.0, 0.0, 0.0, 0.0);
202-
for (int SampleIdx = 0; SampleIdx < 4; ++SampleIdx)
207+
Desc.IsSuccess = BestTotalWeight > 0.1;
208+
if (Desc.IsSuccess)
203209
{
204-
int2 Location = PrevCoord00i + int2(SampleIdx & 0x01, SampleIdx >> 1);
205-
float PrevCamZ = DepthToCameraZ(LoadPrevDepth(Location), g_PrevCamera.mProj);
206-
207-
bool IsValidSample = ComputeDisocclusion(CurrCamZ, PrevCamZ) > (SSR_DISOCCLUSION_THRESHOLD / 2.0);
208-
Weight[SampleIdx] *= float(IsValidSample);
209-
210-
WeightedColor += Weight[SampleIdx] * LoadPrevRadiance(Location);
211-
WeightedCamZ += Weight[SampleIdx] * PrevCamZ;
212-
WeightSum += Weight[SampleIdx];
210+
Desc.Color = (
211+
LoadPrevRadiance(BestFetchCoords.xy) * BestWeights.x +
212+
LoadPrevRadiance(BestFetchCoords.zy) * BestWeights.y +
213+
LoadPrevRadiance(BestFetchCoords.xw) * BestWeights.z +
214+
LoadPrevRadiance(BestFetchCoords.zw) * BestWeights.w
215+
) / BestTotalWeight;
213216
}
214-
215-
WeightSum = max(WeightSum, 1e-6);
216-
WeightedCamZ /= WeightSum;
217-
WeightedColor /= WeightSum;
218-
219-
Desc.IsSuccess = ComputeDisocclusion(CurrCamZ, WeightedCamZ) > SSR_DISOCCLUSION_THRESHOLD;
220-
Desc.Color = WeightedColor;
221-
}
217+
}
222218

223219
Desc.IsSuccess = Desc.IsSuccess && IsInsideScreen(Desc.PrevCoord, g_CurrCamera.f4ViewportSize.xy);
224220
return Desc;

0 commit comments

Comments
 (0)