Improve DDGI quality by not using lower-res cascade fallback

This commit is contained in:
Wojtek Figat
2024-06-02 23:02:20 +02:00
parent a08954f7db
commit aad428210d
2 changed files with 35 additions and 30 deletions

View File

@@ -136,43 +136,34 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
{
// Select the highest cascade that contains the sample location
uint cascadeIndex = 0;
float4 probesDatas[8];
float probesSpacing = 0;
float3 probesOrigin = (float3)0, probesExtent = (float3)0;
for (; cascadeIndex < data.CascadesCount; cascadeIndex++)
{
float probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w;
float3 probesOrigin = data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing + data.ProbesOriginAndSpacing[cascadeIndex].xyz;
float3 probesExtent = (data.ProbesCounts - 1) * (probesSpacing * 0.5f);
probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w;
probesOrigin = data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing + data.ProbesOriginAndSpacing[cascadeIndex].xyz;
probesExtent = (data.ProbesCounts - 1) * (probesSpacing * 0.5f);
float fadeDistance = probesSpacing * 0.5f;
float cascadeWeight = saturate(Min3(probesExtent - abs(worldPosition - probesOrigin)) / fadeDistance);
if (cascadeWeight > dither) // Use dither to make transition smoother
{
// Load probes state for this cascade
uint activeCount = 0;
uint3 baseProbeCoords = clamp(uint3((worldPosition - probesOrigin + probesExtent) / probesSpacing), uint3(0, 0, 0), data.ProbesCounts - uint3(1, 1, 1));
UNROLL
for (uint i = 0; i < 8; i++)
{
uint3 probeCoordsOffset = uint3(i, i >> 1, i >> 2) & 1;
uint3 probeCoords = clamp(baseProbeCoords + probeCoordsOffset, uint3(0, 0, 0), data.ProbesCounts - uint3(1, 1, 1));
uint probeIndex = GetDDGIScrollingProbeIndex(data, cascadeIndex, probeCoords);
float4 probeData = LoadDDGIProbeData(data, probesData, cascadeIndex, probeIndex);
probesDatas[i] = probeData;
uint probeState = DecodeDDGIProbeState(probeData);
if (probeState != DDGI_PROBE_STATE_INACTIVE)
activeCount++;
}
// Ensure there are some valid probes in this cascade
if (activeCount >= 3)
break;
break;
}
}
if (cascadeIndex == data.CascadesCount)
return data.FallbackIrradiance;
uint3 baseProbeCoords = clamp(uint3((worldPosition - probesOrigin + probesExtent) / probesSpacing), uint3(0, 0, 0), data.ProbesCounts - uint3(1, 1, 1));
float probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w;
float3 probesOrigin = data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing + data.ProbesOriginAndSpacing[cascadeIndex].xyz;
float3 probesExtent = (data.ProbesCounts - 1) * (probesSpacing * 0.5f);
// Load probes state for this cascade
float4 probesDatas[8];
UNROLL
for (uint i = 0; i < 8; i++)
{
uint3 probeCoordsOffset = uint3(i, i >> 1, i >> 2) & 1;
uint3 probeCoords = clamp(baseProbeCoords + probeCoordsOffset, uint3(0, 0, 0), data.ProbesCounts - uint3(1, 1, 1));
uint probeIndex = GetDDGIScrollingProbeIndex(data, cascadeIndex, probeCoords);
probesDatas[i] = LoadDDGIProbeData(data, probesData, cascadeIndex, probeIndex);
}
// Bias the world-space position to reduce artifacts
float3 viewDir = normalize(data.ViewPos - worldPosition);
@@ -180,7 +171,6 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
float3 biasedWorldPosition = worldPosition + surfaceBias;
// Get the grid coordinates of the probe nearest the biased world position
uint3 baseProbeCoords = clamp(uint3((worldPosition - probesOrigin + probesExtent) / probesSpacing), uint3(0, 0, 0), data.ProbesCounts - uint3(1, 1, 1));
float3 baseProbeWorldPosition = GetDDGIProbeWorldPosition(data, cascadeIndex, baseProbeCoords);
float3 biasAlpha = saturate((biasedWorldPosition - baseProbeWorldPosition) / probesSpacing);

View File

@@ -21,6 +21,7 @@
#define DDGI_TRACE_RAYS_LIMIT 256 // Limit of rays per-probe (runtime value can be smaller)
#define DDGI_PROBE_UPDATE_BORDERS_GROUP_SIZE 8
#define DDGI_PROBE_CLASSIFY_GROUP_SIZE 32
#define DDGI_PROBE_RELOCATE_ITERATIVE 0 // If true, probes relocation algorithm tries to move them in additive way, otherwise all nearby locations are checked to find the best position
META_CB_BEGIN(0, Data0)
DDGIData DDGI;
@@ -67,8 +68,6 @@ uint GetProbeRaysCount(DDGIData data, uint probeState)
#ifdef _CS_Classify
#define DDGI_PROBE_RELOCATE_ITERATIVE 0 // If true, probes relocation algorithm tries to move them in additive way, otherwise all nearby locations are checked to find the best position
RWTexture2D<snorm float4> RWProbesData : register(u0);
RWByteAddressBuffer RWActiveProbes : register(u1);
@@ -93,13 +92,29 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
probeIndex = GetDDGIScrollingProbeIndex(DDGI, CascadeIndex, probeCoords);
int2 probeDataCoords = GetDDGIProbeTexelCoords(DDGI, CascadeIndex, probeIndex);
float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w;
float3 probeBasePosition = GetDDGIProbeWorldPosition(DDGI, CascadeIndex, probeCoords);
// Disable probes that are is in the range of higher-quality cascade
if (CascadeIndex > 0)
{
uint prevCascade = CascadeIndex - 1;
float prevProbesSpacing = DDGI.ProbesOriginAndSpacing[prevCascade].w;
float3 prevProbesOrigin = DDGI.ProbesScrollOffsets[prevCascade].xyz * prevProbesSpacing + DDGI.ProbesOriginAndSpacing[prevCascade].xyz;
float3 prevProbesExtent = (DDGI.ProbesCounts - 1) * (prevProbesSpacing * 0.5f);
float prevCascadeWeight = Min3(prevProbesExtent - abs(probeBasePosition - prevProbesOrigin));
if (prevCascadeWeight > 0.1f)
{
// Disable probe
RWProbesData[probeDataCoords] = EncodeDDGIProbeData(float3(0, 0, 0), DDGI_PROBE_STATE_INACTIVE);
return;
}
}
// Load probe state and position
float4 probeData = RWProbesData[probeDataCoords];
uint probeState = DecodeDDGIProbeState(probeData);
float3 probeOffset = probeData.xyz * probesSpacing; // Probe offset is [-1;1] within probes spacing
float3 probeOffsetOld = probeOffset;
float3 probeBasePosition = GetDDGIProbeWorldPosition(DDGI, CascadeIndex, probeCoords);
float3 probePosition = probeBasePosition;
#if DDGI_PROBE_RELOCATE_ITERATIVE
probePosition += probeOffset;