kiss3d 0.45.0

Keep it simple, stupid, 2D and 3D graphics engine for Rust.
Documentation
// Visualizes raw AOV buffers (linear depth, encoded normals, segmentation ids)
// as display-ready colors, with a fullscreen triangle.
//
// Two fragment entry points share the vertex stage: `fs_float` reads the float
// AOV texture (depth or normals, selected by `params.x`), `fs_seg` reads the
// integer segmentation texture. Each pipeline's bind group layout only covers
// the bindings its entry point uses.
//
// params:
//   x: float mode (0 = depth, 1 = normals)
//   y: depth range in world units (depth mode only)
//   z: 1.0 when the target is an sRGB format. The visualization is computed in
//      display space (matching the CPU `snap_*` images); linearizing it first
//      makes the hardware sRGB encode round-trip to the intended value.

struct VisUniforms {
    params: vec4<f32>,
}

@group(0) @binding(0) var<uniform> uni: VisUniforms;
@group(0) @binding(1) var t_float: texture_2d<f32>;
@group(0) @binding(2) var t_seg: texture_2d<u32>;

struct VsOut {
    @builtin(position) pos: vec4<f32>,
}

@vertex
fn vs_main(@builtin(vertex_index) vi: u32) -> VsOut {
    // Fullscreen triangle.
    var out: VsOut;
    let uv = vec2<f32>(f32((vi << 1u) & 2u), f32(vi & 2u));
    out.pos = vec4<f32>(uv * 2.0 - 1.0, 0.0, 1.0);
    return out;
}

fn to_target(color: vec3<f32>) -> vec4<f32> {
    if uni.params.z > 0.5 {
        return vec4<f32>(pow(color, vec3<f32>(2.2)), 1.0);
    }
    return vec4<f32>(color, 1.0);
}

@fragment
fn fs_float(in: VsOut) -> @location(0) vec4<f32> {
    let coord = vec2<i32>(in.pos.xy);
    let texel = textureLoad(t_float, coord, 0);
    if uni.params.x < 0.5 {
        // Depth: nearer = brighter over [0, range]; background (0) = black.
        let d = texel.r;
        var v = 0.0;
        if d > 0.0 {
            v = 1.0 - clamp(d / max(uni.params.y, 1.0e-6), 0.0, 1.0);
        }
        return to_target(vec3<f32>(v));
    }
    // Normals: already encoded to [0, 1].
    return to_target(texel.rgb);
}

fn hsv_to_rgb(h: f32, s: f32, v: f32) -> vec3<f32> {
    let i = floor(h * 6.0);
    let f = h * 6.0 - i;
    let p = v * (1.0 - s);
    let q = v * (1.0 - f * s);
    let t = v * (1.0 - (1.0 - f) * s);
    switch i32(i) % 6 {
        case 0: { return vec3<f32>(v, t, p); }
        case 1: { return vec3<f32>(q, v, p); }
        case 2: { return vec3<f32>(p, v, t); }
        case 3: { return vec3<f32>(p, q, v); }
        case 4: { return vec3<f32>(t, p, v); }
        default: { return vec3<f32>(v, p, q); }
    }
}

@fragment
fn fs_seg(in: VsOut) -> @location(0) vec4<f32> {
    let coord = vec2<i32>(in.pos.xy);
    let id = textureLoad(t_seg, coord, 0).r;
    if id == 0u {
        return to_target(vec3<f32>(0.0));
    }
    // Golden-ratio hue stepping, matching the CPU `snap_segmentation_colored`.
    let hue = fract(f32(id) * 0.618034);
    return to_target(hsv_to_rgb(hue, 0.65, 0.95));
}