From fcaea7d502b006cfeae872f7c07358c1efea8ede Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 7 Sep 2026 06:20:31 -0400 Subject: [PATCH] Messing around with chromatic aberration fx --- dist/post_shaders/ChromaticAberration.fx | 58 +++++++++++ dist/post_shaders/Deband.fx | 96 +++++++++++++++++++ .../renderer_vulkan/present/post_process.cpp | 2 +- 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 dist/post_shaders/ChromaticAberration.fx create mode 100644 dist/post_shaders/Deband.fx diff --git a/dist/post_shaders/ChromaticAberration.fx b/dist/post_shaders/ChromaticAberration.fx new file mode 100644 index 0000000000..b5065a83c5 --- /dev/null +++ b/dist/post_shaders/ChromaticAberration.fx @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +texture BackBufferTex : COLOR; +sampler BackBuffer { Texture = BackBufferTex; }; + +uniform float Strength < + ui_type = "slider"; + ui_label = "Strength"; + ui_tooltip = "Channel separation in pixels, measured at the edge of the screen."; + ui_min = 0.0; ui_max = 8.0; ui_step = 0.1; +> = 1.5; + +uniform float Falloff < + ui_type = "slider"; + ui_label = "Falloff"; + ui_tooltip = "How fast the separation grows away from the centre. Higher keeps the middle clean."; + ui_min = 1.0; ui_max = 4.0; ui_step = 0.1; +> = 2.0; + +void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) +{ + uv = float2(0.0, 0.0); + if (id == 2) + { + uv.x = 2.0; + } + if (id == 1) + { + uv.y = 2.0; + } + pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +} + +float4 PS_ChromaticAberration(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target +{ + float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + + float2 direction = uv - float2(0.5, 0.5); + float radius = length(direction); + float2 unit = direction / max(radius, 0.0001); + float2 offset = unit * Strength * pow(radius * 2.0, Falloff) * texel; + + float red = tex2D(BackBuffer, uv + offset).r; + float green = tex2D(BackBuffer, uv).g; + float blue = tex2D(BackBuffer, uv - offset).b; + + return float4(red, green, blue, 1.0); +} + +technique ChromaticAberration +{ + pass + { + VertexShader = VS_PostProcess; + PixelShader = PS_ChromaticAberration; + } +} diff --git a/dist/post_shaders/Deband.fx b/dist/post_shaders/Deband.fx new file mode 100644 index 0000000000..25b3b315d4 --- /dev/null +++ b/dist/post_shaders/Deband.fx @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2015 Niklas Haas +// SPDX-License-Identifier: MIT + +texture BackBufferTex : COLOR; +sampler BackBuffer { Texture = BackBufferTex; }; + +uniform float Threshold < + ui_type = "slider"; + ui_label = "Threshold"; + ui_tooltip = "How flat a neighbourhood must be before it gets smoothed. Raise it to catch wider bands, lower it to keep more detail."; + ui_min = 0.002; ui_max = 0.05; ui_step = 0.001; +> = 0.012; + +uniform float Radius < + ui_type = "slider"; + ui_label = "Radius"; + ui_tooltip = "How far the sampling reaches, in pixels. Wider gradients need a larger radius."; + ui_min = 1.0; ui_max = 32.0; ui_step = 1.0; +> = 8.0; + +uniform float Grain < + ui_type = "slider"; + ui_label = "Dither"; + ui_tooltip = "Noise added to break up whatever banding survives the smoothing."; + ui_min = 0.0; ui_max = 0.02; ui_step = 0.001; +> = 0.004; + +void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD) +{ + uv = float2(0.0, 0.0); + if (id == 2) + { + uv.x = 2.0; + } + if (id == 1) + { + uv.y = 2.0; + } + pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0); +} + +float Hash(float2 p) +{ + float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031); + scattered += dot(scattered, scattered.yzx + 33.33); + return frac((scattered.x + scattered.y) * scattered.z); +} + +float4 PS_Deband(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target +{ + float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + + float3 centre = tex2D(BackBuffer, uv).rgb; + float base = Hash(pos.xy) * 6.2831853; + + float3 total = float3(0.0, 0.0, 0.0); + float3 deviation = float3(0.0, 0.0, 0.0); + + for (int ring = 1; ring <= 2; ++ring) + { + float angle = base + float(ring) * 2.3999632; + float reach = Radius * float(ring) * 0.5; + float2 along = float2(cos(angle), sin(angle)) * reach; + float2 across = float2(-along.y, along.x); + + float3 s0 = tex2D(BackBuffer, uv + along * texel).rgb; + float3 s1 = tex2D(BackBuffer, uv - along * texel).rgb; + float3 s2 = tex2D(BackBuffer, uv + across * texel).rgb; + float3 s3 = tex2D(BackBuffer, uv - across * texel).rgb; + + total += s0 + s1 + s2 + s3; + deviation = max(deviation, max(max(abs(s0 - centre), abs(s1 - centre)), + max(abs(s2 - centre), abs(s3 - centre)))); + } + + float3 average = total * 0.125; + float3 flatness = float3(1.0, 1.0, 1.0) - + smoothstep(Threshold * 0.5, Threshold, deviation); + float3 result = lerp(centre, average, flatness); + + float dither = (Hash(pos.xy + float2(71.3, 41.7)) - 0.5) * Grain; + + return float4(saturate(result + dither), 1.0); +} + +technique Deband +{ + pass + { + VertexShader = VS_PostProcess; + PixelShader = PS_Deband; + } +} diff --git a/src/video_core/renderer_vulkan/present/post_process.cpp b/src/video_core/renderer_vulkan/present/post_process.cpp index bb01b6be12..07d75b7025 100644 --- a/src/video_core/renderer_vulkan/present/post_process.cpp +++ b/src/video_core/renderer_vulkan/present/post_process.cpp @@ -567,7 +567,7 @@ bool PostProcessChain::BuildEffects(const Device& device, MemoryAllocator& alloc entry_binding.binding = binding.entry_point_binding; entry_binding.sampler_index = binding.index; out.sampler_bindings.push_back(entry_binding); - binding_count = std::max(binding_count, binding.entry_point_binding + 1); + binding_count = std::max(binding_count, binding.entry_point_binding + 1); } const std::vector sampler_types(