diff --git a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp index 1ae9ee20e..c0042edbf 100644 --- a/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp +++ b/Source/Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.cpp @@ -487,6 +487,7 @@ bool DynamicDiffuseGlobalIlluminationPass::Render(RenderContext& renderContext, PROFILE_GPU_CPU("Probes Classification"); uint32 threadGroups = Math::DivideAndRoundUp(probesCountCascade, DDGI_PROBE_CLASSIFY_GROUP_SIZE); bindingDataSDF.BindCascades(context, 0); + bindingDataSDF.BindCascadeMips(context, 4); context->BindUA(0, ddgiData.Result.ProbesState); for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++) { diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index d50a9af74..bb90c6a32 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -61,6 +61,7 @@ float3 GetProbeRayDirection(DDGIData data, uint rayIndex) RWTexture2D RWProbesState : register(u0); Texture3D GlobalSDFTex[4] : register(t0); +Texture3D GlobalSDFMip[4] : register(t4); // Compute shader for updating probes state between active and inactive. META_CS(true, FEATURE_LEVEL_SM5) @@ -84,10 +85,10 @@ void CS_Classify(uint3 DispatchThreadId : SV_DispatchThreadID) // Use Global SDF to quickly get distance and direction to the scene geometry float sdf; - float3 sdfNormal = normalize(SampleGlobalSDFGradient(GlobalSDF, GlobalSDFTex, probePosition.xyz, sdf)); + float3 sdfNormal = normalize(SampleGlobalSDFGradient(GlobalSDF, GlobalSDFTex, GlobalSDFMip, probePosition.xyz, sdf)); float sdfDst = abs(sdf); float threshold = GlobalSDF.CascadeVoxelSize[CascadeIndex]; - float distanceLimit = length(probesSpacing) * 2.0f; + float distanceLimit = length(probesSpacing) * 1.5f; float relocateLimit = length(probesSpacing) * 0.6f; if (sdfDst > distanceLimit) // Probe is too far from geometry { diff --git a/Source/Shaders/GlobalSignDistanceField.hlsl b/Source/Shaders/GlobalSignDistanceField.hlsl index e7b4c99c1..da41b1854 100644 --- a/Source/Shaders/GlobalSignDistanceField.hlsl +++ b/Source/Shaders/GlobalSignDistanceField.hlsl @@ -114,6 +114,45 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex[4] return gradient; } +// Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector. +float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex[4], Texture3D mips[4], float3 worldPosition, out float distance) +{ + float3 gradient = float3(0, 0.00001f, 0); + distance = GLOBAL_SDF_WORLD_SIZE; + if (data.CascadePosDistance[3].w <= 0.0f) + return gradient; + float chunkSizeDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_SIZE / data.Resolution; // Size of the chunk in SDF distance (0-1) + float chunkMarginDistance = (float)GLOBAL_SDF_RASTERIZE_CHUNK_MARGIN / data.Resolution; // Size of the chunk margin in SDF distance (0-1) + UNROLL + for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + { + float4 cascadePosDistance = data.CascadePosDistance[cascade]; + float cascadeMaxDistance = cascadePosDistance.w * 2; + float3 posInCascade = worldPosition - cascadePosDistance.xyz; + float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f; + float cascadeDistance = mips[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0); + if (cascadeDistance < chunkSizeDistance && !any(cascadeUV < 0) && !any(cascadeUV > 1)) + { + float cascadeDistanceTex = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0); + if (cascadeDistanceTex < chunkMarginDistance * 2) + { + cascadeDistance = cascadeDistanceTex; + } + float texelOffset = 1.0f / data.Resolution; + float xp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x + texelOffset, cascadeUV.y, cascadeUV.z), 0).x; + float xn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x - texelOffset, cascadeUV.y, cascadeUV.z), 0).x; + float yp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y + texelOffset, cascadeUV.z), 0).x; + float yn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y - texelOffset, cascadeUV.z), 0).x; + float zp = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z + texelOffset), 0).x; + float zn = tex[cascade].SampleLevel(SamplerLinearClamp, float3(cascadeUV.x, cascadeUV.y, cascadeUV.z - texelOffset), 0).x; + gradient = float3(xp - xn, yp - yn, zp - zn) * cascadeMaxDistance; + distance = cascadeDistance * cascadeMaxDistance; + break; + } + } + return gradient; +} + // Ray traces the Global SDF. GlobalSDFHit RayTraceGlobalSDF(const GlobalSDFData data, Texture3D tex[4], Texture3D mips[4], const GlobalSDFTrace trace) {