Skip to content

Commit

Permalink
SSR: reworked temporal accumulation
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Jan 13, 2025
1 parent cbe15a3 commit 66cfd30
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 64 deletions.
26 changes: 9 additions & 17 deletions Shaders/Common/public/PostFX_Common.fxh
Original file line number Diff line number Diff line change
Expand Up @@ -144,24 +144,16 @@ float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,
int MipLevel,
float4x4 Proj)
{
Location -= float2(0.5, 0.5);
int4 FetchCoords;
float4 Weights;
GetBilinearSamplingInfoUC(Location, Dimensions, FetchCoords, Weights);

float Z00 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.xy, MipLevel)), Proj);
float Z10 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.zy, MipLevel)), Proj);
float Z01 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.xw, MipLevel)), Proj);
float Z11 = DepthToCameraZ(DepthBuffer.Load(int3(FetchCoords.zw, MipLevel)), Proj);

float2 Location00 = floor(Location);
float2 Weights = Location - Location00;

int i0 = clamp(int(Location00.x), 0, Dimensions.x - 1);
int j0 = clamp(int(Location00.y), 0, Dimensions.y - 1);
int i1 = clamp(int(Location00.x) + 1, 0, Dimensions.x - 1);
int j1 = clamp(int(Location00.y) + 1, 0, Dimensions.y - 1);

float Z00 = DepthToCameraZ(DepthBuffer.Load(int3(i0, j0, MipLevel)), Proj);
float Z10 = DepthToCameraZ(DepthBuffer.Load(int3(i1, j0, MipLevel)), Proj);
float Z01 = DepthToCameraZ(DepthBuffer.Load(int3(i0, j1, MipLevel)), Proj);
float Z11 = DepthToCameraZ(DepthBuffer.Load(int3(i1, j1, MipLevel)), Proj);

return lerp(lerp(Z00, Z10, Weights.x),
lerp(Z01, Z11, Weights.x),
Weights.y);
return dot(float4(Z00, Z10, Z01, Z11), Weights);
}

