Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-map3d-flight/.nornir/extrude-gpu-guide.md

GPU-compute building extrusion — guide

How to use the GPU-compute building extrusion (FLIGHT-SIM #3b). Everything up to the storage buffers works with no GPU; the dispatch needs the wgpu feature + an adapter.

Marshal footprints (no GPU needed)

use facett_map3d_flight::{Footprint, BuildingMarshal};

let footprints = vec![
    Footprint::new(vec![(0.0,0.0),(0.6,0.0),(0.6,0.3),(0.3,0.3),(0.3,0.6),(0.0,0.6)], 0.4), // concave L
    Footprint { ring: quad, height: 0.25, min_height: 0.0, building_type: 3 },
];
let marshal = BuildingMarshal::from_footprints(&footprints);
// marshal.contour : flat [f32;2] ring vertices (open, CCW)
// marshal.caps    : flat u32 ear-clip cap indices
// marshal.meta    : Vec<BuildingMeta> (prefix-summed output bases)
// marshal.total_vertices / total_indices : output buffer sizes

from_footprints opens + CCW-normalises each ring, precomputes its cap triangulation with the shared §3a ear-clip, and stamps the per-building BuildingMeta. Degenerate footprints (< 3 distinct vertices / collinear) are silently dropped.

The CPU reference / fallback (no GPU needed)

let mesh = marshal.cpu_extrude(); // Mesh3 — same op extrude.wgsl runs, on the CPU

Use this as the fallback on a host with no adapter (wasm / a laptop tester / a deck pane), and as the oracle the GPU is validated against. For a single footprint it is vertex-for-vertex equal to facett_map3d::extrude_prism_mesh (the landed CPU path).

Dispatch on the GPU (wgpu feature + adapter)

use facett_map3d_flight::ExtrudeGpu;

let ext = ExtrudeGpu::new(&device);           // builds the pipeline (validates the WGSL)
let mesh = ext.extrude(&device, &queue, &marshal); // Mesh3 read back from the compute pass

extrude uploads the three storage buffers, dispatches cs_extrude (one invocation per building), and reads the positions/normals/indices back. The output is what an indirect draw_indexed_indirect consumes when the render-pass wiring lands (roadmap).

Inspect a building's bounds

let (lo, hi) = BuildingMarshal::building_aabb(&mesh, &marshal.meta[0]);
// lo/hi = design-plane (x,z) bbox × (min_height .. height) for that building

Check parity (GPU vs CPU reference)

use facett_map3d_flight::geom_parity;
let rep = geom_parity(&gpu_mesh, &cpu_mesh);
assert!(rep.index_match && rep.max_pos_err < 1e-4);

Emitters (gated #[cfg(feature = "testmatrix")])