codecraft 0.2.0

A minimalist 3D game engine built on parts of Bevy (ECS, color) with wgpu and winit: OpenPBR materials, clustered lighting, a yakui-drawn UI, audio and gamepad haptics; its binary maps any folder, and the symbols of its Rust files, as a 3D wall of boxes
Documentation
// The material half of the OpenPBR shader library's preamble.
//
// The lobe code reads its parameters as bare globals -- `base_metalness`,
// `coat_roughness` and the rest -- because the reference GLSL it was ported
// from reads uniforms of those names, and keeping the names made the port
// checkable line by line. So the shading pass copies one material out of the
// table into `mat`, calls `unpack_material()`, and from there every lobe finds
// what it needs without being handed it.
//
// This file is ours; everything after it in the program is the library as it
// arrived. Nothing here refers to a camera, a light, or a scene: what the
// library needs is a material and the energy tables, and that is all.

struct Material {
    base_color_weight: vec4<f32>,
    specular_color_weight: vec4<f32>,
    transmission_color_depth: vec4<f32>,
    transmission_scatter_aniso: vec4<f32>,
    subsurface_color_weight: vec4<f32>,
    subsurface_radius_scale_radius: vec4<f32>,
    coat_color_weight: vec4<f32>,
    fuzz_color_weight: vec4<f32>,
    emission_color_luminance: vec4<f32>,
    base_diffuse_roughness: f32,
    base_metalness: f32,
    specular_roughness: f32,
    specular_anisotropy: f32,
    specular_ior: f32,
    transmission_weight: f32,
    transmission_dispersion_abbe_number: f32,
    transmission_dispersion_scale: f32,
    subsurface_anisotropy: f32,
    coat_roughness: f32,
    coat_anisotropy: f32,
    coat_ior: f32,
    coat_darkening: f32,
    fuzz_roughness: f32,
    thin_film_weight: f32,
    thin_film_thickness: f32,
    thin_film_ior: f32,
    geometry_opacity: f32,
    geometry_thin_walled: u32,
    normal_map_y_along_v: u32,
    base_color_layer: f32,
    roughness_layer: f32,
    metalness_layer: f32,
    normal_layer: f32,
};

// The material being shaded, copied out of the table at entry.
var<private> mat: Material;

var<private> base_weight: f32;
var<private> base_color: vec3<f32>;
var<private> base_diffuse_roughness: f32;
var<private> base_metalness: f32;
var<private> specular_weight: f32;
var<private> specular_color: vec3<f32>;
var<private> specular_roughness: f32;
var<private> specular_anisotropy: f32;
var<private> specular_ior: f32;
var<private> transmission_weight: f32;
var<private> transmission_color: vec3<f32>;
var<private> transmission_depth: f32;
var<private> transmission_scatter: vec3<f32>;
var<private> transmission_scatter_anisotropy: f32;
var<private> transmission_dispersion_abbe_number: f32;
var<private> transmission_dispersion_scale: f32;
var<private> subsurface_weight: f32;
var<private> subsurface_color: vec3<f32>;
var<private> subsurface_radius: f32;
var<private> subsurface_radius_scale: vec3<f32>;
var<private> subsurface_anisotropy: f32;
var<private> coat_weight: f32;
var<private> coat_color: vec3<f32>;
var<private> coat_roughness: f32;
var<private> coat_anisotropy: f32;
var<private> coat_ior: f32;
var<private> coat_darkening: f32;
var<private> fuzz_weight: f32;
var<private> fuzz_color: vec3<f32>;
var<private> fuzz_roughness: f32;
var<private> thin_film_weight: f32;
var<private> thin_film_thickness: f32;
var<private> thin_film_ior: f32;
var<private> emission_luminance: f32;
var<private> emission_color: vec3<f32>;
var<private> geometry_opacity: f32;
var<private> geometry_thin_walled: bool;

// The only two the library wants that are not the material's own. Both are
// switches the path tracer exposed; here they are constants, because a
// forward pass has no wireframe mode and always wants its energy back.
var<private> energy_compensation: bool = true;
var<private> wireframe: bool = false;

