GPU scattering-LUT precompute — guide
How to precompute the atmospheric transmittance LUT on the GPU and get a texture back. Behind the wgpu feature (cargo … -p facett-map3d-flight --features wgpu).
Precompute a LUT on the GPU
use facett_map3d_flight::{GpuScatterLut, TransmittanceLut};
// `device` + `queue` come from your wgpu setup (a compute+storage capable adapter).
let gpu = GpuScatterLut::new(&device);
let lut = gpu.precompute(&device, &queue, 32, 128, 24); // h × mu × march-steps
// The read-back texels (row-major h×mu, same layout as TransmittanceLut::texels)…
assert_eq!(lut.texels.len(), 32 * 128);
// …and a sampled Rgba32Float texture (mu wide × h tall) ready to bind in a shader.
let _view: &wgpu::TextureView = &lut.view;
Verify it against the CPU oracle
The CPU model is the reference. parity_vs returns the split metrics:
let cpu = TransmittanceLut::precompute(32, 128, 24);
let rep = lut.parity_vs(&cpu);
assert!(rep.max_err_upper < 5e-4); // above-horizon (μ≥0) — the sampled region
assert!(rep.outliers_all_below_horizon); // the only divergences are the tangent line
assert!(rep.outliers <= 32 + 2); // one knife-edge texel per altitude row
Testing discipline (GPU-less friendly)
- CPU oracle (runs anywhere, no adapter):
atmos::tests::gpu_lut_oracle_is_stable_and_physicalasserts the LUT is deterministic (stable FNV content hash) + physical (overhead lets more light through than grazing, grazing reddens). This is the RED-when-broken check. - GPU parity (self-skips without an adapter):
scatter_gpu::tests::gpu_lut_matches_cpu_oracle_within_tolerancebuilds a headless compute device; with no adapter it records a sentinel functional-status row and returns; with one it assertsparity_vs(above). - Emitters (L4, gated
--features testmatrix):scatter_lut_oracle(dims/format/content-hash) andscatter_lut_gpu_parity(max_err_upper / outliers).
Run the lot on a GPU box:
cargo test -p facett-map3d-flight --features wgpu,testmatrix
On a GPU-less box, drop wgpu (the CPU oracle still runs and stays RED-when-broken):
cargo test -p facett-map3d-flight --features testmatrix
Tuning
h × mu × steps trade resolution for build cost; TransmittanceLut::standard() is 32 × 128 × 24. GpuScatterLut::precompute clamps each to a safe minimum. The texture is Rgba32Float (portable readback); switch to a filterable format only once a shader actually samples it with bilinear filtering.