From 6d1fdb84f58ae666a649ebc31f22bf001e5cfe12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 14 Feb 2026 08:39:03 +0100 Subject: [PATCH] volumetric cloud reprojection: fallback to cloud map on disocclusion reduces noise --- .../shaders/volumetricCloud_reprojectCS.hlsl | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/WickedEngine/shaders/volumetricCloud_reprojectCS.hlsl b/WickedEngine/shaders/volumetricCloud_reprojectCS.hlsl index 022c15b8e..5c0c107f5 100644 --- a/WickedEngine/shaders/volumetricCloud_reprojectCS.hlsl +++ b/WickedEngine/shaders/volumetricCloud_reprojectCS.hlsl @@ -19,6 +19,16 @@ static const float2 temporalResponseMinMax = float2(0.86, 0.96); // When moving fast reprojection cannot catch up. This value eliminates the ghosting but results in clipping artefacts //#define ADDITIONAL_BOX_CLAMP +// Fallback to non-reprojected but slower updated cloudmap on disocclusions to avoid noisiness: +void cloudmap_fallback(float depth, float3 V, inout float4 result) +{ + if (depth == 0 && V.y > 0 && GetScene().texture_cloudmap >= 0) + { + float4 cloudmap = bindless_textures[descriptor_index(GetScene().texture_cloudmap)].SampleLevel(sampler_linear_clamp, encode_hemioct(V.xzy) * 0.5 + 0.5, 0); + result = cloudmap; + } +} + [numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)] void main(uint3 DTid : SV_DispatchThreadID) { @@ -80,6 +90,10 @@ void main(uint3 DTid : SV_DispatchThreadID) float2 depthResult = 0.0; float additionalResult = 0.0; + float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1).r; // Half res + float3 depthWorldPosition = reconstruct_position(uv, depth); + float tToDepthBuffer = length(depthWorldPosition - GetCamera().position); + float3 V = normalize(depthWorldPosition - GetCamera().position); #if 0 // Simple reprojection version if (shouldUpdatePixel) @@ -107,10 +121,6 @@ void main(uint3 DTid : SV_DispatchThreadID) float4 previousResult = cloud_history.SampleLevel(sampler_linear_clamp, prevUV, 0); float2 previousDepthResult = cloud_depth_history.SampleLevel(sampler_linear_clamp, prevUV, 0); float previousAdditionalResult = cloud_additional_history.SampleLevel(sampler_linear_clamp, prevUV, 0); - - float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1).r; // Half res - float3 depthWorldPosition = reconstruct_position(uv, depth); - float tToDepthBuffer = length(depthWorldPosition - GetCamera().position); // Fow now we use float values instead of half-float, we need to convert the cloud system to use kilometer unit and we can revert to half-float values tToDepthBuffer = depth == 0.0 ? FLT_MAX : tToDepthBuffer; @@ -122,6 +132,7 @@ void main(uint3 DTid : SV_DispatchThreadID) result = newResult; depthResult = newDepthResult; additionalResult = temporalResponseMinMax.x; + cloudmap_fallback(depth, V, result); } else { @@ -192,6 +203,7 @@ void main(uint3 DTid : SV_DispatchThreadID) result = neighborResult; depthResult = neighboorDepthResult; additionalResult = temporalResponseMinMax.x; + cloudmap_fallback(depth, V, result); } } } @@ -242,6 +254,7 @@ void main(uint3 DTid : SV_DispatchThreadID) result = cloud_current.SampleLevel(sampler_linear_clamp, uv, 0); depthResult = cloud_depth_current.SampleLevel(sampler_linear_clamp, uv, 0); additionalResult = temporalResponseMinMax.x; + cloudmap_fallback(depth, V, result); } output[DTid.xy] = result;