kiss3d 0.45.0

Keep it simple, stupid, 2D and 3D graphics engine for Rust.
Documentation
import package::common::fullscreen_uv_from_clip;
// CRT stylization post-process: screen curvature (barrel distortion), chromatic
// aberration, scanlines and a vignette. Reads the rendered scene and writes the
// stylized image to the output. Knobs come from `CrtUniforms`; any term can be
// disabled by zeroing its strength.

@group(0) @binding(0)
var t_fbo: texture_2d<f32>;
@group(0) @binding(1)
var s_fbo: sampler;

struct CrtUniforms {
    // Barrel-distortion strength (0 = flat).
    curvature: f32,
    // Chromatic-aberration strength (UV units at the screen edge).
    aberration: f32,
    // Scanline darkening intensity in [0, 1].
    scanline_intensity: f32,
    // Number of scanlines down the screen.
    scanline_count: f32,
    // Vignette strength in [0, 1].
    vignette: f32,
    _pad0: f32,
    _pad1: f32,
    _pad2: f32,
}

@group(1) @binding(0)
var<uniform> uniforms: CrtUniforms;

struct VertexInput {
    @location(0) position: vec2<f32>,
}

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) tex_coord: vec2<f32>,
}

@vertex
fn vs_main(vertex: VertexInput) -> VertexOutput {
    var out: VertexOutput;
    out.clip_position = vec4<f32>(vertex.position, 0.0, 1.0);
    out.tex_coord = fullscreen_uv_from_clip(vertex.position);
    return out;
}

// Barrel-distort UVs around the screen center to fake a curved CRT tube.
fn curve(uv: vec2<f32>, amount: f32) -> vec2<f32> {
    var c = uv * 2.0 - vec2<f32>(1.0);
    let offset = c.yx * c.yx * amount;
    c += c * offset;
    return c * 0.5 + vec2<f32>(0.5);
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    let uv = curve(in.tex_coord, uniforms.curvature);

    // Outside the curved tube reads as black (the bezel).
    if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
        return vec4<f32>(0.0, 0.0, 0.0, 1.0);
    }

    // Chromatic aberration: offset the R/B taps outward from the center, scaled by
    // distance so the fringing grows toward the edges.
    let from_center = uv - vec2<f32>(0.5);
    let offset = from_center * uniforms.aberration;
    // Explicit LOD: the bezel `return` above makes this non-uniform control flow,
    // where implicit-LOD sampling is illegal (and there's no mip chain anyway).
    let r = textureSampleLevel(t_fbo, s_fbo, uv + offset, 0.0).r;
    let g = textureSampleLevel(t_fbo, s_fbo, uv, 0.0).g;
    let b = textureSampleLevel(t_fbo, s_fbo, uv - offset, 0.0).b;
    var color = vec3<f32>(r, g, b);

    // Scanlines: a sinusoidal darkening along rows.
    let scan = sin(uv.y * uniforms.scanline_count * 3.14159265);
    color *= 1.0 - uniforms.scanline_intensity * (0.5 + 0.5 * scan);

    // Vignette: darken toward the corners.
    let vig = 1.0 - uniforms.vignette * dot(from_center, from_center) * 2.0;
    color *= clamp(vig, 0.0, 1.0);

    return vec4<f32>(color, 1.0);
}