@@ -426,7 +426,6 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
|
||||
// Shift the volume origin based on scroll offsets for each axis once it overflows
|
||||
for (int32 axis = 0; axis < 3; axis++)
|
||||
{
|
||||
// different volume scroll that preserves the scroll offset delta relative to the probe count
|
||||
const int32 probeCount = ddgiData.ProbeCounts.Raw[axis];
|
||||
int32& scrollOffset = cascade.ProbeScrollOffsets.Raw[axis];
|
||||
while (scrollOffset >= probeCount)
|
||||
|
||||
@@ -148,13 +148,12 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
float fadeDistance = probesSpacing * 0.5f;
|
||||
float cascadeWeight = saturate(Min3(probesExtent - abs(worldPosition - probesOrigin)) / fadeDistance);
|
||||
if (cascadeWeight > dither) // Use dither to make transition smoother
|
||||
{
|
||||
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));
|
||||
uint3 probeCoordsEnd = data.ProbesCounts - uint3(1, 1, 1);
|
||||
uint3 baseProbeCoords = clamp(uint3((worldPosition - probesOrigin + probesExtent) / probesSpacing), uint3(0, 0, 0), probeCoordsEnd);
|
||||
|
||||
// Bias the world-space position to reduce artifacts
|
||||
float3 viewDir = normalize(data.ViewPos - worldPosition);
|
||||
@@ -167,17 +166,40 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
|
||||
// Loop over the closest probes to accumulate their contributions
|
||||
float4 irradiance = float4(0, 0, 0, 0);
|
||||
const int3 SearchAxisMasks[3] = { int3(1, 0, 0), int3(0, 1, 0), int3(0, 0, 1) };
|
||||
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));
|
||||
uint3 probeCoords = clamp(baseProbeCoords + probeCoordsOffset, uint3(0, 0, 0), probeCoordsEnd);
|
||||
uint probeIndex = GetDDGIScrollingProbeIndex(data, cascadeIndex, probeCoords);
|
||||
|
||||
// Load probe position and state
|
||||
float4 probeData = LoadDDGIProbeData(data, probesData, cascadeIndex, probeIndex);
|
||||
uint probeState = DecodeDDGIProbeState(probeData);
|
||||
if (probeState == DDGI_PROBE_STATE_INACTIVE)
|
||||
continue;
|
||||
{
|
||||
// Search nearby probes to find any nearby GI sample
|
||||
for (int searchDistance = 1; searchDistance < 3 && probeState == DDGI_PROBE_STATE_INACTIVE; searchDistance++)
|
||||
for (uint searchAxis = 0; searchAxis < 3; searchAxis++)
|
||||
{
|
||||
int searchAxisDir = probeCoordsOffset[searchAxis] ? 1 : -1;
|
||||
int3 searchCoordsOffset = SearchAxisMasks[searchAxis] * searchAxisDir * searchDistance;
|
||||
uint3 searchCoords = clamp((int3)probeCoords + searchCoordsOffset, int3(0, 0, 0), (int3)probeCoordsEnd);
|
||||
uint searchIndex = GetDDGIScrollingProbeIndex(data, cascadeIndex, searchCoords);
|
||||
float4 searchData = LoadDDGIProbeData(data, probesData, cascadeIndex, searchIndex);
|
||||
uint searchState = DecodeDDGIProbeState(searchData);
|
||||
if (searchState != DDGI_PROBE_STATE_INACTIVE)
|
||||
{
|
||||
// Use nearby probe as a fallback (visibility test might ignore it but with smooth gradient)
|
||||
probeCoords = searchCoords;
|
||||
probeIndex = searchIndex;
|
||||
probeData = searchData;
|
||||
probeState = searchState;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (probeState == DDGI_PROBE_STATE_INACTIVE) continue;
|
||||
}
|
||||
float3 probeBasePosition = baseProbeWorldPosition + ((probeCoords - baseProbeCoords) * probesSpacing);
|
||||
float3 probePosition = probeBasePosition + probeData.xyz * probesSpacing; // Probe offset is [-1;1] within probes spacing
|
||||
|
||||
@@ -193,15 +215,13 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
float2 octahedralCoords = GetOctahedralCoords(-biasedPosToProbe);
|
||||
float2 uv = GetDDGIProbeUV(data, cascadeIndex, probeIndex, octahedralCoords, DDGI_PROBE_RESOLUTION_DISTANCE);
|
||||
float2 probeDistance = probesDistance.SampleLevel(SamplerLinearClamp, uv, 0).rg * 2.0f;
|
||||
float probeDistanceMean = probeDistance.x;
|
||||
|
||||
// Visibility weight (Chebyshev)
|
||||
if (biasedPosToProbeDist > probeDistanceMean)
|
||||
if (biasedPosToProbeDist > probeDistance.x)
|
||||
{
|
||||
float probeDistanceMean2 = probeDistance.y;
|
||||
float probeDistanceVariance = abs(Square(probeDistanceMean) - probeDistanceMean2);
|
||||
float chebyshevWeight = probeDistanceVariance / (probeDistanceVariance + Square(biasedPosToProbeDist - probeDistanceMean));
|
||||
weight *= max(chebyshevWeight * chebyshevWeight * chebyshevWeight, 0.05f);
|
||||
float variance = abs(Square(probeDistance.x) - probeDistance.y);
|
||||
float visibilityWeight = variance / (variance + Square(biasedPosToProbeDist - probeDistance.x));
|
||||
weight *= max(visibilityWeight * visibilityWeight * visibilityWeight, 0.05f);
|
||||
}
|
||||
|
||||
// Avoid a weight of zero
|
||||
@@ -209,8 +229,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
|
||||
// Adjust weight curve to inject a small portion of light
|
||||
const float minWeightThreshold = 0.2f;
|
||||
if (weight < minWeightThreshold)
|
||||
weight *= weight * weight * (1.0f / (minWeightThreshold * minWeightThreshold));
|
||||
if (weight < minWeightThreshold) weight *= Square(weight) / Square(minWeightThreshold);
|
||||
|
||||
// Calculate trilinear weights based on the distance to each probe to smoothly transition between grid of 8 probes
|
||||
float3 trilinear = lerp(1.0f - biasAlpha, biasAlpha, (float3)probeCoordsOffset);
|
||||
@@ -246,7 +265,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, T
|
||||
if (irradiance.a > 0.0f)
|
||||
{
|
||||
// Normalize irradiance
|
||||
irradiance.rgb *= 1.0f / irradiance.a;
|
||||
irradiance.rgb /= irradiance.a;
|
||||
#if DDGI_SRGB_BLENDING
|
||||
irradiance.rgb *= irradiance.rgb;
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
// This must match C++
|
||||
#define DDGI_TRACE_RAYS_PROBES_COUNT_LIMIT 4096 // Maximum amount of probes to update at once during rays tracing and blending
|
||||
#define DDGI_TRACE_RAYS_LIMIT 256 // Limit of rays per-probe (runtime value can be smaller)
|
||||
#define DDGI_TRACE_NEGATIVE 0 // If true, rays that start inside geometry will use negative distance to indicate backface hit
|
||||
#define DDGI_PROBE_UPDATE_BORDERS_GROUP_SIZE 8
|
||||
#define DDGI_PROBE_CLASSIFY_GROUP_SIZE 32
|
||||
#define DDGI_PROBE_RELOCATE_ITERATIVE 1 // If true, probes relocation algorithm tries to move them in additive way, otherwise all nearby locations are checked to find the best position
|
||||
@@ -146,9 +147,9 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float sdfDst = abs(sdf);
|
||||
const float ProbesDistanceLimits[4] = { 1.1f, 2.3f, 2.5f, 2.5f };
|
||||
const float ProbesRelocateLimits[4] = { 0.4f, 0.5f, 0.6f, 0.7f };
|
||||
float voxelLimit = GlobalSDF.CascadeVoxelSize[CascadeIndex];
|
||||
float distanceLimit = length(probesSpacing) * ProbesDistanceLimits[CascadeIndex];
|
||||
float relocateLimit = length(probesSpacing) * ProbesRelocateLimits[CascadeIndex];
|
||||
float voxelLimit = GlobalSDF.CascadeVoxelSize[CascadeIndex] * 0.8f;
|
||||
float distanceLimit = probesSpacing * ProbesDistanceLimits[CascadeIndex];
|
||||
float relocateLimit = probesSpacing * ProbesRelocateLimits[CascadeIndex];
|
||||
if (sdfDst > distanceLimit + length(probeOffset)) // Probe is too far from geometry (or deep inside)
|
||||
{
|
||||
// Disable it
|
||||
@@ -317,12 +318,14 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
float4 radiance;
|
||||
if (hit.IsHit())
|
||||
{
|
||||
/*if (hit.HitSDF <= 0.0f && hit.HitTime <= GlobalSDF.CascadeVoxelSize[0])
|
||||
#if DDGI_TRACE_NEGATIVE
|
||||
if (hit.HitSDF <= 0.0f && hit.HitTime <= GlobalSDF.CascadeVoxelSize[0])
|
||||
{
|
||||
// Ray starts inside geometry (mark as negative distance and reduce it's influence during irradiance blending)
|
||||
radiance = float4(0, 0, 0, hit.HitTime * -0.25f);
|
||||
}
|
||||
else*/
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Sample Global Surface Atlas to get the lighting at the hit location
|
||||
float3 hitPosition = hit.GetHitPosition(trace);
|
||||
@@ -393,7 +396,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
|
||||
uint backfacesLimit = uint(probeRaysCount * 0.1f);
|
||||
#else
|
||||
float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w;
|
||||
float distanceLimit = length(probesSpacing) * 1.5f;
|
||||
float distanceLimit = probesSpacing * 1.5f;
|
||||
#endif
|
||||
|
||||
BRANCH
|
||||
@@ -435,6 +438,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
|
||||
|
||||
#if DDGI_PROBE_UPDATE_MODE == 0
|
||||
float4 rayRadiance = CachedProbesTraceRadiance[rayIndex];
|
||||
#if DDGI_TRACE_NEGATIVE
|
||||
if (rayRadiance.w < 0.0f)
|
||||
{
|
||||
// Count backface hits
|
||||
@@ -448,6 +452,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add radiance (RGB) and weight (A)
|
||||
result += float4(rayRadiance.rgb * rayWeight, rayWeight);
|
||||
|
||||
Reference in New Issue
Block a user