From 14842183f230fd50a607bcd8fb663da87ce2845c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 13 Jan 2026 13:12:19 +0100 Subject: [PATCH] Fix sky, skylight and reflections banding artifacts with a random noise #3254 #3318 --- Content/Shaders/Lights.flax | 4 ++-- Content/Shaders/Reflections.flax | 4 ++-- Content/Shaders/Sky.flax | 4 ++-- Source/Engine/Level/Actors/Sky.cpp | 3 ++- Source/Shaders/Lights.shader | 4 ++++ Source/Shaders/Reflections.shader | 8 +++++++- Source/Shaders/Sky.shader | 8 +++++++- 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Content/Shaders/Lights.flax b/Content/Shaders/Lights.flax index 727499080..10c79163f 100644 --- a/Content/Shaders/Lights.flax +++ b/Content/Shaders/Lights.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:68c138e5d710abb090551019a711eff083c61494a632e79b492a597776b8bf86 -size 5118 +oid sha256:95d0234fc09c18eee426229deec826177b99a568024628554602b295352943a2 +size 5281 diff --git a/Content/Shaders/Reflections.flax b/Content/Shaders/Reflections.flax index d5ac73593..923ff7889 100644 --- a/Content/Shaders/Reflections.flax +++ b/Content/Shaders/Reflections.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:28c80074ac502d5a931b91089fea7bc0c9d573e0bdd317623577833ff328aa8a -size 3107 +oid sha256:ff6a10c6be711d85ea5aaab4c1af4b1af6341b552883df4ad8efa9cb84d34661 +size 3287 diff --git a/Content/Shaders/Sky.flax b/Content/Shaders/Sky.flax index a568db451..f61c11f1e 100644 --- a/Content/Shaders/Sky.flax +++ b/Content/Shaders/Sky.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8541d1f0590167498f44da231f6de4f2938e15b26a5eb58e27b5067e1c882be8 -size 2252 +oid sha256:b202fec8285a8d4f51e327da20a8eeba161e1fbdbd7942ccaea51a7d9f7bd39f +size 2542 diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index 6d7d5efe2..7354f3bcf 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -24,7 +24,7 @@ GPU_CB_STRUCT(Data { Matrix WorldViewProjection; Matrix InvViewProjection; Float3 ViewOffset; - float Padding; + float NoiseScale; ShaderGBufferData GBuffer; ShaderAtmosphericFogData Fog; }); @@ -184,6 +184,7 @@ void Sky::ApplySky(GPUContext* context, RenderContext& renderContext, const Matr Matrix::Transpose(renderContext.View.IVP, data.InvViewProjection); GBufferPass::SetInputs(renderContext.View, data.GBuffer); data.ViewOffset = renderContext.View.Origin + GetPosition(); + data.NoiseScale = renderContext.View.IsSingleFrame ? 0.01f : 0.03f; InitConfig(data.Fog); //data.Fog.AtmosphericFogSunPower *= SunLight ? SunLight->Brightness : 1.0f; if (EnumHasNoneFlags(renderContext.View.Flags, ViewFlags::SpecularLight)) diff --git a/Source/Shaders/Lights.shader b/Source/Shaders/Lights.shader index 3ae0295b8..3a17f490c 100644 --- a/Source/Shaders/Lights.shader +++ b/Source/Shaders/Lights.shader @@ -8,6 +8,7 @@ #include "./Flax/IESProfile.hlsl" #include "./Flax/GBuffer.hlsl" #include "./Flax/Lighting.hlsl" +#include "./Flax/Noise.hlsl" // Per light data META_CB_BEGIN(0, PerLight) @@ -168,6 +169,9 @@ float4 PS_Sky(Model_VS2PS input) : SV_Target0 if (gBuffer.ShadingModel != SHADING_MODEL_UNLIT) { output = GetSkyLightLighting(Light, gBuffer, CubeImage); + + // Apply dithering to hide banding artifacts + output.rgb += rand2dTo1d(uv) * 0.02f * Luminance(saturate(output.rgb)); } return output; diff --git a/Source/Shaders/Reflections.shader b/Source/Shaders/Reflections.shader index dd0b695e5..56a95146e 100644 --- a/Source/Shaders/Reflections.shader +++ b/Source/Shaders/Reflections.shader @@ -4,6 +4,7 @@ #include "./Flax/MaterialCommon.hlsl" #include "./Flax/BRDF.hlsl" #include "./Flax/Random.hlsl" +#include "./Flax/Noise.hlsl" #include "./Flax/MonteCarlo.hlsl" #include "./Flax/LightingCommon.hlsl" #include "./Flax/GBuffer.hlsl" @@ -55,7 +56,12 @@ float4 PS_EnvProbe(Model_VS2PS input) : SV_Target0 } // Sample probe - return SampleReflectionProbe(gBufferData.ViewPos, Probe, PData, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness); + float4 color = SampleReflectionProbe(gBufferData.ViewPos, Probe, PData, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness); + + // Apply dithering to hide banding artifacts + color.rgb += rand2dTo1d(uv) * 0.02f * Luminance(saturate(color.rgb)); + + return color; } // Pixel Shader for reflections combine pass (additive rendering to the light buffer) diff --git a/Source/Shaders/Sky.shader b/Source/Shaders/Sky.shader index de29e5d3f..ea2012b26 100644 --- a/Source/Shaders/Sky.shader +++ b/Source/Shaders/Sky.shader @@ -4,13 +4,14 @@ #include "./Flax/MaterialCommon.hlsl" #include "./Flax/GBuffer.hlsl" #include "./Flax/Common.hlsl" +#include "./Flax/Noise.hlsl" #include "./Flax/AtmosphereFog.hlsl" META_CB_BEGIN(0, Data) float4x4 WorldViewProjection; float4x4 InvViewProjection; float3 ViewOffset; -float Padding; +float NoiseScale; GBufferData GBuffer; AtmosphericFogData AtmosphericFog; META_CB_END @@ -53,6 +54,11 @@ GBufferOutput PS_Sky(MaterialInput input) // Sample atmosphere color float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, gBufferData.ViewPos + ViewOffset, viewVector, gBufferData.ViewFar, float3(0, 0, 0)); + // Apply dithering to hide banding artifacts + float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); + float luminance = Luminance(saturate(color.rgb)); + color.rgb += rand2dTo1d(uv) * luminance * NoiseScale; + // Pack GBuffer output.Light = color; output.RT0 = float4(0, 0, 0, 0);