facett-map3d — ground-plane roads/route render (the invisible-roads fix)
design (the chosen shape)
The CPU painter (shade_mesh_faces, the shared geometry oracle behind every backend) runs a screen-space back-face cull (STEP 4): a projected triangle is dropped when its screen-space signed area cross_z <= 0. That is correct for the extruded building shell (walls/roofs), but it wrongly dropped the flat, ground-plane ribbons — roads, the 3-D route ribbon, and the terrain cover — which are all built with a +Y (up) world normal.
Why: a flat +Y face has no meaningful "back". Its screen-winding sign flips with the viewing hemisphere (a +Y quad reads CCW from one side and CW from the other), so from the map's usual above-ground camera the sign came out <= 0 and the ribbon was culled — the roads were data-proven on the mesh but never pixel-drawn (osm-3d-gaps §F, the Garmin navigator's #1 issue).
Chosen fix: keep any strongly up-facing face regardless of screen winding. The per-triangle world normal nv is already computed for lighting just before the cull, so the cull becomes if cross_z <= 0.0 && nv.y <= GROUND_FACE_UP_NY { drop }. The map's orbit camera is elevation-clamped to sit above the ground plane, so an up-facing surface (nv.y > 0.5: roads · route ribbon · terrain cover · roof caps; nv.y ≈ 1) always faces the eye and must never be culled. Genuine back-faces (walls seen edge-on-away nv.y ≈ 0, down-caps nv.y = -1) are unaffected and still dropped.
why not (alternatives → reasoning)
- Re-wind the ribbons — the ribbon winding is already
+Y-consistent with the terrain quad; no fixed winding survives BOTH viewing hemispheres, so re-winding can't fix a sign that flips. - View-space normal · view-dir dot — equivalent result, more arithmetic per triangle; the
nv.ytest is exact here because the camera is constrained above the ground. - Disable the back-face cull entirely — would re-admit building back-walls and inner faces, hurting fill-rate and depth.
observable / RED-when-broken
ground_roads_proof.rs (headless, no GPU): adding a road to a town yields MORE visible shaded faces from BOTH an oblique and an overhead (ViewPreset::Top) camera — 0 before the fix. route_robot.rs now asserts the ground-plane route ribbon changes the main 3-D view, not only the minimap inset. The wgpu goldens (golden_248/render_proof) are unaffected beyond a deterministic 0.008 % sub-budget delta — those scenes carry no roads.