diff --git a/dist/post_shaders/CartoonSoft.fx b/dist/post_shaders/CartoonSoft.fx new file mode 100644 index 0000000000..3fd7ef03f3 --- /dev/null +++ b/dist/post_shaders/CartoonSoft.fx @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project +// SPDX-FileCopyrightText: guest(r) +// SPDX-License-Identifier: GPL-2.0-or-later + +texture BackBufferTex : COLOR; +sampler BackBuffer { Texture = BackBufferTex; }; + +uniform float EdgeStrength < + ui_type = "slider"; + ui_label = "Edge Strength"; + ui_tooltip = "Darkness of the ink outline drawn around detected edges."; + ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; +> = 0.45; + +uniform float ShadowGuard < + ui_type = "slider"; + ui_label = "Shadow Guard"; + ui_tooltip = "Holds the outline back in dark areas. Raise it if shadows turn into black blobs."; + ui_min = 0.1; ui_max = 2.0; ui_step = 0.05; +> = 0.8; + +uniform float Levels < + ui_type = "slider"; + ui_label = "Colour Levels"; + ui_tooltip = "How many bands the colours are quantised into."; + ui_min = 2.0; ui_max = 16.0; ui_step = 1.0; +> = 6.0; + +uniform float Smoothing < + ui_type = "slider"; + ui_label = "Banding"; + ui_tooltip = "How far the picture is pushed towards flat bands."; + ui_min = 0.0; ui_max = 1.0; ui_step = 0.05; +> = 0.75; + +uniform float Saturation < + ui_type = "slider"; + ui_label = "Saturation"; + ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; +> = 1.15; + +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_CartoonSoft(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target +{ + float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + + float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb; + float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb; + float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb; + float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb; + float3 c11 = tex2D(BackBuffer, uv).rgb; + float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb; + float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb; + float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb; + float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb; + + const float3 dt = float3(1.0, 1.0, 1.0); + const float3 luma_weights = float3(0.299, 0.587, 0.114); + + float d1 = dot(abs(c00 - c22), dt); + float d2 = dot(abs(c20 - c02), dt); + float hl = dot(abs(c01 - c21), dt); + float vl = dot(abs(c10 - c12), dt); + + float luma = dot(c11, luma_weights); + float response = (d1 + d2 + hl + vl) / (luma * 2.0 + ShadowGuard); + float ink = 1.0 - saturate(response * EdgeStrength); + + float scaled = luma * Levels; + float step_position = frac(scaled); + float eased = step_position * step_position * (3.0 - 2.0 * step_position); + float banded = (floor(scaled) + eased) / Levels; + float target = lerp(luma, banded, Smoothing); + + float3 tinted = c11 * (target / max(luma, 0.001)); + float3 grey = dot(tinted, luma_weights); + float3 color = lerp(grey, tinted, Saturation) * ink; + + return float4(saturate(color), 1.0); +} + +technique CartoonSoft +{ + pass + { + VertexShader = VS_PostProcess; + PixelShader = PS_CartoonSoft; + } +} diff --git a/dist/post_shaders/Denoise.fx b/dist/post_shaders/Denoise.fx new file mode 100644 index 0000000000..fd8046204e --- /dev/null +++ b/dist/post_shaders/Denoise.fx @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +// SPDX-FileCopyrightText: Copyright 2019-2021 bloc97 +// SPDX-License-Identifier: MIT + +texture BackBufferTex : COLOR; +sampler BackBuffer { Texture = BackBufferTex; }; + +uniform float Strength < + ui_type = "slider"; + ui_label = "Strength"; + ui_min = 0.01; ui_max = 0.5; ui_step = 0.01; +> = 0.1; + +uniform float Radius < + ui_type = "slider"; + ui_label = "Radius"; + ui_min = 0.3; ui_max = 2.0; ui_step = 0.05; +> = 1.0; + +uniform float Curve < + ui_type = "slider"; + ui_label = "Shadow Bias"; + ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; +> = 1.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); +} + +float3 IntensityWeight(float3 value, float3 sigma, float3 centre) +{ + float3 scaled = (value - centre) / sigma; + return exp(-0.5 * scaled * scaled); +} + +float SpatialWeight(float distance, float sigma) +{ + float scaled = distance / sigma; + return exp(-0.5 * scaled * scaled); +} + +float4 PS_Denoise(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target +{ + float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); + + float3 centre = tex2D(BackBuffer, uv).rgb; + float3 intensity_sigma = max(pow(centre + 0.0001, Curve) * Strength, 0.0001); + float spatial_sigma = max(Radius, 0.05); + + float3 sum = float3(0.0, 0.0, 0.0); + float3 total = float3(0.0, 0.0, 0.0); + + for (int y = -2; y <= 2; ++y) + { + for (int x = -2; x <= 2; ++x) + { + float2 offset = float2(x, y); + float3 tap = tex2D(BackBuffer, uv + offset * texel).rgb; + float3 weight = IntensityWeight(tap, intensity_sigma, centre) * + SpatialWeight(length(offset), spatial_sigma); + sum += weight * tap; + total += weight; + } + } + + return float4(sum / total, 1.0); +} + +technique Denoise +{ + pass + { + VertexShader = VS_PostProcess; + PixelShader = PS_Denoise; + } +} diff --git a/dist/post_shaders/FakeGI.fx b/dist/post_shaders/FakeGI.fx deleted file mode 100644 index 399da96aad..0000000000 --- a/dist/post_shaders/FakeGI.fx +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -texture BackBufferTex : COLOR; -sampler BackBuffer { Texture = BackBufferTex; }; - -texture BrightTex { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; -sampler Bright { Texture = BrightTex; }; - -texture BounceTex { Width = BUFFER_WIDTH / 2; Height = BUFFER_HEIGHT / 2; Format = RGBA16F; }; -sampler BounceMap { Texture = BounceTex; }; - -uniform float Threshold < - ui_type = "slider"; - ui_label = "Light Threshold"; - ui_tooltip = "Luminance above which a pixel is treated as a light source."; - ui_min = 0.0; ui_max = 1.0; ui_step = 0.01; -> = 0.45; - -uniform float Radius < - ui_type = "slider"; - ui_label = "Bounce Radius"; - ui_tooltip = "How far light spreads onto neighbouring surfaces."; - ui_min = 0.5; ui_max = 8.0; ui_step = 0.1; -> = 3.0; - -uniform float Bounce < - ui_type = "slider"; - ui_label = "Bounce Strength"; - ui_tooltip = "Amount of coloured light bleeding onto the image."; - ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; -> = 0.7; - -uniform float Occlusion < - ui_type = "slider"; - ui_label = "Contact Shadows"; - ui_tooltip = "Darkening applied where a pixel is dimmer than its surroundings."; - ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; -> = 0.6; - -uniform float Saturation < - ui_type = "slider"; - ui_label = "Bounce Saturation"; - ui_tooltip = "How strongly the bounced light keeps the colour of its source."; - ui_min = 0.0; ui_max = 2.0; ui_step = 0.05; -> = 1.3; - -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 Luma(float3 color) -{ - return dot(color, float3(0.2126, 0.7152, 0.0722)); -} - -float4 PS_Extract(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target -{ - float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT); - - float3 sum = tex2D(BackBuffer, uv).rgb; - sum += tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb; - sum += tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb; - sum += tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb; - sum += tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb; - sum *= 0.2; - - float luma = Luma(sum); - float mask = saturate((luma - Threshold) / max(1.0 - Threshold, 0.0001)); - - float3 tint = lerp(float3(luma, luma, luma), sum, Saturation); - return float4(tint * mask * mask, 1.0); -} - -float4 PS_Spread(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target -{ - float2 unit = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT) * Radius * 8.0; - - const float2 dirs[8] = { - float2( 1.0, 0.0), float2(-1.0, 0.0), - float2( 0.0, 1.0), float2( 0.0, -1.0), - float2( 0.7071, 0.7071), float2(-0.7071, 0.7071), - float2( 0.7071, -0.7071), float2(-0.7071, -0.7071) - }; - - float3 sum = tex2D(Bright, uv).rgb; - float total = 1.0; - - for (int i = 0; i < 8; ++i) - { - sum += tex2D(Bright, uv + dirs[i] * unit * 0.45).rgb * 0.8; - sum += tex2D(Bright, uv + dirs[i] * unit).rgb * 0.5; - total += 1.3; - } - - return float4(sum / total, 1.0); -} - -float4 PS_Composite(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target -{ - float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT) * 2.0; - - float3 color = tex2D(BackBuffer, uv).rgb; - float centre = Luma(color); - - float around = Luma(tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb); - around += Luma(tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb); - around += Luma(tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb); - around += Luma(tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb); - around *= 0.25; - - float cavity = saturate(around - centre); - float shadow = 1.0 - cavity * Occlusion; - - float3 bounce = tex2D(BounceMap, uv).rgb; - float3 lit = color * shadow + bounce * Bounce * (1.0 - centre); - - return float4(saturate(lit), 1.0); -} - -technique FakeGI -{ - pass - { - VertexShader = VS_PostProcess; - PixelShader = PS_Extract; - RenderTarget = BrightTex; - } - pass - { - VertexShader = VS_PostProcess; - PixelShader = PS_Spread; - RenderTarget = BounceTex; - } - pass - { - VertexShader = VS_PostProcess; - PixelShader = PS_Composite; - } -}