diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-08 12:25:04 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | 172eb56fee0b6bde698e72be2bca55a90fe81ce9 (patch) | |
| tree | f2fd94709facf134c3670db4c1a20a5eaca1d53d /shaders | |
| parent | b91e5ebf8b529d0ced0bf18e83b17df0bd2374ce (diff) | |
| download | pardes-172eb56fee0b6bde698e72be2bca55a90fe81ce9.tar.gz pardes-172eb56fee0b6bde698e72be2bca55a90fe81ce9.zip | |
steam deck nice version
Diffstat (limited to 'shaders')
| -rw-r--r-- | shaders/crt.frag.glsl | 39 | ||||
| -rw-r--r-- | shaders/crt.vert.glsl | 9 |
2 files changed, 48 insertions, 0 deletions
diff --git a/shaders/crt.frag.glsl b/shaders/crt.frag.glsl new file mode 100644 index 00000000..1c9b15a8 --- /dev/null +++ b/shaders/crt.frag.glsl @@ -0,0 +1,39 @@ +#version 450 + +// The Crt builtin's post-process, one pass, fully static (no animation, no +// glitches). Screen point cc shows the scene at uv' = cc*(1 + BARREL*r2), +// and src/crt.zig maps mouse input through that same transform — keep them +// equal or clicks drift near the edges. + +layout(set = 2, binding = 0) uniform sampler2D u_scene; + +layout(location = 0) out vec4 o_col; + +const float BARREL = 0.012; // barrel curvature; MUST match src/crt.zig barrel +const float VIGNETTE = 0.07; // corner darkening: *= 1 - VIGNETTE*r2^2 +const vec2 PHOSPHOR = vec2(2.0, 2.0); // uv quantize cell in scene px (~1/7 of a glyph cell) +const float SCAN = 0.15; // scanline depth, one raised-cosine band per PHOSPHOR.y rows +const float CHROMA = 0.001; // R/B radial sample offset, grows toward the edges +const float BLOOM = 0.4; // bright-pass neighbor glow added back +const float BLOOM_MIN = 0.5; // channel level where the bright pass starts +const float LIFT = 1.08; // output brightness lift (offsets scan+vignette losses) + +void main() { + vec2 size = vec2(textureSize(u_scene, 0)); + vec2 cc = gl_FragCoord.xy / size * 2.0 - 1.0; + float r2 = dot(cc, cc); + vec2 uv = cc * (1.0 + BARREL * r2) * 0.5 + 0.5; + vec3 col = vec3(0.0); + if (all(greaterThanEqual(uv, vec2(0.0))) && all(lessThanEqual(uv, vec2(1.0)))) { + vec2 q = (floor(uv * size / PHOSPHOR) + 0.5) * PHOSPHOR / size; + vec2 ca = cc * (CHROMA * r2); + col = vec3(texture(u_scene, q + ca).r, texture(u_scene, q).g, texture(u_scene, q - ca).b); + vec2 px = PHOSPHOR / size; + vec3 nb = texture(u_scene, q + vec2(px.x, 0.0)).rgb + texture(u_scene, q - vec2(px.x, 0.0)).rgb + + texture(u_scene, q + vec2(0.0, px.y)).rgb + texture(u_scene, q - vec2(0.0, px.y)).rgb; + col += max(nb * 0.25 - BLOOM_MIN, 0.0) * BLOOM; + } + col *= 1.0 - VIGNETTE * r2 * r2; + col *= 1.0 - SCAN * (0.5 + 0.5 * cos(gl_FragCoord.y * 6.2831853 / PHOSPHOR.y)); + o_col = vec4(col * LIFT, 1.0); +} diff --git a/shaders/crt.vert.glsl b/shaders/crt.vert.glsl new file mode 100644 index 00000000..4e15fcdf --- /dev/null +++ b/shaders/crt.vert.glsl @@ -0,0 +1,9 @@ +#version 450 + +// CRT post-process pass: one fullscreen triangle from gl_VertexIndex, no +// vertex buffer. The fragment shader derives uv from gl_FragCoord. + +void main() { + vec2 p = vec2(float((gl_VertexIndex << 1) & 2), float(gl_VertexIndex & 2)); + gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0); +} |
