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

nordisk/facett

facett-map3d/.nornir/flightsim-render.md

FLIGHTSIM-RENDER — sun/PBR/sky/fog + shadows + reflective water (design + guide + for-idiots)

Ratified design: /home/rickard/.cache/claude-build/flightsim-design.md. Shipped on branch agent/map3d-flightsim. The goal: make the wgpu OSM map3d read like a modern flight-sim — lighting, shadows, materials, fog, water, sky on simple BLOCK buildings (buildings stay blocks; the quality is light + water, NOT geometry).

Framing LAW: vello is 2D only (labels/HUD). Every bit of 3D quality is wgpu pipelines + WGSL feeding the existing OffscreenColorDepth target, then blitted; vello draws 2D chrome on top. See .nornir/render-engine.md §L0/L1.


Design — the pass list (per frame, GPU lane)

[shadow depth pass]  → 2048² Depth32 shadow map (sun's view of the mesh)
[reflection pass]    → half-res colour (opaque mesh, MIRROR camera)   (Ground tier + water)
[sky pass]           → fullscreen analytic gradient + HDR sun disc/glow  (sun tint
                       ← physical transmittance LUT when one is wired in, Phase 3)
 main mesh pass      → offscreen colour+depth  (PBR + sun + sky + height-fog + PCF shadows)
[water pass]         → over the offscreen colour (Gerstner + Fresnel + depth-tint + foam)
 blit                → egui colour pass (scissored to the widget rect)

Phase 1 — the lighting that sells it (map3d.wgsl, sky.rs)

Phase 2 — reflective water (the headline, water.wgsl, extrude.rs)

Phase 3 — physical-sky transmittance LUT sampling (sky.wgsl, gpu.rs, FLIGHT-SIM #7)


Guide — how to drive it

use facett_map3d::{Map3D, SunSky};
let m = Map3D::from_ways("city", &ways, 0.3)
    .with_gpu(true)                 // GPU lane (host installs gpu::install_renderer)
    .with_sun(SunSky::noon())       // or golden_hour() / from_angles(az, el)
    .with_shadows(0.85)             // 0 = off (cheap/wasm); 0..1 = cast-shadow darkness
    .with_planar_reflection(true);  // false = wasm sky-fallback water
// Water switches on by ALTITUDE automatically (< 300 m). Override for tests:
let m = m.with_water_override(Some(true));

Physical-sky transmittance LUT (Phase 3): hand the flight crate's GPU scattering-LUT readback to the sky pass and the sun reddens physically at low elevation.

use facett_map3d::SkyTransmittanceLut;
// gpu_lut = facett_map3d_flight::GpuScatterLut::new(&device).precompute(&device,&queue,32,128,24);
let lut = SkyTransmittanceLut::from_rgb(gpu_lut.mu_size as u32, gpu_lut.h_size as u32,
                                        &gpu_lut.texels, /*alt_norm*/ 0.0);
let m = m.with_sky_transmittance_lut(lut);        // or m.set_sky_transmittance_lut(lut)
// m.clear_sky_transmittance_lut();               // → analytic sun tint (the default)
// m.sky_transmittance_lut_active()               // state_json-style oracle

Tests (every render feature ships an emitter + a PNG blob oracle you LOOK at)

Feature Test Emitter row Blob
calibration + LOD src/lod.rs (unit) — (inject-assert) —
sun/PBR/sky/fog tests/flightsim_phase1.rs phase1_sun_pbr_sky_fog /tmp/map3d_phase1_noon.png
shadows tests/flightsim_shadows.rs shadow_cascade_darkens_ground /tmp/map3d_shadows_on.png
water + 300 m + Fresnel tests/flightsim_water.rs reflective_water_below_300m, water_fresnel_and_wasm_fallback /tmp/map3d_water_on.png
physical-sky LUT (Phase 3) tests/sky_lut_proof.rs (on-screen, adapter-gated) + gpu.rs::sky_lut_wiring_… (GPU-less RED) sky_lut_onscreen, sky_lut_wiring /tmp/map3d_sky_lut_red.png

Run: CARGO_TARGET_DIR=… cargo test -p facett-map3d --features wgpu,testmatrix


For idiots