kiss3d 0.45.0

Keep it simple, stupid, 2D and 3D graphics engine for Rust.
Documentation
import package::common::{fullscreen_triangle_xy, fullscreen_uv_from_clip};
// Reprojects six captured cube faces (stored as layers of a 2D array) into one
// equirectangular map, used by runtime reflection-probe capture.
//
// The face layout is defined here AND in `renderer::reflection_probe`'s capture
// camera, so the two stay consistent by construction (no reliance on hardware
// cube-map face conventions): face `i` was rendered by a 90°-FOV right-handed
// camera looking along `FORWARD[i]` with up hint `UP[i]`. For an output direction
// `d` we find the face it falls in and reproject using the same basis the camera
// used (matching glam's `look_at_rh`).

@group(0) @binding(0) var faces: texture_2d_array<f32>;
@group(0) @binding(1) var samp: sampler;

const PI: f32 = 3.14159265359;

fn face_forward(i: u32) -> vec3<f32> {
    switch i {
        case 0u: { return vec3<f32>(1.0, 0.0, 0.0); }
        case 1u: { return vec3<f32>(-1.0, 0.0, 0.0); }
        case 2u: { return vec3<f32>(0.0, 1.0, 0.0); }
        case 3u: { return vec3<f32>(0.0, -1.0, 0.0); }
        case 4u: { return vec3<f32>(0.0, 0.0, 1.0); }
        default: { return vec3<f32>(0.0, 0.0, -1.0); }
    }
}

fn face_up(i: u32) -> vec3<f32> {
    switch i {
        case 2u: { return vec3<f32>(0.0, 0.0, -1.0); }
        case 3u: { return vec3<f32>(0.0, 0.0, 1.0); }
        default: { return vec3<f32>(0.0, 1.0, 0.0); }
    }
}

struct VsOut {
    @builtin(position) pos: vec4<f32>,
    @location(0) uv: vec2<f32>,
};

@vertex
fn vs_main(@builtin(vertex_index) vid: u32) -> VsOut {
    let xy = fullscreen_triangle_xy(vid);
    var out: VsOut;
    out.pos = vec4<f32>(xy, 0.0, 1.0);
    out.uv = fullscreen_uv_from_clip(xy);
    return out;
}

@fragment
fn fs_main(in: VsOut) -> @location(0) vec4<f32> {
    // Equirect UV -> world direction (inverse of `ibl_dir_to_uv`).
    let theta = (in.uv.x - 0.5) * 2.0 * PI;
    let phi = in.uv.y * PI;
    let sp = sin(phi);
    let d = vec3<f32>(cos(theta) * sp, cos(phi), sin(theta) * sp);

    // Pick the face whose forward axis is most aligned with `d` and reproject.
    var best = 0u;
    var best_dot = -2.0;
    for (var i = 0u; i < 6u; i = i + 1u) {
        let dd = dot(d, face_forward(i));
        if dd > best_dot {
            best_dot = dd;
            best = i;
        }
    }
    let fwd = face_forward(best);
    let s = normalize(cross(fwd, face_up(best))); // camera right
    let u = cross(s, fwd); // camera up (recomputed, matches look_at_rh)
    let denom = max(dot(d, fwd), 1e-4);
    let ndc = vec2<f32>(dot(d, s) / denom, dot(d, u) / denom);
    let tex_uv = vec2<f32>(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
    return textureSampleLevel(faces, samp, tex_uv, i32(best), 0.0);
}