Bloom pass — HDR highlight glow (T2.1) + the with_bloom toggle
The 3D-map's HDR post stack (bloom.wgsl, driven from gpu.rs) glows highlights brighter than a linear threshold, then ACES-tonemaps to the 8-bit surface. The scene writes linear HDR into an Rgba16Float offscreen (the sun disc + emissive/spec highlights sit well above 1.0), so real glow survives instead of being clipped by a per-fragment tonemap.
The pass (what runs)
HDR offscreen ──▶ bright-pass ──▶ blur H ──▶ blur V ──▶ composite ──▶ FXAA ──▶ present
(Rgba16Float) (soft-knee (half-res (half-res (HDR + bloom· (LDR)
threshold) Gaussian) Gaussian) intensity → ACES)
- bright-pass —
soft_threshold(threshold=1.0, knee=0.6), 4-tap half-texel box → stable half-res downsample of just the bright fragments. - blur H / blur V — separable Gaussian ping-pong (
u_blur_h/u_blur_v, axis in the per-pass uniform), half-res. - composite —
scene + bloom·INTENSITY(0.65), then ACES + exposure (EV100) → LDR.
with_bloom(on: bool) (new, T2.1)
Mirrors with_ssao — a chainable GPU-lane toggle (default on). false sets the composite's bloom intensity to 0 so it adds zero glow — the flat/wasm fallback and the render-proof control. Threaded: Map3D.bloom → backend::SceneFlags.bloom → Map3dPaintCallback.bloom_on → HdrPost::write_uniforms(bloom_on). The bright/blur passes still run harmlessly (only composite_fs reads params.z), so the toggle is a one-uniform change — no pipeline restructure.
Proof (LAW #4, in code)
tests/bloom_proof.rs renders the sun-framed synthetic scene bloom on vs off (the only variable) through egui_kittest's wgpu backend and asserts, as DATA:
- adds light — mean luma on > off (measured Δ≈0.44);
- spreads the glow — the saturated near-white core region grows (≈9578 vs 7794, +23%): bloom lifts the sun's neighbourhood to saturation;
- deterministic — two bloom-on renders byte-identical (FC-7). Emits the
facett-map3d/bloom_glows_highlightsnornir-testmatrixcell.
Roadmap — mip-pyramid bloom (next tranche step)
Today's bloom is a single half-res level. The "tiptop" upgrade is a mip pyramid: progressive downsample chain (½, ¼, ⅛ …) blurred + upsampled-and-summed (COD/Jimenez dual-filter), for a wider, softer, resolution-independent glow. It slots behind the same bright → {chain} → composite seam (add levels + their bind groups; the with_bloom/params.z gate and the proof stay). Deferred as a bounded follow-up.
Sibling: render-engine-reasoning.md (the wgpu=3D / vello=2D law + full pass list). SSAO twin: tests/ssao_proof.rs.