Facett Graphics — State-of-the-Art Roadmap (real-time / AAA / film / demoscene)
Branch agent/facett-gfx-sota. This doc inventories modern real-time graphics techniques, scores each against facett's existing HDR-offscreen + post-pass plumbing, gives a prioritized roadmap, and records what was implemented vs. deferred. It is research-grounded (sources at the end).
0. What already exists (the ~50-technique baseline — do NOT duplicate)
GGX PBR · orthographic shadow map + 3×3 PCF (CSM/PCSS landing) · 3-wave Gerstner water + planar reflection + foam · analytic-gradient sky + sun disc · HDR Rgba16Float offscreen colour+depth (OffscreenColorDepth) · bloom (bright-pass + separable Gaussian + additive) + ACES tonemap · FXAA · dual-Kawase frosted-glass backdrop blur · graph3d GPU-instanced nodes/edges with emissive+additive neon · injected-clock easing/spring motion (FC-7 determinism).
The shared GPU seam lives in facett-core::render::gpu: OffscreenColorDepth (HDR target), GaussianBlur (separable blur), GpuSdfRenderer (instanced SDF), install_renderer (egui callback lifecycle). The map3d ACES post chain (PostStack in facett-map3d/src/gpu.rs + bloom.wgsl/fxaa.wgsl) is private and off-limits. New work composes with the public HDR seam instead.
1. Technique inventory + prioritized roadmap
| Technique | What it buys | Cost | Facett-fit (HDR offscreen + post plumbing) | Priority |
| AgX tonemap (vs ACES) | Film-like highlight roll-off; fixes ACES' over-saturated/clipped neon & skewed bright hues | ~1 fullscreen pass (cheap) | Drop-in post over HDR colour; new file, doesn't touch ACES | DONE (P0) |
| Blue-noise/IGN dither | Kills 8-bit gradient banding in sky/bloom/fog | negligible (per-pixel hash) | Final step of the grade pass | DONE (P0) |
| CAS sharpen (FidelityFX) | Natural edge crispness without ring/halo; pairs with any AA/upscale | cheap (5 taps) | Folds into the grade pass over HDR | DONE (P0) |
| Vignette / film grain | Cinematic framing + grade cohesion | negligible | Grade pass | DONE (P0) |
| MSDF text | Razor-sharp glowing labels at any zoom from one small atlas; outlines/glow cheap | small atlas + tiny shader | New self-contained module; complements labels3d.rs billboards |
DONE (P1) |
| GPU compute particles | Thousands of additive boids/sparks into HDR; "alive" scenes; offloads CPU | one compute + one additive pass | Additive into the HDR target; first compute outside the map cull | DONE (P1) |
| GTAO (over basic SSAO) | Horizon-based AO with better contact darkening than a depth-only SSAO | medium (depth+normal, several taps) | Needs scene normals + the depth seam; in-flight by another agent | P1 (avoided — collision) |
| SSR (screen-space reflections) | Glossy reflections beyond planar water | medium-high (depth march + colour resolve) | Needs the depth-sample seam in gpu.rs; can't add cleanly without editing it now |
P2 (deferred) |
| Volumetric fog / god-rays (froxel) | Light shafts, depth, atmosphere | medium-high (3D froxel grid or radial blur) | Reads depth + sun; froxel grid is a new compute module — viable later | P2 (deferred) |
| TAA / temporal upsampling | Best-in-class AA + cheap supersample; enables stochastic effects | high (history buffer, motion vectors, reprojection, clamp) | Needs motion vectors + jittered camera in gpu.rs (off-limits) and a history target |
P3 (deferred) |
| SSGI / Lumen-style GI | One-bounce indirect light, huge realism jump | very high (ray/probe infra) | Large new subsystem; out of scope for a post-pass milestone | P3 (deferred) |
| Clustered / Forward+ lighting | Many dynamic lights at scale | high (cluster build compute + light lists) | Architectural change to the mesh pass (off-limits) | P3 (deferred) |
| FFT ocean (vs Gerstner) | Realistic open-water spectrum | high (compute FFT + cascades) | Would replace water.wgsl (off-limits) |
P3 (deferred) |
| Parallax-occlusion mapping | Fake geometric depth on flat faces | medium (per-material height + march) | Belongs in the mesh shader (off-limits) | P3 (deferred) |
| Virtualized geometry (Nanite-like) | Pixel-scale detail at constant cost | research-grade | Out of scope | P4 (research) |
| Bokeh DoF / motion blur | Cinematic focus + speed | medium (CoC + gather / velocity) | DoF needs depth; motion blur needs velocity buffer | P2 (deferred) |
| Khronos PBR-Neutral tonemap | Product-accurate hue preservation | cheap | Alternative grade preset — easy future addition to the grade module | P2 (nice-to-have) |
Priority key: P0 highest ROI / lowest risk / zero collision → P4 research.
2. What was implemented (this branch)
All three are new modules under facett-core/src/render/gpu/ (the shared GPU seam — NOT the off-limits map3d files), each behind the existing wgpu feature, each with the codebase's CPU-math-mirrored-by-WGSL pattern and "assert on data" render proofs that self-skip when no GPU adapter is present.
(a) colorgrade.rs + colorgrade.wgsl — final-look colour grade
A single fullscreen pass over the HDR colour: exposure → CAS sharpen → AgX tonemap (blended toward Reinhard by agx) → vignette → film grain → optional sRGB encode → IGN ordered dither. An optional alternative to the existing ACES blit — consumers opt in; the map3d ACES path is untouched.
- Public:
ColorGrade::new(device, output_format),ColorGrade::render(...),ColorGradeParams(exposure/agx/vignette/grain/dither/sharpen/frame_index/srgb). - CPU mirror (unit-tested, FC-7):
agx_tonemap,ign,vignette_factor,srgb_oetf. - Tests: AgX is black-anchored / monotone / rolls off highlights / desaturates bright primaries (the qualitative win over ACES-clamp); vignette darkens only corners; IGN deterministic + bounded + animated; sRGB anchors. Render proofs (real device): bright HDR is not clipped to flat white + corner darker than centre; 2× exposure measurably brighter.
(b) particles.rs + particles.wgsl — GPU compute particles (boids)
Storage-buffer Reynolds flocking (separation/alignment/cohesion) stepped O(n²) in a compute shader over a ping-pong buffer pair, drawn as soft additive point sprites into the HDR target (glow accumulates on overlap). First compute shader in the tree outside the 2D map cull.
- Public:
GpuParticles::new/make_buffers/step/render,Particle,SimParams,DrawParams, and the CPU referencestep_cpu. - Tests: CPU step deterministic (FC-7), positions stay in the toroidal box, speed clamp holds, separation pushes neighbours apart. Render proofs (real device): GPU↔CPU parity (one device step matches
step_cpuwithin 1e-3), and additive overlap (two stacked particles measurably brighter than one).
(c) msdf.rs + msdf.wgsl — MSDF text / labels
Instanced glyph quads sampling an MSDF atlas; fragment takes the median of the three distance channels (sharp corners a 1-channel SDF would round) and converts to ~1px coverage via the per-glyph screen pixel range → crisp at any zoom. Ships disk_msdf_atlas (analytic filled-disk SDF) so the render proof is self-contained, needing no external msdf-atlas-gen.
- Public:
MsdfText::new/atlas_bind/render,GlyphInstance, and the mathmedian3,coverage,screen_px_range,disk_msdf_atlas. - Tests: median picks the middle; coverage is an edge that sharpens with range; screen-px-range scales with glyph size (the "any zoom" property); disk atlas encodes the signed field. Render proof (real device): a crisp filled disk (opaque centre, empty corner, lit area ≈ πr²) and 2× zoom grows area ~4× (edges stay thin, not blurred).
3. What was deferred — and why
- GTAO / SSAO upgrade — another agent is actively in the SSAO/CSM render-graph code; avoided to prevent collision (would also need the scene-normal seam).
- SSR, volumetric/froxel fog, DoF, motion blur — all need the scene-depth (and for SSR/SSAO a normal) seam wired through
facett-map3d/src/gpu.rs, which is off-limits this milestone.OffscreenColorDepthalready exposes a sampleable depth view, so these are clean follow-ups once the mesh pass can be touched. - TAA / temporal upsampling — needs camera jitter + motion vectors produced in the (off-limits) mesh pass and a persistent history target.
- SSGI/Lumen, clustered/Forward+, FFT ocean, POM, Nanite — architectural subsystems beyond a composable post-pass milestone; tracked as P3/P4.
4. Off-limits files avoided (per the task constraints)
facett-map3d/src/gpu.rs, map3d.wgsl, water.wgsl, sky.wgsl, the shadow/SSAO code, and facett-core/src/look/* were not edited. All new code lives in new files under facett-core/src/render/gpu/ plus this doc; the only edit to an existing file is adding the three pub mod + re-exports to facett-core/src/render/gpu/mod.rs.
5. Sources (web research, June 2026)
- AgX vs ACES tone mapping — cgcookie "Filmic vs AgX", CG Meerkat "Qualities of a good tonemapper", three.js forum AgX implementation thread; Khronos PBR-Neutral tone mapper announcement.
- MSDF — Chlumsky
msdfgen,awesome-msdf, webgpu-samples MSDF text, Red Blob Games "Signed Distance Field Fonts". - CAS / blue-noise dither — AMD GPUOpen FidelityFX CAS (Timothy Lottes), Xenia blue-noise presentation dither notes.
- GPU compute particles / boids — WebGPU-samples computeBoids, Mike Turitzin "Rendering Particles with Compute Shaders".