Add improved fallback GI outside the DDGI range to use a special ambient probe for stability
This commit is contained in:
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
#define DDGI_FALLBACK_COORDS_ENCODE(coord) ((float3)(coord + 1) / 128.0f)
|
||||
#define DDGI_FALLBACK_COORDS_DECODE(data) (uint3)(data.xyz * 128.0f - 1)
|
||||
#define DDGI_FALLBACK_COORDS_VALID(data) (length(data.xyz) > 0)
|
||||
#define DDGI_FALLBACK_OUTER_DEDICATED_PROBE 1 // Enables using a special probe at (0, 0, 0) of the last cascade to be used for ambient GI on far pixels outside the DDGI range
|
||||
//#define DDGI_DEBUG_CASCADE 0 // Forces a specific cascade to be only in use (for debugging)
|
||||
|
||||
// DDGI data for a constant buffer
|
||||
@@ -166,6 +167,21 @@ float3 SampleDDGIIrradianceCascade(DDGIData data, Texture2D<snorm float4> probes
|
||||
{
|
||||
bool invalidCascade = cascadeIndex >= data.CascadesCount;
|
||||
cascadeIndex = min(cascadeIndex, data.CascadesCount - 1);
|
||||
#if DDGI_FALLBACK_OUTER_DEDICATED_PROBE
|
||||
if (invalidCascade)
|
||||
{
|
||||
// Sample a special probe as a fallback for ambient GI outside the last cascade
|
||||
float2 octahedralCoords = GetOctahedralCoords(worldNormal);
|
||||
float2 uv = GetDDGIProbeUV(data, cascadeIndex, 0, octahedralCoords, DDGI_PROBE_RESOLUTION_IRRADIANCE);
|
||||
float3 probeIrradiance = probesIrradiance.SampleLevel(SamplerLinearClamp, uv, 0).rgb;
|
||||
#if DDGI_SRGB_BLENDING
|
||||
probeIrradiance = pow(probeIrradiance, data.IrradianceGamma * 0.5f);
|
||||
probeIrradiance *= probeIrradiance;
|
||||
#endif
|
||||
probeIrradiance *= 2.0f * PI;
|
||||
return probeIrradiance;
|
||||
}
|
||||
#endif
|
||||
uint3 probeCoordsEnd = data.ProbesCounts - uint3(1, 1, 1);
|
||||
uint3 baseProbeCoords = clamp(uint3((worldPosition - probesOrigin + probesExtent) / probesSpacing), uint3(0, 0, 0), probeCoordsEnd);
|
||||
|
||||
@@ -258,8 +274,10 @@ float3 SampleDDGIIrradianceCascade(DDGIData data, Texture2D<snorm float4> probes
|
||||
irradiance = float4(0, 1, 0, 1);
|
||||
else if (cascadeIndex == 2)
|
||||
irradiance = float4(0, 0, 1, 1);
|
||||
else
|
||||
else if (invalidCascade) // Area outside the last cascade that clamps to it
|
||||
irradiance = float4(1, 0, 1, 1);
|
||||
else
|
||||
irradiance = float4(0, 1, 1, 1);
|
||||
#endif
|
||||
|
||||
if (irradiance.a > 0.0f)
|
||||
@@ -267,7 +285,11 @@ float3 SampleDDGIIrradianceCascade(DDGIData data, Texture2D<snorm float4> probes
|
||||
// Normalize irradiance
|
||||
//irradiance.rgb /= irradiance.a;
|
||||
//irradiance.rgb /= lerp(1, irradiance.a, saturate(irradiance.a * irradiance.a + 0.9f));
|
||||
#if DDGI_FALLBACK_OUTER_DEDICATED_PROBE
|
||||
irradiance.rgb /= lerp(1, irradiance.a, saturate(irradiance.a * irradiance.a + 0.9f));
|
||||
#else
|
||||
irradiance.rgb /= invalidCascade ? irradiance.a : lerp(1, irradiance.a, saturate(irradiance.a * irradiance.a + 0.9f));
|
||||
#endif
|
||||
#if DDGI_SRGB_BLENDING
|
||||
irradiance.rgb *= irradiance.rgb;
|
||||
#endif
|
||||
@@ -331,13 +353,15 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
// Blend with the next cascade (or fallback irradiance outside the volume)
|
||||
#if DDGI_CASCADE_BLEND_SMOOTH && !defined(DDGI_DEBUG_CASCADE)
|
||||
cascadeIndex++;
|
||||
if (cascadeIndex < data.CascadesCount && cascadeWeight < 0.99f)
|
||||
if (cascadeIndex <= data.CascadesCount && cascadeWeight < 0.99f)
|
||||
{
|
||||
uint cascadeIndexTmp = cascadeIndex;
|
||||
cascadeIndex = min(cascadeIndex, data.CascadesCount - 1);
|
||||
probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w;
|
||||
probesOrigin = data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing + data.ProbesOriginAndSpacing[cascadeIndex].xyz;
|
||||
probesExtent = (data.ProbesCounts - 1) * (probesSpacing * 0.5f);
|
||||
biasedWorldPosition = worldPosition + GetDDGISurfaceBias(viewDir, probesSpacing, worldNormal, bias);
|
||||
float3 resultNext = SampleDDGIIrradianceCascade(data, probesData, probesDistance, probesIrradiance, worldPosition, worldNormal, cascadeIndex, probesOrigin, probesExtent, probesSpacing, biasedWorldPosition);
|
||||
float3 resultNext = SampleDDGIIrradianceCascade(data, probesData, probesDistance, probesIrradiance, worldPosition, worldNormal, cascadeIndexTmp, probesOrigin, probesExtent, probesSpacing, biasedWorldPosition);
|
||||
result *= cascadeWeight;
|
||||
result += resultNext * (1 - cascadeWeight);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define DDGI_PROBE_EMPTY_AREA_DENSITY 8 // Spacing (in probe grid) between fallback probes placed into empty areas to provide valid GI for nearby dynamic objects or transparency
|
||||
#define DDGI_DEBUG_STATS 0 // Enables additional GPU-driven stats for probe/rays count
|
||||
#define DDGI_DEBUG_INSTABILITY 0 // Enables additional probe irradiance instability debugging
|
||||
#define DDGI_SKY_DISTANCE 1e27f // Sky is the limit
|
||||
|
||||
META_CB_BEGIN(0, Data0)
|
||||
DDGIData DDGI;
|
||||
@@ -191,21 +192,51 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float relocateLimit = probesSpacing * ProbesRelocateLimits[CascadeIndex];
|
||||
#ifdef DDGI_PROBE_EMPTY_AREA_DENSITY
|
||||
uint3 probeCoordsStable = GetDDGIProbeCoords(DDGI, probeIndex);
|
||||
#endif
|
||||
|
||||
// Classify probe based on previous state and neighborhood
|
||||
#if DDGI_FALLBACK_OUTER_DEDICATED_PROBE
|
||||
if (CascadeIndex == DDGI.CascadesCount - 1 && probeIndex == 0)
|
||||
{
|
||||
// Special probe as a fallback for ambient GI outside the last cascade
|
||||
probeOffset = float3(0, 0, 0);
|
||||
if (probeStateOld == DDGI_PROBE_STATE_INACTIVE)
|
||||
{
|
||||
probeState = DDGI_PROBE_STATE_ACTIVATED;
|
||||
probeAttention = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
probeState = DDGI_PROBE_STATE_ACTIVE;
|
||||
probeAttention = 0.5f;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef DDGI_PROBE_EMPTY_AREA_DENSITY
|
||||
if (sdf > probesSpacing * DDGI.ProbesCounts.x * 0.3f
|
||||
#if DDGI_PROBE_EMPTY_AREA_DENSITY > 1
|
||||
&& (
|
||||
// Low-density grid grid
|
||||
(probeCoordsStable.x % DDGI_PROBE_EMPTY_AREA_DENSITY == 0 && probeCoordsStable.y % DDGI_PROBE_EMPTY_AREA_DENSITY == 0 && probeCoordsStable.z % DDGI_PROBE_EMPTY_AREA_DENSITY == 0)
|
||||
// Edge probes at the last cascade (for good fallback irradiance outside the GI distance)
|
||||
// Edge probes at the last cascade (for good fallback irradiance outside the GI distance) - not needed anymore as DDGI_FALLBACK_OUTER_DEDICATED_PROBE does a far better job
|
||||
//|| (CascadeIndex + 1 == DDGI.CascadesCount && IsProbeAtBorder(probeCoords))
|
||||
)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Addd some fallback probes in empty areas to provide valid GI for nearby dynamic objects or transparency
|
||||
// Add some fallback probes in empty areas to provide valid GI for nearby dynamic objects or transparency
|
||||
probeOffset = float3(0, 0, 0);
|
||||
probeState = wasScrolled || probeStateOld == DDGI_PROBE_STATE_INACTIVE ? DDGI_PROBE_STATE_ACTIVATED : DDGI_PROBE_STATE_ACTIVE;
|
||||
probeAttention = DDGI_PROBE_ATTENTION_MIN;
|
||||
if (wasScrolled || probeStateOld == DDGI_PROBE_STATE_INACTIVE)
|
||||
{
|
||||
probeState = DDGI_PROBE_STATE_ACTIVATED;
|
||||
probeAttention = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
probeState = DDGI_PROBE_STATE_ACTIVE;
|
||||
probeAttention = DDGI_PROBE_ATTENTION_MIN;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -479,6 +510,15 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex, probeRaysCount, probeIndex, probeCoords);
|
||||
// TODO: implement ray-guiding based on the probe irradiance (prioritize directions with high luminance)
|
||||
|
||||
#if DDGI_FALLBACK_OUTER_DEDICATED_PROBE
|
||||
if (CascadeIndex == DDGI.CascadesCount - 1 && probeIndex == 0)
|
||||
{
|
||||
// Special probe as a fallback for ambient GI outside the last cascade
|
||||
RWProbesTrace[uint2(rayIndex, DispatchThreadId.x)] = float4(Skybox.SampleLevel(SamplerLinearClamp, probeRayDirection, 0).rgb * SkyboxIntensity, DDGI_SKY_DISTANCE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Trace ray with Global SDF
|
||||
GlobalSDFTrace trace;
|
||||
trace.Init(probePosition, probeRayDirection, 0.0f, DDGI.RayMaxDistance);
|
||||
@@ -513,7 +553,7 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
// Ray hits sky
|
||||
radiance.rgb = Skybox.SampleLevel(SamplerLinearClamp, probeRayDirection, 0).rgb * SkyboxIntensity;
|
||||
radiance.a = 1e27f; // Sky is the limit
|
||||
radiance.a = DDGI_SKY_DISTANCE;
|
||||
}
|
||||
|
||||
// Write into probes trace results
|
||||
|
||||
Reference in New Issue
Block a user