CRT effect custom shader

This commit is contained in:
Kovid Goyal 2026-08-05 06:46:28 +05:30
parent 4aa5579c3c
commit d2cab32fe1
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
2 changed files with 40 additions and 2 deletions

View file

@ -755,8 +755,8 @@ setup_texture_as_render_target(unsigned width, unsigned height, GLuint *texture_
glBindTexture(GL_TEXTURE_2D, *texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// We use GL_RGBA16 to avoid incorrect colors due to quantization loss when
// blending, see https://github.com/kovidgoyal/kitty/issues/8953
static struct { bool ok; int fmt; } status = { false, GL_RGBA16};

View file

@ -0,0 +1,38 @@
#language slang 2026
// Original shader: https://www.shadertoy.com/view/WsVSzV (CC BY NC SA 3.0)
// Ported to slang for kitty
import kitty_custom_shader_types;
extern static const float warp = 0.25f; // simulates curvature of CRT monitor
extern static const float scan = 0.50f; // simulates darkness between scanlines
public float4 fragment_main(
float4 color,
KittyTextures t,
KittyCustomShaderData d,
float4 viewport
) {
// UV within the current viewport (0..1)
float2 uv = t.pos;
// Squared distance from center (drives curvature)
float2 dc = abs(0.5f - uv);
dc *= dc;
// Warp UV to simulate CRT screen curvature
uv.x -= 0.5f; uv.x *= 1.0f + (dc.y * (0.3f * warp)); uv.x += 0.5f;
uv.y -= 0.5f; uv.y *= 1.0f + (dc.x * (0.4f * warp)); uv.y += 0.5f;
// Original Y pixel coordinate within the viewport (for scanline phase)
float fragCoordY = (t.pos.y - viewport.y) * float(d.viewport_size_pixels.y);
// Scanline darkness at this pixel row
float apply = abs(sin(fragCoordY) * 0.25f * scan);
// Sample the backbuffer at the warped viewport UV
float2 sample_uv = viewport.xy + uv * viewport.zw;
float3 col = t.backbuffer.Sample(sample_uv).rgb;
return float4(lerp(col, float3(0.0f), apply), 1.0f);
}