diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index 98fdcad04..1982e532e 100644 --- a/Content/Shaders/GI/DDGI.flax +++ b/Content/Shaders/GI/DDGI.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e57f5363c7e39b61123d748ea9134f16ae7d67208cb0c7aeb1e2bae3479a7e77 -size 19642 +oid sha256:f53f603799652bb3cfba5b25388fa0c7bad4745c1128d891c61ccff5bac70fb6 +size 19937 diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h index 3f7a53d48..4a3524c2a 100644 --- a/Source/Engine/Graphics/PostProcessSettings.h +++ b/Source/Engine/Graphics/PostProcessSettings.h @@ -333,7 +333,7 @@ API_STRUCT() struct FLAXENGINE_API GlobalIlluminationSettings : ISerializable /// Defines how quickly GI blends between the the current frame and the history buffer. Lower values update GI faster, but with more jittering and noise. If the camera in your game doesn't move much, we recommend values closer to 1. /// API_FIELD(Attributes="EditorOrder(20), Limit(0, 1), PostProcessSetting((int)GlobalIlluminationSettingsOverride.TemporalResponse)") - float TemporalResponse = 0.8f; + float TemporalResponse = 0.9f; /// /// Draw distance of the Global Illumination effect. Scene outside the range will use fallback irradiance. diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index e2598c315..1ffc38f2f 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -34,7 +34,7 @@ // This must match HLSL #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_GROUP_SIZE_X 32 -#define DDGI_TRACE_RAYS_LIMIT 512 // Limit of rays per-probe (runtime value can be smaller) +#define DDGI_TRACE_RAYS_LIMIT 256 // Limit of rays per-probe (runtime value can be smaller) #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_PROBE_UPDATE_BORDERS_GROUP_SIZE 8 @@ -268,26 +268,30 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, // Setup options auto& settings = renderContext.List->Settings.GlobalIllumination; - // TODO: implement GI Quality to affect cascades update rate, probes spacing and rays count per probe const float probesSpacing = 100.0f; // GI probes placement spacing nearby camera (for closest cascade; gets automatically reduced for further cascades) + int32 probeRaysCount; switch (Graphics::GIQuality) { case Quality::Low: + probeRaysCount = 96; break; case Quality::Medium: + probeRaysCount = 128; break; case Quality::High: + probeRaysCount = 192; break; case Quality::Ultra: default: + probeRaysCount = 256; break; } + ASSERT_LOW_LAYER(Math::Min(Math::AlignUp(probeRaysCount, DDGI_TRACE_RAYS_GROUP_SIZE_X), DDGI_TRACE_RAYS_LIMIT) == probeRaysCount); bool debugProbes = false; // TODO: add debug option to draw probes locations -> in Graphics window - Editor-only const float indirectLightingIntensity = settings.Intensity; const float probeHistoryWeight = Math::Clamp(settings.TemporalResponse, 0.0f, 0.98f); const float distance = settings.Distance; const Color fallbackIrradiance = settings.FallbackIrradiance; - 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 // Automatically calculate amount of cascades to cover the GI distance at the current probes spacing const int32 idealProbesCount = 20; // Ideal amount of probes per-cascade to try to fit in order to cover whole distance diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 37e07140d..6a1735063 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -546,11 +546,8 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex } // Perform batched chunks rasterization - if (!anyDraw) - { - anyDraw = true; - context->ResetSR(); - } + anyDraw = true; + context->ResetSR(); ModelsRasterizeData data; data.CascadeCoordToPosMul = (Float3)cascadeBounds.GetSize() / (float)resolution; data.CascadeCoordToPosAdd = (Float3)cascadeBounds.Minimum + cascadeVoxelSize * 0.5f; diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 9484155c5..2cf4ae36e 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -17,7 +17,7 @@ #include "./Flax/GI/DDGI.hlsl" // This must match C++ -#define DDGI_TRACE_RAYS_LIMIT 512 // Limit of rays per-probe (runtime value can be smaller) +#define DDGI_TRACE_RAYS_LIMIT 256 // Limit of rays per-probe (runtime value can be smaller) #define DDGI_TRACE_RAYS_GROUP_SIZE_X 32 #define DDGI_PROBE_UPDATE_BORDERS_GROUP_SIZE 8 #define DDGI_PROBE_CLASSIFY_GROUP_SIZE 32 @@ -207,12 +207,13 @@ void CS_TraceRays(uint3 DispatchThreadId : SV_DispatchThreadID) #if DDGI_PROBE_UPDATE_MODE == 0 // Update irradiance #define DDGI_PROBE_RESOLUTION DDGI_PROBE_RESOLUTION_IRRADIANCE +groupshared float4 CachedProbesTraceRadiance[DDGI_TRACE_RAYS_LIMIT]; #else // Update distance #define DDGI_PROBE_RESOLUTION DDGI_PROBE_RESOLUTION_DISTANCE +groupshared float CachedProbesTraceDistance[DDGI_TRACE_RAYS_LIMIT]; #endif -groupshared float4 CachedProbesTraceRadiance[DDGI_TRACE_RAYS_LIMIT]; groupshared float3 CachedProbesTraceDirection[DDGI_TRACE_RAYS_LIMIT]; RWTexture2D RWOutput : register(u0); @@ -243,6 +244,15 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ if (probeState == DDGI_PROBE_STATE_INACTIVE) skip = true; +#if DDGI_PROBE_UPDATE_MODE == 0 + uint backfacesCount = 0; + uint backfacesLimit = uint(DDGI.RaysCount * 0.1f); +#else + float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w; + float distanceLimit = length(probesSpacing) * 1.5f; +#endif + + BRANCH if (!skip) { // Load trace rays results into shared memory to reuse across whole thread group (raysCount per thread) @@ -252,7 +262,12 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ for (uint i = 0; i < raysCount; i++) { uint rayIndex = raysStart + i; +#if DDGI_PROBE_UPDATE_MODE == 0 CachedProbesTraceRadiance[rayIndex] = ProbesTrace[uint2(rayIndex, GroupId.x)]; +#else + float rayDistance = ProbesTrace[uint2(rayIndex, GroupId.x)].w; + CachedProbesTraceDistance[rayIndex] = min(abs(rayDistance), distanceLimit); +#endif CachedProbesTraceDirection[rayIndex] = GetProbeRayDirection(DDGI, rayIndex); } } @@ -289,21 +304,14 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ // Loop over rays float4 result = float4(0, 0, 0, 0); -#if DDGI_PROBE_UPDATE_MODE == 0 - uint backfacesCount = 0; - uint backfacesLimit = uint(DDGI.RaysCount * 0.1f); -#else - float probesSpacing = DDGI.ProbesOriginAndSpacing[CascadeIndex].w; - float distanceLimit = length(probesSpacing) * 1.5f; -#endif LOOP for (uint rayIndex = 0; rayIndex < DDGI.RaysCount; rayIndex++) { float3 rayDirection = CachedProbesTraceDirection[rayIndex]; float rayWeight = max(dot(octahedralDirection, rayDirection), 0.0f); - float4 rayRadiance = CachedProbesTraceRadiance[rayIndex]; #if DDGI_PROBE_UPDATE_MODE == 0 + float4 rayRadiance = CachedProbesTraceRadiance[rayIndex]; if (rayRadiance.w < 0.0f) { // Count backface hits @@ -325,7 +333,7 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ rayWeight = pow(rayWeight, 10.0f); // Add distance (R), distance^2 (G) and weight (A) - float rayDistance = min(abs(rayRadiance.w), distanceLimit); + float rayDistance = CachedProbesTraceDistance[rayIndex]; result += float4(rayDistance * rayWeight, (rayDistance * rayDistance) * rayWeight, 0.0f, rayWeight); #endif } @@ -351,18 +359,18 @@ void CS_UpdateProbes(uint3 GroupThreadId : SV_GroupThreadID, uint3 GroupId : SV_ if (irradianceDeltaMax > 0.2f) { // Reduce history weight after significant lighting change - historyWeight = max(historyWeight - 0.7f, 0.0f); + historyWeight = max(historyWeight - 0.9f, 0.0f); } if (irradianceDeltaLen > 2.0f) { // Reduce flickering during rapid brightness changes - result.rgb = previous + (irradianceDelta * 0.25f); + //result.rgb = previous + (irradianceDelta * 0.25f); } float3 resultDelta = (1.0f - historyWeight) * irradianceDelta; if (Max3(result.rgb) < Max3(previous)) resultDelta = min(max(abs(resultDelta), 1.0f / 1024.0f), abs(irradianceDelta)) * sign(resultDelta); - result = float4(previous + resultDelta, 1.0f); - //result = float4(lerp(result.rgb, previous.rgb, historyWeight), 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