Refactor DDGI probes to use variable ray count depending on the probe location relative to the view frustum

This commit is contained in:
Wojciech Figat
2022-12-15 17:33:44 +01:00
parent 3fcbcacd43
commit 1cf6c5233e
13 changed files with 106 additions and 89 deletions

Binary file not shown.

BIN
Content/Shaders/GI/DDGI.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/GI/GlobalSurfaceAtlas.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/VolumetricFog.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -170,7 +170,7 @@ bool GlobalIlluminationFeature::Bind(MaterialShader::BindParameters& params, Spa
// Bind DDGI data
data.DDGI = bindingDataDDGI.Constants;
params.GPUContext->BindSR(srv + 0, bindingDataDDGI.ProbesState);
params.GPUContext->BindSR(srv + 0, bindingDataDDGI.ProbesData);
params.GPUContext->BindSR(srv + 1, bindingDataDDGI.ProbesDistance);
params.GPUContext->BindSR(srv + 2, bindingDataDDGI.ProbesIrradiance);
}

View File

@@ -87,7 +87,7 @@ public:
int32 ProbesCountTotal = 0;
Int3 ProbeCounts = Int3::Zero;
GPUTexture* ProbesTrace = nullptr; // Probes ray tracing: (RGB: hit radiance, A: hit distance)
GPUTexture* ProbesState = nullptr; // Probes state: (RGB: world-space offset, A: state)
GPUTexture* ProbesData = nullptr; // Probes data: (RGB: world-space offset, A: state/data)
GPUTexture* ProbesIrradiance = nullptr; // Probes irradiance (RGB: sRGB color)
GPUTexture* ProbesDistance = nullptr; // Probes distance (R: mean distance, G: mean distance^2)
GPUBuffer* ActiveProbes = nullptr; // List with indices of the active probes (built during probes classification to use indirect dispatches for probes updating), counter at 0
@@ -97,7 +97,7 @@ public:
FORCE_INLINE void Release()
{
RenderTargetPool::Release(ProbesTrace);
RenderTargetPool::Release(ProbesState);
RenderTargetPool::Release(ProbesData);
RenderTargetPool::Release(ProbesIrradiance);
RenderTargetPool::Release(ProbesDistance);
SAFE_DELETE_GPU_RESOURCE(ActiveProbes);
@@ -373,7 +373,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
#define INIT_TEXTURE(texture, format, width, height) desc.Format = format; desc.Width = width; desc.Height = height; ddgiData.texture = RenderTargetPool::Get(desc); if (!ddgiData.texture) return true; memUsage += ddgiData.texture->GetMemoryUsage(); RENDER_TARGET_POOL_SET_NAME(ddgiData.texture, "DDGI." #texture)
desc.Flags = GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess;
INIT_TEXTURE(ProbesTrace, PixelFormat::R16G16B16A16_Float, probeRaysCount, Math::Min(probesCountCascade, DDGI_TRACE_RAYS_PROBES_COUNT_LIMIT));
INIT_TEXTURE(ProbesState, PixelFormat::R8G8B8A8_SNorm, probesCountTotalX, probesCountTotalY);
INIT_TEXTURE(ProbesData, PixelFormat::R8G8B8A8_SNorm, probesCountTotalX, probesCountTotalY);
INIT_TEXTURE(ProbesIrradiance, PixelFormat::R11G11B10_Float, probesCountTotalX * (DDGI_PROBE_RESOLUTION_IRRADIANCE + 2), probesCountTotalY * (DDGI_PROBE_RESOLUTION_IRRADIANCE + 2));
INIT_TEXTURE(ProbesDistance, PixelFormat::R16G16_Float, probesCountTotalX * (DDGI_PROBE_RESOLUTION_DISTANCE + 2), probesCountTotalY * (DDGI_PROBE_RESOLUTION_DISTANCE + 2));
#undef INIT_TEXTURE
@@ -393,7 +393,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
{
// Clear probes
PROFILE_GPU("Clear");
context->ClearUA(ddgiData.ProbesState, Float4::Zero);
context->ClearUA(ddgiData.ProbesData, Float4::Zero);
context->ClearUA(ddgiData.ProbesIrradiance, Float4::Zero);
context->ClearUA(ddgiData.ProbesDistance, Float4::Zero);
}
@@ -458,7 +458,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
ddgiData.Result.Constants.IrradianceGamma = 1.5f;
ddgiData.Result.Constants.IndirectLightingIntensity = indirectLightingIntensity;
ddgiData.Result.Constants.FallbackIrradiance = fallbackIrradiance.ToFloat3() * fallbackIrradiance.A;
ddgiData.Result.ProbesState = ddgiData.ProbesState->View();
ddgiData.Result.ProbesData = ddgiData.ProbesData->View();
ddgiData.Result.ProbesDistance = ddgiData.ProbesDistance->View();
ddgiData.Result.ProbesIrradiance = ddgiData.ProbesIrradiance->View();
@@ -516,7 +516,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
threadGroupsX = Math::DivideAndRoundUp(probesCountCascade, DDGI_PROBE_CLASSIFY_GROUP_SIZE);
context->BindSR(0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr);
context->BindSR(1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr);
context->BindUA(0, ddgiData.Result.ProbesState);
context->BindUA(0, ddgiData.Result.ProbesData);
context->BindUA(1, ddgiData.ActiveProbes->View());
Data1 data;
data.CascadeIndex = cascadeIndex;
@@ -558,7 +558,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
context->BindSR(4, bindingDataSurfaceAtlas.Objects ? bindingDataSurfaceAtlas.Objects->View() : nullptr);
context->BindSR(5, bindingDataSurfaceAtlas.AtlasDepth->View());
context->BindSR(6, bindingDataSurfaceAtlas.AtlasLighting->View());
context->BindSR(7, ddgiData.Result.ProbesState);
context->BindSR(7, ddgiData.Result.ProbesData);
context->BindSR(8, skybox);
context->BindSR(9, ddgiData.ActiveProbes->View());
context->BindUA(0, ddgiData.ProbesTrace->View());
@@ -570,7 +570,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
// Update probes irradiance and distance textures (one thread-group per probe)
{
PROFILE_GPU_CPU_NAMED("Update Probes");
context->BindSR(0, ddgiData.Result.ProbesState);
context->BindSR(0, ddgiData.Result.ProbesData);
context->BindSR(1, ddgiData.ProbesTrace->View());
context->BindSR(2, ddgiData.ActiveProbes->View());
context->BindUA(0, ddgiData.Result.ProbesIrradiance);
@@ -682,7 +682,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
context->BindSR(1, renderContext.Buffers->GBuffer1->View());
context->BindSR(2, renderContext.Buffers->GBuffer2->View());
context->BindSR(3, renderContext.Buffers->DepthBuffer->View());
context->BindSR(4, ddgiData.Result.ProbesState);
context->BindSR(4, ddgiData.Result.ProbesData);
context->BindSR(5, ddgiData.Result.ProbesDistance);
context->BindSR(6, ddgiData.Result.ProbesIrradiance);
context->SetViewportAndScissors(renderContext.View.ScreenSize.X, renderContext.View.ScreenSize.Y);
@@ -724,7 +724,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, ToSpan(targetBuffers, ARRAY_COUNT(targetBuffers)));
{
// Pass DDGI data to the material
_debugMaterial->SetParameterValue(TEXT("ProbesState"), Variant(ddgiData.ProbesState));
_debugMaterial->SetParameterValue(TEXT("ProbesData"), Variant(ddgiData.ProbesData));
_debugMaterial->SetParameterValue(TEXT("ProbesIrradiance"), Variant(ddgiData.ProbesIrradiance));
_debugMaterial->SetParameterValue(TEXT("ProbesDistance"), Variant(ddgiData.ProbesDistance));
auto cb = _debugMaterial->GetShader()->GetCB(3);

View File

@@ -34,7 +34,7 @@ public:
struct BindingData
{
ConstantsData Constants;
GPUTextureView* ProbesState;
GPUTextureView* ProbesData;
GPUTextureView* ProbesDistance;
GPUTextureView* ProbesIrradiance;
};

View File

@@ -1056,7 +1056,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
PROFILE_GPU_CPU_NAMED("DDGI");
data.DDGI = bindingDataDDGI.Constants;
data.Light.Radius = giSettings.BounceIntensity / bindingDataDDGI.Constants.IndirectLightingIntensity; // Reuse for smaller CB
context->BindSR(5, bindingDataDDGI.ProbesState);
context->BindSR(5, bindingDataDDGI.ProbesData);
context->BindSR(6, bindingDataDDGI.ProbesDistance);
context->BindSR(7, bindingDataDDGI.ProbesIrradiance);
context->UpdateCB(_cb0, &data);

View File

@@ -671,7 +671,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
int32 csIndex;
if (useDDGI)
{
context->BindSR(5, bindingDataDDGI.ProbesState);
context->BindSR(5, bindingDataDDGI.ProbesData);
context->BindSR(6, bindingDataDDGI.ProbesDistance);
context->BindSR(7, bindingDataDDGI.ProbesIrradiance);
csIndex = 1;

View File

@@ -13,9 +13,9 @@
#include "./Flax/Math.hlsl"
#include "./Flax/Octahedral.hlsl"
#define DDGI_PROBE_STATE_INACTIVE 0.0f
#define DDGI_PROBE_STATE_ACTIVATED 0.2f
#define DDGI_PROBE_STATE_ACTIVE 1.0f
#define DDGI_PROBE_STATE_INACTIVE 0
#define DDGI_PROBE_STATE_ACTIVATED 1
#define DDGI_PROBE_STATE_ACTIVE 2
#define DDGI_PROBE_RESOLUTION_IRRADIANCE 6 // Resolution (in texels) for probe irradiance data (excluding 1px padding on each side)
#define DDGI_PROBE_RESOLUTION_DISTANCE 14 // Resolution (in texels) for probe distance data (excluding 1px padding on each side)
#define DDGI_SRGB_BLENDING 1 // Enables blending in sRGB color space, otherwise irradiance blending is done in linear space
@@ -89,22 +89,32 @@ float3 GetDDGIProbeWorldPosition(DDGIData data, uint cascadeIndex, uint3 probeCo
return probesOrigin + probePosition - probeGridOffset + (data.ProbesScrollOffsets[cascadeIndex].xyz * probesSpacing);
}
// Loads probe probe state
float LoadDDGIProbeState(DDGIData data, Texture2D<snorm float4> probesState, uint cascadeIndex, uint probeIndex)
// Loads probe probe data (encoded)
float4 LoadDDGIProbeData(DDGIData data, Texture2D<snorm float4> probesData, uint cascadeIndex, uint probeIndex)
{
int2 probeDataCoords = GetDDGIProbeTexelCoords(data, cascadeIndex, probeIndex);
float4 probeState = probesState.Load(int3(probeDataCoords, 0));
return probeState.w;
return probesData.Load(int3(probeDataCoords, 0));
}
// Loads probe world-space position (XYZ) and probe state (W)
float4 LoadDDGIProbePositionAndState(DDGIData data, Texture2D<snorm float4> probesState, uint cascadeIndex, uint probeIndex, uint3 probeCoords)
// Encodes probe probe data
float4 EncodeDDGIProbeData(float3 probeOffset, uint probeState)
{
int2 probeDataCoords = GetDDGIProbeTexelCoords(data, cascadeIndex, probeIndex);
float4 probeState = probesState.Load(int3(probeDataCoords, 0));
probeState.xyz *= data.ProbesOriginAndSpacing[cascadeIndex].w; // Probe offset is [-1;1] within probes spacing
probeState.xyz += GetDDGIProbeWorldPosition(data, cascadeIndex, probeCoords); // Place probe on a grid
return probeState;
return float4(probeOffset, (float)probeState * (1.0f / 8.0f));
}
// Decodes probe state from the encoded state
uint DecodeDDGIProbeState(float4 probeData)
{
return (uint)(probeData.w * 8.0f);
}
// Decodes probe world-space position (XYZ) from the encoded state
float3 DecodeDDGIProbePosition(DDGIData data, float4 probeData, uint cascadeIndex, uint probeIndex, uint3 probeCoords)
{
float3 probePosition = probeData.xyz;
probePosition *= data.ProbesOriginAndSpacing[cascadeIndex].w; // Probe offset is [-1;1] within probes spacing
probePosition += GetDDGIProbeWorldPosition(data, cascadeIndex, probeCoords); // Place probe on a grid
return probePosition;
}
// Calculates texture UVs for sampling probes atlas texture (irradiance or distance)
@@ -122,11 +132,11 @@ float2 GetDDGIProbeUV(DDGIData data, uint cascadeIndex, uint probeIndex, float2
// Samples DDGI probes volume at the given world-space position and returns the irradiance.
// bias - scales the bias vector to the initial sample point to reduce self-shading artifacts
// dither - randomized per-pixel value in range 0-1, used to smooth dithering for cascades blending
float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesState, Texture2D<float4> probesDistance, Texture2D<float4> probesIrradiance, float3 worldPosition, float3 worldNormal, float bias = 0.2f, float dither = 0.0f)
float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesData, Texture2D<float4> probesDistance, Texture2D<float4> probesIrradiance, float3 worldPosition, float3 worldNormal, float bias = 0.2f, float dither = 0.0f)
{
// Select the highest cascade that contains the sample location
uint cascadeIndex = 0;
float4 probeStates[8];
float4 probesDatas[8];
for (; cascadeIndex < data.CascadesCount; cascadeIndex++)
{
float probesSpacing = data.ProbesOriginAndSpacing[cascadeIndex].w;
@@ -145,9 +155,10 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesState,
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 probeState = probesState.Load(int3(GetDDGIProbeTexelCoords(data, cascadeIndex, probeIndex), 0));
probeStates[i] = probeState;
if (probeState.w != DDGI_PROBE_STATE_INACTIVE)
float4 probeData = LoadDDGIProbeData(data, probesData, cascadeIndex, probeIndex);
probesDatas[i] = probeData;
uint probeState = DecodeDDGIProbeState(probeData);
if (probeState != DDGI_PROBE_STATE_INACTIVE)
activeCount++;
}
@@ -182,12 +193,12 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesState,
uint probeIndex = GetDDGIScrollingProbeIndex(data, cascadeIndex, probeCoords);
// Load probe position and state
float4 probeState = probeStates[i];
if (probeState.w == DDGI_PROBE_STATE_INACTIVE)
float4 probeData = probesDatas[i];
uint probeState = DecodeDDGIProbeState(probeData);
if (probeState == DDGI_PROBE_STATE_INACTIVE)
continue;
probeState.xyz *= probesSpacing; // Probe offset is [-1;1] within probes spacing
float3 probeBasePosition = baseProbeWorldPosition + ((probeCoords - baseProbeCoords) * probesSpacing);
float3 probePosition = probeBasePosition + probeState.xyz;
float3 probePosition = probeBasePosition + probeData.xyz * probesSpacing; // Probe offset is [-1;1] within probes spacing
// Calculate the distance and direction from the (biased and non-biased) shading point and the probe
float3 worldPosToProbe = normalize(probePosition - worldPosition);
@@ -233,7 +244,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesState,
#endif
// Debug probe offset visualization
//probeIrradiance = float3(max(frac(probeState.xyz) * 2, 0.1f));
//probeIrradiance = float3(max(frac(probeData.xyz) * 2, 0.1f));
// Accumulate weighted irradiance
irradiance += float4(probeIrradiance * weight, weight);

View File

@@ -58,17 +58,18 @@ float3 GetProbeRayDirection(DDGIData data, uint rayIndex)
return normalize(QuaternionRotate(data.RaysRotation, direction));
}
// Checks if the probe states are equal
bool GetProbeState(float a, float b)
// Calculates amount of rays to allocate for a probe
uint GetProbeRaysCount(DDGIData data, uint probeState)
{
return abs(a - b) < 0.05f;
// TODO: implement variable ray count based on probe location relative to the view frustum (use probe state for storage)
return data.RaysCount;
}
#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> RWProbesState : register(u0);
RWTexture2D<snorm float4> RWProbesData : register(u0);
RWByteAddressBuffer RWActiveProbes : register(u1);
Texture3D<float> GlobalSDFTex : register(t0);
@@ -79,7 +80,7 @@ float3 Remap(float3 value, float3 fromMin, float3 fromMax, float3 toMin, float3
return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin;
}
// Compute shader for updating probes state between active and inactive.
// Compute shader for updating probes state between active and inactive and performing probes relocation.
META_CS(true, FEATURE_LEVEL_SM5)
[numthreads(DDGI_PROBE_CLASSIFY_GROUP_SIZE, 1, 1)]
void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
@@ -94,14 +95,15 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w;
// Load probe state and position
float4 probeState = RWProbesState[probeDataCoords];
probeState.xyz *= probesSpacing; // Probe offset is [-1;1] within probes spacing
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 += probeState.xyz;
probePosition += probeOffset;
#endif
float4 probeStateOld = probeState;
// Use Global SDF to quickly get distance and direction to the scene geometry
#if DDGI_PROBE_RELOCATE_ITERATIVE
@@ -117,7 +119,8 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
if (sdfDst > distanceLimit) // Probe is too far from geometry
{
// Disable it
probeState = float4(0, 0, 0, DDGI_PROBE_STATE_INACTIVE);
probeOffset = float3(0, 0, 0);
probeState = DDGI_PROBE_STATE_INACTIVE;
}
else
{
@@ -127,22 +130,22 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
if (sdfDst < relocateLimit)
{
float3 offsetToAdd = sdfNormal * (sdf + threshold);
if (distance(probeState.xyz, offsetToAdd) < relocateLimit)
if (distance(probeOffset, offsetToAdd) < relocateLimit)
{
// Relocate it
probeState.xyz += offsetToAdd;
probeOffset += offsetToAdd;
}
}
else
{
// Reset relocation
probeState.xyz = float3(0, 0, 0);
probeOffset = float3(0, 0, 0);
}
}
else if (sdf > threshold * 4.0f) // Probe is far enough from any geometry
{
// Reset relocation
probeState.xyz = float3(0, 0, 0);
probeOffset = float3(0, 0, 0);
}
// Check if probe is relocated but the base location is fine
@@ -150,7 +153,7 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
if (sdf > threshold)
{
// Reset relocation
probeState.xyz = float3(0, 0, 0);
probeOffset = float3(0, 0, 0);
}
#else
// Sample Global SDF around the probe location
@@ -177,7 +180,7 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
// Relocate the probe to the best found location (or zero if nothing good found)
if (bestOffset.w <= threshold)
bestOffset.xyz = float3(0, 0, 0);
probeState.xyz = bestOffset.xyz;
probeOffset = bestOffset.xyz;
#endif
// Check if probe was scrolled
@@ -189,23 +192,21 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
int probeCount = (int)DDGI.ProbesCounts[planeIndex];
int newCord = (int)probeCoords[planeIndex] + probeScrollClears[planeIndex];
if (newCord < 0 || newCord >= probeCount)
{
wasScrolled = true;
}
}
// If probe was in different location or was inactive last frame then mark it as activated
bool wasInactive = probeStateOld.w == DDGI_PROBE_STATE_INACTIVE;
bool wasRelocated = distance(probeState.xyz, probeStateOld.xyz) > 2.0f;
probeState.w = wasInactive || wasScrolled || wasRelocated ? DDGI_PROBE_STATE_ACTIVATED : DDGI_PROBE_STATE_ACTIVE;
bool wasInactive = probeState == DDGI_PROBE_STATE_INACTIVE;
bool wasRelocated = distance(probeOffset, probeOffsetOld) > 2.0f;
probeState = wasInactive || wasScrolled || wasRelocated ? DDGI_PROBE_STATE_ACTIVATED : DDGI_PROBE_STATE_ACTIVE;
}
// Save probe state
probeState.xyz /= probesSpacing;
RWProbesState[probeDataCoords] = probeState;
probeOffset /= probesSpacing; // Move offset back to [-1;1] space
RWProbesData[probeDataCoords] = EncodeDDGIProbeData(probeOffset, probeState);
// Collect active probes
if (probeState.w != DDGI_PROBE_STATE_INACTIVE)
if (probeState != DDGI_PROBE_STATE_INACTIVE)
{
uint activeProbeIndex;
RWActiveProbes.InterlockedAdd(0, 1, activeProbeIndex); // Counter at 0
@@ -250,7 +251,7 @@ ByteAddressBuffer RWGlobalSurfaceAtlasCulledObjects : register(t3);
Buffer<float4> GlobalSurfaceAtlasObjects : register(t4);
Texture2D GlobalSurfaceAtlasDepth : register(t5);
Texture2D GlobalSurfaceAtlasTex : register(t6);
Texture2D<snorm float4> ProbesState : register(t7);
Texture2D<snorm float4> ProbesData : register(t7);
TextureCube Skybox : register(t8);
ByteAddressBuffer ActiveProbes : register(t9);
@@ -269,14 +270,17 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID)
probeIndex = GetDDGIScrollingProbeIndex(DDGI, CascadeIndex, probeCoords);
// Load current probe state and position
float4 probePositionAndState = LoadDDGIProbePositionAndState(DDGI, ProbesState, CascadeIndex, probeIndex, probeCoords);
if (probePositionAndState.w == DDGI_PROBE_STATE_INACTIVE)
return; // Skip disabled probes
float4 probeData = LoadDDGIProbeData(DDGI, ProbesData, CascadeIndex, probeIndex);
uint probeState = DecodeDDGIProbeState(probeData);
uint probeRaysCount = GetProbeRaysCount(DDGI, probeState);
if (probeState == DDGI_PROBE_STATE_INACTIVE || probeRaysCount < rayIndex)
return; // Skip disabled probes or if current thread's ray is unused
float3 probePosition = DecodeDDGIProbePosition(DDGI, probeData, CascadeIndex, probeIndex, probeCoords);
float3 probeRayDirection = GetProbeRayDirection(DDGI, rayIndex);
// Trace ray with Global SDF
GlobalSDFTrace trace;
trace.Init(probePositionAndState.xyz, probeRayDirection, 0.0f, DDGI.RayMaxDistance);
trace.Init(probePosition, probeRayDirection, 0.0f, DDGI.RayMaxDistance);
GlobalSDFHit hit = RayTraceGlobalSDF(GlobalSDF, GlobalSDFTex, GlobalSDFMip, trace);
// Calculate radiance and distance
@@ -328,7 +332,7 @@ groupshared float CachedProbesTraceDistance[DDGI_TRACE_RAYS_LIMIT];
groupshared float3 CachedProbesTraceDirection[DDGI_TRACE_RAYS_LIMIT];
RWTexture2D<float4> RWOutput : register(u0);
Texture2D<snorm float4> ProbesState : register(t0);
Texture2D<snorm float4> ProbesData : register(t0);
Texture2D<float4> ProbesTrace : register(t1);
ByteAddressBuffer ActiveProbes : register(t2);
@@ -348,13 +352,15 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
// Skip disabled probes
bool skip = false;
float probeState = LoadDDGIProbeState(DDGI, ProbesState, CascadeIndex, probeIndex);
float4 probeData = LoadDDGIProbeData(DDGI, ProbesData, CascadeIndex, probeIndex);
uint probeState = DecodeDDGIProbeState(probeData);
uint probeRaysCount = GetProbeRaysCount(DDGI, probeState);
if (probeState == DDGI_PROBE_STATE_INACTIVE)
skip = true;
#if DDGI_PROBE_UPDATE_MODE == 0
uint backfacesCount = 0;
uint backfacesLimit = uint(DDGI.RaysCount * 0.1f);
uint backfacesLimit = uint(probeRaysCount * 0.1f);
#else
float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w;
float distanceLimit = length(probesSpacing) * 1.5f;
@@ -364,9 +370,9 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
if (!skip)
{
// Load trace rays results into shared memory to reuse across whole thread group (raysCount per thread)
uint raysCount = (uint)(ceil((float)DDGI.RaysCount / (float)(DDGI_PROBE_RESOLUTION * DDGI_PROBE_RESOLUTION)));
uint raysCount = (uint)(ceil((float)probeRaysCount / (float)(DDGI_PROBE_RESOLUTION * DDGI_PROBE_RESOLUTION)));
uint raysStart = GroupIndex * raysCount;
raysCount = max(min(raysStart + raysCount, DDGI.RaysCount), raysStart) - raysStart;
raysCount = max(min(raysStart + raysCount, probeRaysCount), raysStart) - raysStart;
for (uint i = 0; i < raysCount; i++)
{
uint rayIndex = raysStart + i;
@@ -392,7 +398,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
// Loop over rays
float4 result = float4(0, 0, 0, 0);
LOOP
for (uint rayIndex = 0; rayIndex < DDGI.RaysCount; rayIndex++)
for (uint rayIndex = 0; rayIndex < probeRaysCount; rayIndex++)
{
float3 rayDirection = CachedProbesTraceDirection[rayIndex];
float rayWeight = max(dot(octahedralDirection, rayDirection), 0.0f);
@@ -426,12 +432,12 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
}
// Normalize results
float epsilon = (float)DDGI.RaysCount * 1e-9f;
float epsilon = (float)probeRaysCount * 1e-9f;
result.rgb *= 1.0f / (2.0f * max(result.a, epsilon));
// Load current probe value
float3 previous = RWOutput[outputCoords].rgb;
bool wasActivated = GetProbeState(probeState, DDGI_PROBE_STATE_ACTIVATED);
bool wasActivated = probeState == DDGI_PROBE_STATE_ACTIVATED;
if (ResetBlend || wasActivated)
previous = float3(0, 0, 0);
@@ -541,7 +547,7 @@ void CS_UpdateBorders(uint3 DispatchThreadId : SV_DispatchThreadID)
#include "./Flax/Random.hlsl"
#include "./Flax/LightingCommon.hlsl"
Texture2D<snorm float4> ProbesState : register(t4);
Texture2D<snorm float4> ProbesData : register(t4);
Texture2D<float4> ProbesDistance : register(t5);
Texture2D<float4> ProbesIrradiance : register(t6);
@@ -565,7 +571,7 @@ void PS_IndirectLighting(Quad_VS2PS input, out float4 output : SV_Target0)
// Sample irradiance
float bias = 0.2f;
float dither = RandN2(input.TexCoord + TemporalTime).x;
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal, bias, dither);
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesData, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal, bias, dither);
// Calculate lighting
float3 diffuseColor = GetDiffuseColor(gBuffer);

