diff options
Diffstat (limited to 'shaders/crt.frag.glsl')
| -rw-r--r-- | shaders/crt.frag.glsl | 39 |
1 files changed, 39 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); +} |