fn unpack_material() {
    base_color = mat.base_color_weight.xyz;
    base_weight = mat.base_color_weight.w;
    specular_color = mat.specular_color_weight.xyz;
    specular_weight = mat.specular_color_weight.w;
    transmission_color = mat.transmission_color_depth.xyz;
    transmission_depth = mat.transmission_color_depth.w;
    transmission_scatter = mat.transmission_scatter_aniso.xyz;
    transmission_scatter_anisotropy = mat.transmission_scatter_aniso.w;
    subsurface_color = mat.subsurface_color_weight.xyz;
    subsurface_weight = mat.subsurface_color_weight.w;
    subsurface_radius_scale = mat.subsurface_radius_scale_radius.xyz;
    subsurface_radius = mat.subsurface_radius_scale_radius.w;
    coat_color = mat.coat_color_weight.xyz;
    coat_weight = mat.coat_color_weight.w;
    fuzz_color = mat.fuzz_color_weight.xyz;
    fuzz_weight = mat.fuzz_color_weight.w;
    emission_color = mat.emission_color_luminance.xyz;
    emission_luminance = mat.emission_color_luminance.w;
    base_diffuse_roughness = mat.base_diffuse_roughness;
    base_metalness = mat.base_metalness;
    specular_roughness = mat.specular_roughness;
    specular_anisotropy = mat.specular_anisotropy;
    specular_ior = mat.specular_ior;
    transmission_weight = mat.transmission_weight;
    transmission_dispersion_abbe_number = mat.transmission_dispersion_abbe_number;
    transmission_dispersion_scale = mat.transmission_dispersion_scale;
    subsurface_anisotropy = mat.subsurface_anisotropy;
    coat_roughness = mat.coat_roughness;
    coat_anisotropy = mat.coat_anisotropy;
    coat_ior = mat.coat_ior;
    coat_darkening = mat.coat_darkening;
    fuzz_roughness = mat.fuzz_roughness;
    thin_film_weight = mat.thin_film_weight;
    thin_film_thickness = mat.thin_film_thickness;
    thin_film_ior = mat.thin_film_ior;
    geometry_opacity = mat.geometry_opacity;
    geometry_thin_walled = mat.geometry_thin_walled != 0u;
}

// ---------------------------------------------------------------------------
// The energy compensation tables: eight curves of `ENERGY_BINS` samples for
// every material, in the order `EnergyTables` writes them. See `energy.rs`.
// ---------------------------------------------------------------------------
const ENERGY_BINS: u32 = 32u;
const ENERGY_METAL: u32 = 0u;
const ENERGY_DIELECTRIC_RT_OUT: u32 = 1u;
const ENERGY_DIELECTRIC_RT_IN: u32 = 2u;
const ENERGY_DIELECTRIC_R_OUT: u32 = 3u;
const ENERGY_DIELECTRIC_R_IN: u32 = 4u;
const ENERGY_DIELECTRIC_T_OUT: u32 = 5u;
const ENERGY_DIELECTRIC_T_IN: u32 = 6u;
const ENERGY_COAT_R: u32 = 7u;
/// How many floats one material's tables occupy.
const ENERGY_STRIDE: u32 = 8u * ENERGY_BINS;

// Where this material's tables start, set alongside `mat`.
var<private> energy_base: u32;

// ---------------------------------------------------------------------------
// What the shading pass binds. The library reads only `energy_tables`; the
// other two are here because a binding declared next to the struct it carries
// is a binding that cannot drift from it.
// ---------------------------------------------------------------------------
@group(0) @binding(4) var<storage, read> materials: array<Material>;
@group(0) @binding(5) var<storage, read> energy_tables: array<f32>;

/// One local light: a place, a reach, a colour, and a cone if it has one.
/// Mirrors `GpuLight`.
struct LocalLight {
    // xyz where it is, w how far it reaches.
    position_range: vec4<f32>,
    color: vec4<f32>,
    // xyz the way a spot points, w the cosine of its outer half-angle, or
    // `NOT_A_CONE` for a light that goes everywhere.
    direction_outer: vec4<f32>,
    // x the cosine of the inner half-angle.
    cone: vec4<f32>,
};

const NOT_A_CONE: f32 = -2.0;

@group(0) @binding(6) var<storage, read> lights: array<LocalLight>;
// The cluster grid, filled by the culling pass: how many lights reached each
// cell, and which. See `clustered.rs`.
@group(0) @binding(7) var<storage, read> cluster_counts: array<u32>;
@group(0) @binding(8) var<storage, read> cluster_lights: array<u32>;

const CLUSTER_X: u32 = 16u;
const CLUSTER_Y: u32 = 9u;
const CLUSTER_Z: u32 = 24u;
const MAX_LIGHTS_PER_CLUSTER: u32 = 64u;

/// Take up material `index` and everything that goes with it.
///
/// The two globals set here that are not the material's own are the reason
/// this is a function rather than three lines at the top of a shading pass:
///
/// - `wavelength_nm` reaches `specular_ior_dispersive`, which divides by its
///   square. Left at zero -- which is what a `var<private>` starts as -- the
///   IOR comes back infinite, `eta_s` turns that into a NaN, and the NaN goes
///   through every lobe and out into the frame as a black surface. Nothing
///   reports it. 550 nm is the middle of the visible band, and is what the
///   path tracer uses when it is not tracing a spectral path.
/// - `rndSeed` is only read where a lobe is *sampled*, which a forward pass
///   never does, but a zero seed is a degenerate one and costs nothing to
///   avoid.
fn openpbr_begin(index: u32, seed: u32) {
    mat = materials[index];
    energy_base = index * ENERGY_STRIDE;
    wavelength_nm = 550.0;
    rndSeed = seed;
    unpack_material();
}