Fix initializing activated and scrolled DDGI probes
This commit is contained in:
@@ -49,6 +49,7 @@ PACK_STRUCT(struct Data0
|
||||
Float2 Padding0;
|
||||
float ResetBlend;
|
||||
float TemporalTime;
|
||||
Int4 ProbeScrollClears[4];
|
||||
});
|
||||
|
||||
PACK_STRUCT(struct Data1
|
||||
@@ -68,16 +69,14 @@ public:
|
||||
float ProbesSpacing = 0.0f;
|
||||
Int3 ProbeScrollOffsets;
|
||||
Int3 ProbeScrollDirections;
|
||||
bool ProbeScrollClear[3];
|
||||
Int3 ProbeScrollClears;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
ProbesOrigin = Float3::Zero;
|
||||
ProbeScrollOffsets = Int3::Zero;
|
||||
ProbeScrollDirections = Int3::Zero;
|
||||
ProbeScrollClear[0] = false;
|
||||
ProbeScrollClear[1] = false;
|
||||
ProbeScrollClear[2] = false;
|
||||
ProbeScrollClears = Int3::Zero;
|
||||
}
|
||||
} Cascades[4];
|
||||
|
||||
@@ -315,7 +314,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
||||
idealDistance *= 2;
|
||||
cascadesCount++;
|
||||
}
|
||||
|
||||
|
||||
// Calculate the probes count based on the amount of cascades and the distance to cover
|
||||
const float cascadesDistanceScales[] = { 1.0f, 3.0f, 6.0f, 10.0f }; // Scales each cascade further away from the camera origin
|
||||
const float distanceExtent = distance / cascadesDistanceScales[cascadesCount - 1];
|
||||
@@ -427,7 +426,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
||||
continue;
|
||||
auto& cascade = ddgiData.Cascades[cascadeIndex];
|
||||
|
||||
// Reset the volume origin and scroll offsets for each axis
|
||||
// Reset the volume origin and scroll offsets for each axis once it overflows
|
||||
for (int32 axis = 0; axis < 3; axis++)
|
||||
{
|
||||
if (cascade.ProbeScrollOffsets.Raw[axis] != 0 && (cascade.ProbeScrollOffsets.Raw[axis] % ddgiData.ProbeCounts.Raw[axis] == 0))
|
||||
@@ -445,7 +444,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
||||
const float value = translation.Raw[axis] / cascade.ProbesSpacing;
|
||||
const int32 scroll = value >= 0.0f ? (int32)Math::Floor(value) : (int32)Math::Ceil(value);
|
||||
cascade.ProbeScrollOffsets.Raw[axis] += scroll;
|
||||
cascade.ProbeScrollClear[axis] = scroll != 0;
|
||||
cascade.ProbeScrollClears.Raw[axis] = scroll;
|
||||
cascade.ProbeScrollDirections.Raw[axis] = translation.Raw[axis] >= 0.0f ? 1 : -1;
|
||||
}
|
||||
}
|
||||
@@ -459,10 +458,8 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
||||
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
||||
{
|
||||
auto& cascade = ddgiData.Cascades[cascadeIndex];
|
||||
int32 probeScrollClear = cascade.ProbeScrollClear[0] + cascade.ProbeScrollClear[1] * 2 + cascade.ProbeScrollClear[2] * 4; // Pack clear flags into bits
|
||||
ddgiData.Result.Constants.ProbesOriginAndSpacing[cascadeIndex] = Float4(cascade.ProbesOrigin, cascade.ProbesSpacing);
|
||||
ddgiData.Result.Constants.ProbesScrollOffsets[cascadeIndex] = Int4(cascade.ProbeScrollOffsets, probeScrollClear);
|
||||
ddgiData.Result.Constants.ProbeScrollDirections[cascadeIndex] = Int4(cascade.ProbeScrollDirections, 0);
|
||||
ddgiData.Result.Constants.ProbesScrollOffsets[cascadeIndex] = Int4(cascade.ProbeScrollOffsets, 0);
|
||||
}
|
||||
ddgiData.Result.Constants.RayMaxDistance = 10000.0f; // TODO: adjust to match perf/quality ratio (make it based on Global SDF and Global Surface Atlas distance)
|
||||
ddgiData.Result.Constants.ViewDir = renderContext.View.Direction;
|
||||
@@ -487,6 +484,11 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
|
||||
data.GlobalSDF = bindingDataSDF.Constants;
|
||||
data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants;
|
||||
data.ResetBlend = clear ? 1.0f : 0.0f;
|
||||
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
|
||||
{
|
||||
auto& cascade = ddgiData.Cascades[cascadeIndex];
|
||||
data.ProbeScrollClears[cascadeIndex] = Int4(cascade.ProbeScrollClears, 0);
|
||||
}
|
||||
if (renderContext.List->Settings.AntiAliasing.Mode == AntialiasingMode::TemporalAntialiasing)
|
||||
{
|
||||
// Use temporal offset in the dithering factor (gets cleaned out by TAA)
|
||||
|
||||
@@ -17,7 +17,6 @@ public:
|
||||
{
|
||||
Float4 ProbesOriginAndSpacing[4];
|
||||
Int4 ProbesScrollOffsets[4];
|
||||
Int4 ProbeScrollDirections[4];
|
||||
uint32 ProbesCounts[3];
|
||||
uint32 CascadesCount;
|
||||
float IrradianceGamma;
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
#include "./Flax/Math.hlsl"
|
||||
#include "./Flax/Octahedral.hlsl"
|
||||
|
||||
#define DDGI_PROBE_STATE_ACTIVE 0
|
||||
#define DDGI_PROBE_STATE_INACTIVE 1
|
||||
#define DDGI_PROBE_STATE_INACTIVE 0.0f
|
||||
#define DDGI_PROBE_STATE_ACTIVATED 0.2f
|
||||
#define DDGI_PROBE_STATE_ACTIVE 1.0f
|
||||
#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
|
||||
@@ -23,8 +24,7 @@
|
||||
struct DDGIData
|
||||
{
|
||||
float4 ProbesOriginAndSpacing[4];
|
||||
int4 ProbesScrollOffsets[4];
|
||||
int4 ProbeScrollDirections[4];
|
||||
int4 ProbesScrollOffsets[4]; // w unused
|
||||
uint3 ProbesCounts;
|
||||
uint CascadesCount;
|
||||
float IrradianceGamma;
|
||||
@@ -77,7 +77,7 @@ uint2 GetDDGIProbeTexelCoords(DDGIData data, uint cascadeIndex, uint probeIndex)
|
||||
uint GetDDGIScrollingProbeIndex(DDGIData data, uint cascadeIndex, uint3 probeCoords)
|
||||
{
|
||||
// Probes are scrolled on edges to stabilize GI when camera moves
|
||||
return GetDDGIProbeIndex(data, (probeCoords + data.ProbesScrollOffsets[cascadeIndex].xyz + data.ProbesCounts) % data.ProbesCounts);
|
||||
return GetDDGIProbeIndex(data, ((int3)probeCoords + data.ProbesScrollOffsets[cascadeIndex].xyz + (int3)data.ProbesCounts) % (int3)data.ProbesCounts);
|
||||
}
|
||||
|
||||
float3 GetDDGIProbeWorldPosition(DDGIData data, uint cascadeIndex, uint3 probeCoords)
|
||||
@@ -146,7 +146,7 @@ float3 SampleDDGIIrradiance(DDGIData data, Texture2D<snorm float4> probesState,
|
||||
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_ACTIVE)
|
||||
if (probeState.w != DDGI_PROBE_STATE_INACTIVE)
|
||||
activeCount++;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ GBufferData GBuffer;
|
||||
float2 Padding0;
|
||||
float ResetBlend;
|
||||
float TemporalTime;
|
||||
int4 ProbeScrollClears[4];
|
||||
META_CB_END
|
||||
|
||||
META_CB_BEGIN(1, Data1)
|
||||
@@ -56,6 +57,12 @@ 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)
|
||||
{
|
||||
return abs(a - b) < 0.05f;
|
||||
}
|
||||
|
||||
#ifdef _CS_Classify
|
||||
|
||||
RWTexture2D<snorm float4> RWProbesState : register(u0);
|
||||
@@ -83,7 +90,7 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
probeState.xyz *= probesSpacing; // Probe offset is [-1;1] within probes spacing
|
||||
float3 probeBasePosition = GetDDGIProbeWorldPosition(DDGI, CascadeIndex, probeCoords);
|
||||
float3 probePosition = probeBasePosition + probeState.xyz;
|
||||
probeState.w = DDGI_PROBE_STATE_ACTIVE;
|
||||
float4 probeStateOld = probeState;
|
||||
|
||||
// Use Global SDF to quickly get distance and direction to the scene geometry
|
||||
float sdf;
|
||||
@@ -129,13 +136,32 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
// Reset relocation
|
||||
probeState.xyz = float3(0, 0, 0);
|
||||
}
|
||||
|
||||
// Check if probe was scrolled
|
||||
int3 probeScrollClears = ProbeScrollClears[CascadeIndex].xyz;
|
||||
bool wasScrolled = false;
|
||||
UNROLL
|
||||
for (uint planeIndex = 0; planeIndex < 3; planeIndex++)
|
||||
{
|
||||
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) > 1.0f;
|
||||
probeState.w = wasInactive || wasScrolled || wasRelocated ? DDGI_PROBE_STATE_ACTIVATED : DDGI_PROBE_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
probeState.xyz /= probesSpacing;
|
||||
RWProbesState[probeDataCoords] = probeState;
|
||||
|
||||
// Collect active probes
|
||||
if (probeState.w == DDGI_PROBE_STATE_ACTIVE)
|
||||
if (probeState.w != DDGI_PROBE_STATE_INACTIVE)
|
||||
{
|
||||
uint activeProbeIndex;
|
||||
RWActiveProbes.InterlockedAdd(0, 1, activeProbeIndex); // Counter at 0
|
||||
@@ -313,29 +339,6 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
|
||||
return;
|
||||
probeCoords = GetDDGIProbeCoords(DDGI, probeIndex);
|
||||
uint2 outputCoords = GetDDGIProbeTexelCoords(DDGI, CascadeIndex, probeIndex) * (DDGI_PROBE_RESOLUTION + 2) + 1 + GroupThreadId.xy;
|
||||
|
||||
// Clear probes that have been scrolled to a new positions
|
||||
int3 probesScrollOffsets = DDGI.ProbesScrollOffsets[CascadeIndex].xyz;
|
||||
int probeScrollClear = DDGI.ProbesScrollOffsets[CascadeIndex].w;
|
||||
int3 probeScrollDirections = DDGI.ProbeScrollDirections[CascadeIndex].xyz;
|
||||
bool scrolled = false;
|
||||
UNROLL
|
||||
for (uint planeIndex = 0; planeIndex < 3; planeIndex++)
|
||||
{
|
||||
if (probeScrollClear & (1 << planeIndex))
|
||||
{
|
||||
int scrollOffset = probesScrollOffsets[planeIndex];
|
||||
int scrollDirection = probeScrollDirections[planeIndex];
|
||||
uint probeCount = DDGI.ProbesCounts[planeIndex];
|
||||
uint coord = (probeCount + (scrollDirection ? (scrollOffset - 1) : (scrollOffset % probeCount))) % probeCount;
|
||||
if (probeCoords[planeIndex] == coord)
|
||||
scrolled = true;
|
||||
}
|
||||
}
|
||||
if (scrolled)
|
||||
{
|
||||
RWOutput[outputCoords] = float4(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Calculate octahedral projection for probe (unwraps spherical projection into a square)
|
||||
float2 octahedralCoords = GetOctahedralCoords(GroupThreadId.xy, DDGI_PROBE_RESOLUTION);
|
||||
@@ -381,11 +384,16 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_
|
||||
float epsilon = (float)DDGI.RaysCount * 1e-9f;
|
||||
result.rgb *= 1.0f / (2.0f * max(result.a, epsilon));
|
||||
|
||||
// Blend current value with the previous probe data
|
||||
// Load current probe value
|
||||
float3 previous = RWOutput[outputCoords].rgb;
|
||||
bool wasActivated = GetProbeState(probeState, DDGI_PROBE_STATE_ACTIVATED);
|
||||
if (wasActivated)
|
||||
previous = float3(0, 0, 0);
|
||||
|
||||
// Blend current value with the previous probe data
|
||||
float historyWeight = DDGI.ProbeHistoryWeight;
|
||||
//historyWeight = 0.0f;
|
||||
if (ResetBlend || scrolled || dot(previous, previous) == 0)
|
||||
if (ResetBlend || wasActivated || dot(previous, previous) == 0)
|
||||
historyWeight = 0.0f;
|
||||
#if DDGI_PROBE_UPDATE_MODE == 0
|
||||
result *= DDGI.IndirectLightingIntensity;
|
||||
|
||||
Reference in New Issue
Block a user