diff --git a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax index fd74958c4..68f46f7d4 100644 --- a/Content/Editor/DebugMaterials/DDGIDebugProbes.flax +++ b/Content/Editor/DebugMaterials/DDGIDebugProbes.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2405a01ca57fed4112695e699036aa63a77e5140dadd7de957a353992ada02ca -size 41461 +oid sha256:a34e48c787818a3a22072142c6a51aa8dd37ae03a1f96526f6021302c6f6508a +size 41832 diff --git a/Content/Shaders/GI/DDGI.flax b/Content/Shaders/GI/DDGI.flax index 9e45adb50..5e5b5c8be 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:f3816b8fdd088656e385f46832c2719c77d386d12ec14ac3d0ac6df017b2c7e4 -size 23668 +oid sha256:a5e9fd224618c4b2b6850a843bf9452d49099bfc44549662c1544cf40510294c +size 24284 diff --git a/Content/Shaders/GI/GlobalSurfaceAtlas.flax b/Content/Shaders/GI/GlobalSurfaceAtlas.flax index 3450fa8c6..baf00844c 100644 --- a/Content/Shaders/GI/GlobalSurfaceAtlas.flax +++ b/Content/Shaders/GI/GlobalSurfaceAtlas.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c342070b981a0dbf335276434ce59f345861e8f9e7d4f2cf07ae2016542642e8 -size 12954 +oid sha256:3e56bf2cd056460a987fb98529e9a78ffa0bd7326ad9cae82145aa169c2dae4f +size 12952 diff --git a/Content/Shaders/VolumetricFog.flax b/Content/Shaders/VolumetricFog.flax index 997b1ab8f..f4990d1cc 100644 --- a/Content/Shaders/VolumetricFog.flax +++ b/Content/Shaders/VolumetricFog.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7fd020a2c82854ed852a2bb7682dc69b7abe31f139ecff485082d21d9188993d -size 14257 +oid sha256:1a3f3207746368c6d516d51e1053c08cbd4beea71703fa540b4229aa836cff14 +size 14255 diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index f2e9ffa8a..a1bf52c9d 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -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); } diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index 2414ddeca..9db25159f 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -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); diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h index a6bdc9e9e..75a45061d 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h @@ -34,7 +34,7 @@ public: struct BindingData { ConstantsData Constants; - GPUTextureView* ProbesState; + GPUTextureView* ProbesData; GPUTextureView* ProbesDistance; GPUTextureView* ProbesIrradiance; }; diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index d4760ba4e..e67ba36b2 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -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); diff --git a/Source/Engine/Renderer/VolumetricFogPass.cpp b/Source/Engine/Renderer/VolumetricFogPass.cpp index 44cad992b..72cd2bb00 100644 --- a/Source/Engine/Renderer/VolumetricFogPass.cpp +++ b/Source/Engine/Renderer/VolumetricFogPass.cpp @@ -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; diff --git a/Source/Shaders/GI/DDGI.hlsl b/Source/Shaders/GI/DDGI.hlsl index 8ae91b3a6..498475561 100644 --- a/Source/Shaders/GI/DDGI.hlsl +++ b/Source/Shaders/GI/DDGI.hlsl @@ -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 probesState, uint cascadeIndex, uint probeIndex) +// Loads probe probe data (encoded) +float4 LoadDDGIProbeData(DDGIData data, Texture2D 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 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 probesState, Texture2D probesDistance, Texture2D probesIrradiance, float3 worldPosition, float3 worldNormal, float bias = 0.2f, float dither = 0.0f) +float3 SampleDDGIIrradiance(DDGIData data, Texture2D probesData, Texture2D probesDistance, Texture2D 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 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 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 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); diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 4ecd185ec..5feb04557 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -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 RWProbesState : register(u0); +RWTexture2D RWProbesData : register(u0); RWByteAddressBuffer RWActiveProbes : register(u1); Texture3D 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 GlobalSurfaceAtlasObjects : register(t4); Texture2D GlobalSurfaceAtlasDepth : register(t5); Texture2D GlobalSurfaceAtlasTex : register(t6); -Texture2D ProbesState : register(t7); +Texture2D 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 RWOutput : register(u0); -Texture2D ProbesState : register(t0); +Texture2D ProbesData : register(t0); Texture2D 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 ProbesState : register(t4); +Texture2D ProbesData : register(t4); Texture2D ProbesDistance : register(t5); Texture2D 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); diff --git a/Source/Shaders/GI/GlobalSurfaceAtlas.shader b/Source/Shaders/GI/GlobalSurfaceAtlas.shader index 70b5ee9dc..95607e4da 100644 --- a/Source/Shaders/GI/GlobalSurfaceAtlas.shader +++ b/Source/Shaders/GI/GlobalSurfaceAtlas.shader @@ -87,7 +87,7 @@ float4 PS_ClearLighting(AtlasVertexOutput input) : SV_Target // GBuffer+Depth at 0-3 slots Buffer GlobalSurfaceAtlasObjects : register(t4); #if INDIRECT_LIGHT -Texture2D ProbesState : register(t5); +Texture2D ProbesData : register(t5); Texture2D ProbesDistance : register(t6); Texture2D 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 diff --git a/Source/Shaders/VolumetricFog.shader b/Source/Shaders/VolumetricFog.shader index 01756fe56..b24c2beae 100644 --- a/Source/Shaders/VolumetricFog.shader +++ b/Source/Shaders/VolumetricFog.shader @@ -286,7 +286,7 @@ Texture3D LightScatteringHistory : register(t2); Texture3D LocalShadowedLightScattering : register(t3); Texture2DArray ShadowMapCSM : register(t4); #if USE_DDGI -Texture2D ProbesState : register(t5); +Texture2D ProbesData : register(t5); Texture2D ProbesDistance : register(t6); Texture2D 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