float SampleCameraZFromDepthUC(Texture2D<float> DepthBuffer,
Expand Down
33 changes: 33 additions & 0 deletions Shaders/Common/public/ShaderUtilities.fxh
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,37 @@ void BasisFromNormal(in float3 N,
T = normalize(cross(N, abs(N.y) > 0.5 ? float3(1.0, 0.0, 0.0) : float3(0.0, 1.0, 0.0)));
B = cross(T, N);
}

/// Returns bilinear sampling information for unnormailzed coordinates.
///
/// \param [in] Location - Unnormalized location in the texture space.
/// \param [in] Dimensions - Texture dimensions.
/// \param [out] FetchCoords - Texture coordinates to fetch the data from:
/// (x, y) - lower left corner
/// (z, w) - upper right corner
/// \param [out] Weights - Bilinear interpolation weights.
///
/// \remarks The filtering should be done as follows:
/// Tex.Load(FetchCoords.xy) * Weights.x +
/// Tex.Load(FetchCoords.zy) * Weights.y +
/// Tex.Load(FetchCoords.xw) * Weights.z +
/// Tex.Load(FetchCoords.zw) * Weights.w
void GetBilinearSamplingInfoUC(in float2 Location,
in int2 Dimensions,
out int4 FetchCoords,
out float4 Weights)
{
Location -= float2(0.5, 0.5);
float2 Location00 = floor(Location);

FetchCoords.xy = int2(Location00);
FetchCoords.zw = FetchCoords.xy + int2(1, 1);
Dimensions -= int2(1, 1);
FetchCoords = clamp(FetchCoords, int4(0, 0, 0, 0), Dimensions.xyxy);

float x = Location.x - Location00.x;
float y = Location.y - Location00.y;
Weights = float4(1.0 - x, x, 1.0 - x, x) * float4(1.0 - y, 1.0 - y, y, y);
}

#endif //_SHADER_UTILITIES_FXH_
Original file line number Diff line number Diff line change
Expand Up @@ -161,64 +161,60 @@ ProjectionDesc ComputeReprojection(float2 PrevPos, float CurrDepth)
g_TextureCurrDepth.GetDimensions(DepthDim.x, DepthDim.y);
if (!Desc.IsSuccess)
{
float Disocclusion = 0.0;
const int SearchRadius = 1;
float4 BestWeights = float4(0.0, 0.0, 0.0, 0.0);
int4 BestFetchCoords = int4(0, 0, 0, 0);
float BestTotalWeight = 0.0;

const int SearchRadius = 1;
const float BestTotalWeightEarlyExitThreshold = 0.9;
for (int y = -SearchRadius; y <= SearchRadius; y++)
{
for (int x = -SearchRadius; x <= SearchRadius; x++)
{
float2 Location = PrevPos + float2(x, y);
float PrevCameraZ = SampleCameraZFromDepthUC(g_TexturePrevDepth, DepthDim, Location, 0, g_PrevCamera.mProj);
float Weight = ComputeDisocclusion(CurrCamZ, PrevCameraZ);
if (Weight > Disocclusion)
float2 Location = PrevPos + float2(x, y);

int4 FetchCoords;
float4 Weights;
GetBilinearSamplingInfoUC(Location, DepthDim, FetchCoords, Weights);

float PrevZ00 = DepthToCameraZ(LoadPrevDepth(FetchCoords.xy), g_PrevCamera.mProj);
float PrevZ10 = DepthToCameraZ(LoadPrevDepth(FetchCoords.zy), g_PrevCamera.mProj);
float PrevZ01 = DepthToCameraZ(LoadPrevDepth(FetchCoords.xw), g_PrevCamera.mProj);
float PrevZ11 = DepthToCameraZ(LoadPrevDepth(FetchCoords.zw), g_PrevCamera.mProj);

Weights.x *= ComputeDisocclusion(CurrCamZ, PrevZ00) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
Weights.y *= ComputeDisocclusion(CurrCamZ, PrevZ10) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
Weights.z *= ComputeDisocclusion(CurrCamZ, PrevZ01) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;
Weights.w *= ComputeDisocclusion(CurrCamZ, PrevZ11) > (SSR_DISOCCLUSION_THRESHOLD / 2.0) ? 1.0 : 0.0;

float TotalWeight = dot(Weights, float4(1.0, 1.0, 1.0, 1.0));
if (TotalWeight > BestTotalWeight)
{
Disocclusion = Weight;
Desc.PrevCoord = Location;
BestTotalWeight = TotalWeight;
BestWeights = Weights;
BestFetchCoords = FetchCoords;
Desc.PrevCoord = Location;

if (BestTotalWeight > BestTotalWeightEarlyExitThreshold)
break;
}
}

if (BestTotalWeight > BestTotalWeightEarlyExitThreshold)
break;
}

Desc.IsSuccess = Disocclusion > SSR_DISOCCLUSION_THRESHOLD;
Desc.Color = SamplePrevRadianceLinear(Desc.PrevCoord);
}

if (!Desc.IsSuccess)
{
float2 PrevCoord = Desc.PrevCoord - float2(0.5, 0.5);
float2 PrevCoord00 = floor(PrevCoord);
int2 PrevCoord00i = int2(PrevCoord00);
float x = PrevCoord.x - PrevCoord00.x;
float y = PrevCoord.y - PrevCoord00.y;

float Weight[4];
Weight[0] = (1.0 - x) * (1.0 - y);
Weight[1] = x * (1.0 - y);
Weight[2] = (1.0 - x) * y;
Weight[3] = x * y;

float WeightSum = 0.0;
float WeightedCamZ = 0.0;
float4 WeightedColor = float4(0.0, 0.0, 0.0, 0.0);
for (int SampleIdx = 0; SampleIdx < 4; ++SampleIdx)
Desc.IsSuccess = BestTotalWeight > 0.1;
if (Desc.IsSuccess)
{
int2 Location = PrevCoord00i + int2(SampleIdx & 0x01, SampleIdx >> 1);
float PrevCamZ = DepthToCameraZ(LoadPrevDepth(Location), g_PrevCamera.mProj);

bool IsValidSample = ComputeDisocclusion(CurrCamZ, PrevCamZ) > (SSR_DISOCCLUSION_THRESHOLD / 2.0);
Weight[SampleIdx] *= float(IsValidSample);

WeightedColor += Weight[SampleIdx] * LoadPrevRadiance(Location);
WeightedCamZ += Weight[SampleIdx] * PrevCamZ;
WeightSum += Weight[SampleIdx];
Desc.Color = (
LoadPrevRadiance(BestFetchCoords.xy) * BestWeights.x +
LoadPrevRadiance(BestFetchCoords.zy) * BestWeights.y +
LoadPrevRadiance(BestFetchCoords.xw) * BestWeights.z +
LoadPrevRadiance(BestFetchCoords.zw) * BestWeights.w
) / BestTotalWeight;
}

WeightSum = max(WeightSum, 1e-6);
WeightedCamZ /= WeightSum;
WeightedColor /= WeightSum;

Desc.IsSuccess = ComputeDisocclusion(CurrCamZ, WeightedCamZ) > SSR_DISOCCLUSION_THRESHOLD;
Desc.Color = WeightedColor;
}
}

Desc.IsSuccess = Desc.IsSuccess && IsInsideScreen(Desc.PrevCoord, g_CurrCamera.f4ViewportSize.xy);
return Desc;
Expand Down

0 comments on commit 66cfd30

Please sign in to comment.