Improve GI quality

This commit is contained in:
Wojciech Figat
2022-05-31 15:52:19 +02:00
parent bdc7b3b754
commit 641d04a50e
7 changed files with 34 additions and 25 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.

View File

@@ -43,7 +43,8 @@ PACK_STRUCT(struct Data0
GlobalSignDistanceFieldPass::ConstantsData GlobalSDF;
GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas;
GBufferData GBuffer;
Vector3 Padding0;
Vector2 Padding0;
float ResetBlend;
float IndirectLightingIntensity;
});
@@ -283,7 +284,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
// TODO: configurable via graphics settings
const Quality quality = Quality::Ultra;
bool debugProbes = true; // TODO: add debug option to draw probes locations -> in Graphics window - Editor-only
bool debugProbes = false; // TODO: add debug option to draw probes locations -> in Graphics window - Editor-only
// TODO: configurable via postFx settings (maybe use Global SDF distance?)
const float indirectLightingIntensity = 1.0f;
const Vector3 giDistance(2000, 2000, 2000); // GI distance around the view (in each direction)
@@ -291,7 +292,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
const Int3 probesCounts(Vector3::Ceil(giDistance / giResolution));
const Vector3 probesDistance = Vector3(probesCounts) * giResolution;
const int32 probeRaysCount = Math::Min(Math::AlignUp(256, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT); // TODO: make it based on the GI Quality
const float probeHistoryWeight = 0.97f;
const float probeHistoryWeight = 0.8f;
// Init buffers
const int32 probesCount = probesCounts.X * probesCounts.Y * probesCounts.Z;
@@ -347,6 +348,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
viewOrigin += viewDirection * viewOriginOffset;
const float viewOriginSnapping = giResolution;
viewOrigin = Vector3::Floor(viewOrigin / viewOriginSnapping) * viewOriginSnapping;
//viewOrigin = Vector3::Zero;
CalculateVolumeScrolling(ddgiData, viewOrigin);
// Upload constants
@@ -377,6 +379,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext,
data.DDGI = ddgiData.Result.Constants;
data.GlobalSDF = bindingDataSDF.Constants;
data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants;
data.ResetBlend = clear ? 1.0f : 0.0f;
data.IndirectLightingIntensity = indirectLightingIntensity;
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
context->UpdateCB(_cb0, &data);

View File

@@ -437,7 +437,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
surfaceAtlasData.TileTexelsPerWorldUnit = 1.0f / 10.0f; // Scales the tiles resolution
surfaceAtlasData.DistanceScalingStart = 2000.0f; // Distance from camera at which the tiles resolution starts to be scaled down
surfaceAtlasData.DistanceScalingEnd = 5000.0f; // Distance from camera at which the tiles resolution end to be scaled down
surfaceAtlasData.DistanceScaling = 0.1f; // The scale for tiles at distanceScalingEnd and further away
surfaceAtlasData.DistanceScaling = 0.2f; // The scale for tiles at distanceScalingEnd and further away
// TODO: add DetailsScale param to adjust quality of scene details in Global Surface Atlas
const uint32 viewMask = renderContext.View.RenderLayersMask;
const Vector3 viewPosition = renderContext.View.Position;
@@ -595,6 +595,9 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
result.Constants.ChunkSize = distance / (float)GLOBAL_SURFACE_ATLAS_CHUNKS_RESOLUTION;
result.Constants.ObjectsCount = surfaceAtlasData.Objects.Count();
// If we don't know the culled objects buffer capacity then we shouldn't use atlas results as many objects are still missing (see CulledObjectsCounterIndex usage)
bool notReady = false;
// Cull objects into chunks (for faster Atlas sampling)
if (surfaceAtlasData.Objects.Count() != 0)
{
@@ -620,18 +623,23 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
if (surfaceAtlasData.CulledObjectsCounterIndex != -1)
{
// Get the last counter value (accept staging readback delay)
notReady = true;
auto data = (uint32*)_culledObjectsSizeBuffer->Map(GPUResourceMapMode::Read);
if (data)
{
uint32 counter = data[surfaceAtlasData.CulledObjectsCounterIndex];
_culledObjectsSizeBuffer->Unmap();
if (counter > 0)
{
objectsBufferCapacity = counter * sizeof(Vector4);
notReady = false;
}
}
}
if (surfaceAtlasData.CulledObjectsCounterIndex == -1)
{
// Find a free timer slot
notReady = true;
for (int32 i = 0; i < ARRAY_COUNT(_culledObjectsSizeFrames); i++)
{
if (currentFrame - _culledObjectsSizeFrames[i] > GPU_ASYNC_LATENCY)
@@ -870,12 +878,10 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
context->ResetRenderTarget();
}
// TODO: indirect lighting apply to get infinite bounces for GI
// TODO: explore atlas tiles optimization with feedback from renderer (eg. when tile is sampled by GI/Reflections mark it as used, then sort tiles by importance and prioritize updates for ones frequently used)
#undef WRITE_TILE
return false;
return notReady;
}
void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output)

View File

@@ -27,7 +27,8 @@ DDGIData DDGI;
GlobalSDFData GlobalSDF;
GlobalSurfaceAtlasData GlobalSurfaceAtlas;
GBufferData GBuffer;
float3 Padding0;
float2 Padding0;
float ResetBlend;
float IndirectLightingIntensity;
META_CB_END
@@ -228,8 +229,7 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
{
// Clear probe and return
//RWOutput[outputCoords] = float4(0, 0, 0, 0);
if (!skip)
RWOutput[outputCoords] = float4(0, 0, 0, 0);
//if (!skip) RWOutput[outputCoords] = float4(0, 0, 0, 0);
skip = true;
}
}
@@ -260,7 +260,7 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
if (skip)
{
// Clear probe
//RWOutput[outputCoords] = float4(0, 0, 0, 0);
RWOutput[outputCoords] = float4(0, 0, 0, 0);
return;
}
@@ -310,17 +310,15 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
// Blend current value with the previous probe data
float3 previous = RWOutput[outputCoords].rgb;
float historyWeight = DDGI.ProbeHistoryWeight;
if (dot(previous, previous) == 0)
{
// Cut any blend from zero
//historyWeight = 0.0f;
if (ResetBlend || dot(previous, previous) == 0)
historyWeight = 0.0f;
}
#if DDGI_PROBE_UPDATE_MODE == 0
result *= IndirectLightingIntensity;
#if DDGI_SRGB_BLENDING
result.rgb = pow(result.rgb, 1.0f / DDGI.IrradianceGamma);
#endif
float3 irradianceDelta = result.rgb - previous.rgb;
float3 irradianceDelta = result.rgb - previous;
float irradianceDeltaMax = Max3(abs(irradianceDelta));
if (irradianceDeltaMax > 0.25f)
{
@@ -330,12 +328,13 @@ void CS_UpdateProbes(uint3 DispatchThreadId : SV_DispatchThreadID, uint GroupInd
if (irradianceDeltaMax > 0.8f)
{
// Reduce flickering during rapid brightness changes
result.rgb = previous.rgb + (irradianceDelta * 0.25f);
result.rgb = previous + (irradianceDelta * 0.25f);
}
float3 resultDelta = (1.0f - historyWeight) * irradianceDelta;
if (Max3(result.rgb) < Max3(previous.rgb))
if (Max3(result.rgb) < Max3(previous))
resultDelta = min(max(abs(resultDelta), 1.0f / 1024.0f), abs(irradianceDelta)) * sign(resultDelta);
result = float4(previous.rgb + resultDelta, 1.0f);
result = float4(previous + resultDelta, 1.0f);
//result = float4(lerp(result.rgb, previous.rgb, historyWeight), 1.0f);
#else
result = float4(lerp(result.rg, previous.rg, historyWeight), 0.0f, 1.0f);
#endif

View File

@@ -117,6 +117,7 @@ float4 PS_Lighting(AtlasVertexOutput input) : SV_Target
// Sample irradiance
float bias = 1.0f;
float3 irradiance = SampleDDGIIrradiance(DDGI, ProbesState, ProbesDistance, ProbesIrradiance, gBuffer.WorldPos, gBuffer.Normal, bias);
//irradiance = 0;
// Calculate lighting
float3 diffuseColor = GetDiffuseColor(gBuffer);