View File

@@ -87,7 +87,7 @@ float4 PS_ClearLighting(AtlasVertexOutput input) : SV_Target
// GBuffer+Depth at 0-3 slots
Buffer<float4> GlobalSurfaceAtlasObjects : register(t4);
#if INDIRECT_LIGHT
Texture2D<snorm float4> ProbesState : register(t5);
Texture2D<snorm float4> ProbesData : register(t5);
Texture2D<float4> ProbesDistance : register(t6);
Texture2D<float4> ProbesIrradiance : register(t7);
#else
@@ -134,7 +134,7 @@ float4 PS_Lighting(AtlasVertexOutput input) : SV_Target
#if INDIRECT_LIGHT
// Sample irradiance
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal);
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesData, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal);
irradiance *= Light.Radius; // Cached BounceIntensity / IndirectLightingIntensity
// Calculate lighting

View File

@@ -286,7 +286,7 @@ Texture3D<float4> LightScatteringHistory : register(t2);
Texture3D<float4> LocalShadowedLightScattering : register(t3);
Texture2DArray ShadowMapCSM : register(t4);
#if USE_DDGI
Texture2D<snorm float4> ProbesState : register(t5);
Texture2D<snorm float4> ProbesData : register(t5);
Texture2D<float4> ProbesDistance : register(t6);
Texture2D<float4> ProbesIrradiance : register(t7);
#else
@@ -337,7 +337,7 @@ void CS_LightScattering(uint3 GroupId : SV_GroupID, uint3 DispatchThreadId : SV_
#if USE_DDGI
// Dynamic Diffuse Global Illumination
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, positionWS, cameraVectorNormalized, 0.0f, cellOffset.x);
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesData, ProbesDistance, ProbesIrradiance, positionWS, cameraVectorNormalized, 0.0f, cellOffset.x);
lightScattering += float4(irradiance, 1);
#else
// Sky light