mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-08 13:11:02 +00:00
Math reviewed on shaders
This commit is contained in:
Vendored
+109
@@ -0,0 +1,109 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
texture BackBufferTex : COLOR;
|
||||
sampler BackBuffer { Texture = BackBufferTex; };
|
||||
|
||||
uniform float Radius <
|
||||
ui_type = "slider";
|
||||
ui_label = "Radius";
|
||||
ui_tooltip = "How far the blur reaches, in pixels.";
|
||||
ui_min = 1.0; ui_max = 12.0; ui_step = 0.5;
|
||||
> = 4.0;
|
||||
|
||||
uniform float Strength <
|
||||
ui_type = "slider";
|
||||
ui_label = "Strength";
|
||||
ui_tooltip = "Blend between the original image and the blurred one.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 1.0;
|
||||
|
||||
uniform float FocusSize <
|
||||
ui_type = "slider";
|
||||
ui_label = "Sharp Centre";
|
||||
ui_tooltip = "Size of the region left in focus at the centre of the screen. At zero the whole image is blurred evenly.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.0;
|
||||
|
||||
uniform float FocusSoftness <
|
||||
ui_type = "slider";
|
||||
ui_label = "Focus Falloff";
|
||||
ui_tooltip = "How gradually the sharp centre gives way to the blur.";
|
||||
ui_min = 0.05; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.4;
|
||||
|
||||
static const int TAPS = 17;
|
||||
static const float3 KERNEL[17] = {
|
||||
float3( 0.171499, 0.000000, 0.942873),
|
||||
float3(-0.219031, 0.200651, 0.838223),
|
||||
float3( 0.033526, -0.382014, 0.745189),
|
||||
float3( 0.276075, 0.360090, 0.662480),
|
||||
float3(-0.506631, -0.089616, 0.588951),
|
||||
float3( 0.479925, -0.305289, 0.523583),
|
||||
float3(-0.160526, 0.597147, 0.465471),
|
||||
float3(-0.306140, -0.589453, 0.413808),
|
||||
float3( 0.664200, 0.242565, 0.367879),
|
||||
float3(-0.690990, 0.285231, 0.327048),
|
||||
float3( 0.333103, -0.711821, 0.290749),
|
||||
float3( 0.246154, 0.784779, 0.258479),
|
||||
float3(-0.741912, -0.429953, 0.229790),
|
||||
float3( 0.870348, -0.191344, 0.204286),
|
||||
float3(-0.531160, 0.755520, 0.181612),
|
||||
float3(-0.122710, -0.946946, 0.161455),
|
||||
float3( 0.753320, 0.634899, 0.143535)
|
||||
};
|
||||
|
||||
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_Blur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
||||
{
|
||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
||||
float3 original = tex2D(BackBuffer, uv).rgb;
|
||||
|
||||
float2 centred = (uv - 0.5) * float2(BUFFER_WIDTH * BUFFER_RCP_HEIGHT, 1.0) * 2.0;
|
||||
float distance_from_centre = length(centred);
|
||||
float no_focus = 1.0 - step(0.001, FocusSize);
|
||||
float focus = max(smoothstep(FocusSize, FocusSize + FocusSoftness, distance_from_centre), no_focus);
|
||||
float amount = Strength * focus;
|
||||
|
||||
float angle = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453) * 6.2831853;
|
||||
float2 rotation = float2(cos(angle), sin(angle));
|
||||
|
||||
float3 sum = float3(0.0, 0.0, 0.0);
|
||||
float total = 0.0;
|
||||
for (int i = 0; i < TAPS; ++i)
|
||||
{
|
||||
float3 tap = KERNEL[i];
|
||||
float2 spun = float2(tap.x * rotation.x - tap.y * rotation.y,
|
||||
tap.x * rotation.y + tap.y * rotation.x);
|
||||
sum += tex2D(BackBuffer, uv + spun * texel * Radius).rgb * tap.z;
|
||||
total += tap.z;
|
||||
}
|
||||
|
||||
float3 blurred = sum / total;
|
||||
return float4(lerp(original, blurred, amount), 1.0);
|
||||
}
|
||||
|
||||
technique Blur <
|
||||
ui_label = "Blur";
|
||||
ui_tooltip = "Gaussian blur with an optional sharp centre, for softening the picture or faking depth of field.";
|
||||
>
|
||||
{
|
||||
pass
|
||||
{
|
||||
VertexShader = VS_PostProcess;
|
||||
PixelShader = PS_Blur;
|
||||
}
|
||||
}
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
texture BackBufferTex : COLOR;
|
||||
sampler BackBuffer { Texture = BackBufferTex; };
|
||||
|
||||
uniform float Bands <
|
||||
ui_type = "slider";
|
||||
ui_label = "Shading Bands";
|
||||
ui_tooltip = "How many flat steps the lighting is collapsed into. Three or four gives the classic look.";
|
||||
ui_min = 2.0; ui_max = 8.0; ui_step = 1.0;
|
||||
> = 4.0;
|
||||
|
||||
uniform float BandContrast <
|
||||
ui_type = "slider";
|
||||
ui_label = "Band Contrast";
|
||||
ui_tooltip = "Spreads the bands towards pure black and white. Lower it if the shadows crush.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.5;
|
||||
|
||||
uniform float BandEdge <
|
||||
ui_type = "slider";
|
||||
ui_label = "Band Edge";
|
||||
ui_tooltip = "Width of the transition between bands. Low values give hard cel steps.";
|
||||
ui_min = 0.02; ui_max = 1.0; ui_step = 0.02;
|
||||
> = 0.15;
|
||||
|
||||
uniform float Detail <
|
||||
ui_type = "slider";
|
||||
ui_label = "Texture Detail";
|
||||
ui_tooltip = "How much surface texture survives the flattening. At zero the bands are completely flat.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.6;
|
||||
|
||||
uniform float OutlineStrength <
|
||||
ui_type = "slider";
|
||||
ui_label = "Outline Strength";
|
||||
ui_tooltip = "Opacity of the ink line drawn along detected edges.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.8;
|
||||
|
||||
uniform float OutlineThreshold <
|
||||
ui_type = "slider";
|
||||
ui_label = "Outline Threshold";
|
||||
ui_tooltip = "How strong an edge has to be before it is inked. Raise it to keep ink off textures and specular highlights.";
|
||||
ui_min = 0.01; ui_max = 0.4; ui_step = 0.01;
|
||||
> = 0.18;
|
||||
|
||||
uniform float Saturation <
|
||||
ui_type = "slider";
|
||||
ui_label = "Saturation";
|
||||
ui_tooltip = "Colour intensity of the flat regions.";
|
||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
||||
> = 1.25;
|
||||
|
||||
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_CelShading(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
||||
{
|
||||
const float3 luma_weights = float3(0.2126, 0.7152, 0.0722);
|
||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
||||
|
||||
float3 centre = tex2D(BackBuffer, uv).rgb;
|
||||
float luma = dot(centre, luma_weights);
|
||||
|
||||
float2 near = texel * 1.5;
|
||||
float2 far = texel * 3.5;
|
||||
|
||||
float a00 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, -1.0)).rgb, luma_weights);
|
||||
float a20 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, -1.0)).rgb, luma_weights);
|
||||
float a02 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, 1.0)).rgb, luma_weights);
|
||||
float a22 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, 1.0)).rgb, luma_weights);
|
||||
|
||||
float b00 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, -1.0)).rgb, luma_weights);
|
||||
float b20 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, -1.0)).rgb, luma_weights);
|
||||
float b02 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, 1.0)).rgb, luma_weights);
|
||||
float b22 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, 1.0)).rgb, luma_weights);
|
||||
|
||||
float gx = (a00 + a02) - (a20 + a22);
|
||||
float gy = (a00 + a20) - (a02 + a22);
|
||||
float gradient = sqrt(gx * gx + gy * gy);
|
||||
float ink = smoothstep(OutlineThreshold, OutlineThreshold + 0.04, gradient);
|
||||
|
||||
float lighting = (a00 + a20 + a02 + a22 + b00 + b20 + b02 + b22) * 0.125;
|
||||
float detail = luma - lighting;
|
||||
|
||||
float softness = max(BandEdge, 0.001);
|
||||
float coord = lighting * Bands - softness * 0.5;
|
||||
float index = floor(coord) + smoothstep(1.0 - softness, 1.0, frac(coord));
|
||||
|
||||
float centred = (index + 0.5) / Bands;
|
||||
float stretched = index / max(Bands - 1.0, 1.0);
|
||||
float banded = saturate(lerp(centred, stretched, BandContrast));
|
||||
|
||||
float target = saturate(banded + detail * Detail);
|
||||
|
||||
float gain = min(target / max(luma, 0.001), 4.0);
|
||||
float3 shaded = centre * gain;
|
||||
float3 grey = dot(shaded, luma_weights);
|
||||
float3 color = lerp(grey, shaded, Saturation);
|
||||
color *= 1.0 - ink * OutlineStrength;
|
||||
|
||||
return float4(saturate(color), 1.0);
|
||||
}
|
||||
|
||||
technique CelShading <
|
||||
ui_label = "Cel Shading";
|
||||
ui_tooltip = "Collapses the lighting into a few hard steps and inks the edges, keeping texture detail and hue intact.";
|
||||
>
|
||||
{
|
||||
pass
|
||||
{
|
||||
VertexShader = VS_PostProcess;
|
||||
PixelShader = PS_CelShading;
|
||||
}
|
||||
}
|
||||
Vendored
-74
@@ -1,74 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// Ported from fakereflections.fsh in PPSSPP.
|
||||
|
||||
texture BackBufferTex : COLOR;
|
||||
sampler BackBuffer { Texture = BackBufferTex; };
|
||||
|
||||
uniform float Amount <
|
||||
ui_type = "slider";
|
||||
ui_label = "Amount";
|
||||
ui_tooltip = "Strength of the reflection added to the lower half of the screen.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.6;
|
||||
|
||||
uniform float Power <
|
||||
ui_type = "slider";
|
||||
ui_label = "Power";
|
||||
ui_tooltip = "How sharply the reflection falls off away from bright areas.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.5;
|
||||
|
||||
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 Wrap(float value, float period)
|
||||
{
|
||||
return period * frac(value / period);
|
||||
}
|
||||
|
||||
float4 PS_FakeReflections(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
||||
{
|
||||
float3 color = tex2D(BackBuffer, uv).rgb;
|
||||
|
||||
float gray = (color.r + color.g + color.b) / 3.0;
|
||||
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
|
||||
|
||||
float rndx = Wrap(uv.x + gray, 0.03) + Wrap(uv.y + saturation, 0.05);
|
||||
float rndy = Wrap(uv.y + saturation, 0.03) + Wrap(uv.x + gray, 0.05);
|
||||
|
||||
float falloff = (max(gray, saturation) + 0.1) * uv.y;
|
||||
float2 offset = float2(rndx, rndy - min(uv.y, 0.25)) * falloff;
|
||||
|
||||
float3 reflection = tex2D(BackBuffer, uv + offset).rgb;
|
||||
reflection *= 4.0 * (1.0 - gray) * Amount;
|
||||
reflection *= reflection * falloff * Power;
|
||||
|
||||
return float4(saturate(color + reflection), 1.0);
|
||||
}
|
||||
|
||||
technique FakeReflections <
|
||||
ui_label = "Fake Reflections";
|
||||
ui_tooltip = "Adds a wet looking reflection across the lower half of the screen.";
|
||||
>
|
||||
{
|
||||
pass
|
||||
{
|
||||
VertexShader = VS_PostProcess;
|
||||
PixelShader = PS_FakeReflections;
|
||||
}
|
||||
}
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
texture BackBufferTex : COLOR;
|
||||
sampler BackBuffer { Texture = BackBufferTex; };
|
||||
|
||||
uniform float Timer < source = "timer"; > = 0.0;
|
||||
|
||||
uniform float Horizon <
|
||||
ui_type = "slider";
|
||||
ui_label = "Reflection Line";
|
||||
ui_tooltip = "Height on screen where the reflective floor begins. Everything above it is left untouched.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
||||
> = 0.55;
|
||||
|
||||
uniform float Amount <
|
||||
ui_type = "slider";
|
||||
ui_label = "Amount";
|
||||
ui_tooltip = "How strongly the reflection shows through the floor.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.35;
|
||||
|
||||
uniform float Falloff <
|
||||
ui_type = "slider";
|
||||
ui_label = "Falloff";
|
||||
ui_tooltip = "How quickly the reflection fades as the floor comes towards the viewer. At zero it stays even.";
|
||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
|
||||
> = 1.2;
|
||||
|
||||
uniform float Perspective <
|
||||
ui_type = "slider";
|
||||
ui_label = "Perspective";
|
||||
ui_tooltip = "Stretches or squashes the mirrored image. One is a true mirror, higher values pull it towards the line.";
|
||||
ui_min = 0.2; ui_max = 2.0; ui_step = 0.05;
|
||||
> = 1.0;
|
||||
|
||||
uniform float Ripple <
|
||||
ui_type = "slider";
|
||||
ui_label = "Ripple";
|
||||
ui_tooltip = "Amplitude of the waves disturbing the reflection. At zero the mirror is perfectly still.";
|
||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
||||
> = 0.0;
|
||||
|
||||
uniform float RippleSpeed <
|
||||
ui_type = "slider";
|
||||
ui_label = "Ripple Speed";
|
||||
ui_tooltip = "How fast the waves travel.";
|
||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
|
||||
> = 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);
|
||||
}
|
||||
|
||||
float4 PS_Reflections(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
||||
{
|
||||
float3 color = tex2D(BackBuffer, uv).rgb;
|
||||
|
||||
float depth = uv.y - Horizon;
|
||||
float on_floor = step(0.0, depth);
|
||||
float span = max(1.0 - Horizon, 0.001);
|
||||
float distance_down = saturate(depth / span);
|
||||
|
||||
float seconds = Timer * 0.001;
|
||||
float wave = sin(uv.x * 38.0 + seconds * RippleSpeed * 2.0) *
|
||||
sin(uv.y * 21.0 - seconds * RippleSpeed * 1.3);
|
||||
float2 disturbance = float2(wave * 0.004, wave * 0.002) * Ripple * distance_down;
|
||||
|
||||
float2 mirrored = float2(uv.x, Horizon - depth * Perspective) + disturbance;
|
||||
float3 reflection = tex2D(BackBuffer, saturate(mirrored)).rgb;
|
||||
|
||||
float fade = pow(max(1.0 - distance_down, 0.0001), Falloff);
|
||||
float strength = Amount * fade * on_floor;
|
||||
|
||||
return float4(lerp(color, reflection, strength), 1.0);
|
||||
}
|
||||
|
||||
technique Reflections <
|
||||
ui_label = "Reflections";
|
||||
ui_tooltip = "Mirrors the picture into a reflective floor below a line you choose, with optional water ripples.";
|
||||
>
|
||||
{
|
||||
pass
|
||||
{
|
||||
VertexShader = VS_PostProcess;
|
||||
PixelShader = PS_Reflections;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user