feat(facades): 0.1.4 — module kit, textured materials, theatre trim #30

Merged
zwitschi merged 13 commits from facades-0.1.4 into main 2026-11-08 20:29:12 +01:00
Owner

Summary

The 0.1.4 building-façade patch, reviewed and signed off.

What it delivers

  • Façade module kit at the measured 4.96 m bay / 3.10 m storey — 16 SM_ meshes (pilaster, sill, lintel, window bay, shopfront bay, door bay, cornice, parapet, coping), each topology-validated (manifold, 12 tris), assembled onto 8 buildings / 625 pieces from each building's world bounds.
  • Generated surface textures (ashlar, stucco, asphalt, concrete; base colour + roughness, deterministic, ~196 KB regenerated on demand) sampled world-aligned, plus masonry coursing and roughness variation in the material graphs and per-slot material assignment.
  • El Capitan Theatre trim — projecting marquee (12.0 × 2.60 m at a 4.60 m soffit), illuminated fascia, recessed soffit, vertical blade sign with frame and bracket.
  • Visual review loop (Tools/visual_loop.py + visual_targets.json) — verifies each capture against an expectation and measures it against the reference photograph, with skill-addressed feedback; iterations stay gitignored until confirmed.
  • fbx_export_preset.py (one preset replacing six copies, now exporting smoothing groups) and ue_common.py (LFS read-only save fix).

Fixed — five defects, four of them invisible in a render

Blockout frame shift (≈119 m X, from a missing --origin); kit placed ~12 km away (mesh-local bbox); marquee mirrored across the boulevard (Blender +Y = Unreal −Y); marquee hanging 5 cm above the pavement (absolute Z); window bays inside the solid wall; plus glazing that wasn't glass, hero windows 1.44 m off the wall, medallions lying on the coping, missing hero collision, silent failed map saves and a silent north-buildings import.

Verified

Packaged -qaselftest: walk 761 cm · reset · pause/unpause · transect 1456 samples / 0 holes · wall probe 0/35 · façade probe 0/9 — all PASS (run twice; the harness is time-based and one loaded run reported a false failure). All eight buildings probed against the verified world spans. 67 tool tests pass.

Review

Docs/reviews/0.1.4-review.md — short intro, seven signoff items (all ticked 2026-11-09) and the four demo captures embedded inline. Screenshots/ is now demo-map only and each shot carries expected content, a mechanical verified state and an approval state.

Leftover geometry (retail neighbours from their own references, hero fluting/motto band, blockout cleaning, a 1440p re-measure) is carried to a new 0.1.5 Façade finishing patch rather than growing this one.

## Summary The `0.1.4` building-façade patch, reviewed and signed off. ### What it delivers - **Façade module kit** at the measured **4.96 m bay / 3.10 m storey** — 16 `SM_` meshes (pilaster, sill, lintel, window bay, shopfront bay, door bay, cornice, parapet, coping), each topology-validated (manifold, 12 tris), assembled onto **8 buildings / 625 pieces** from each building's world bounds. - **Generated surface textures** (ashlar, stucco, asphalt, concrete; base colour + roughness, deterministic, ~196 KB regenerated on demand) sampled world-aligned, plus masonry coursing and roughness variation in the material graphs and **per-slot** material assignment. - **El Capitan Theatre trim** — projecting marquee (12.0 × 2.60 m at a 4.60 m soffit), illuminated fascia, recessed soffit, vertical blade sign with frame and bracket. - **Visual review loop** (`Tools/visual_loop.py` + `visual_targets.json`) — verifies each capture against an expectation and measures it against the reference photograph, with skill-addressed feedback; iterations stay gitignored until confirmed. - **`fbx_export_preset.py`** (one preset replacing six copies, now exporting smoothing groups) and **`ue_common.py`** (LFS read-only save fix). ### Fixed — five defects, four of them invisible in a render Blockout frame shift (≈119 m X, from a missing `--origin`); kit placed ~12 km away (mesh-local bbox); marquee mirrored across the boulevard (Blender +Y = Unreal −Y); marquee hanging 5 cm above the pavement (absolute Z); window bays inside the solid wall; plus glazing that wasn't glass, hero windows 1.44 m off the wall, medallions lying on the coping, missing hero collision, silent failed map saves and a silent north-buildings import. ### Verified Packaged `-qaselftest`: walk 761 cm · reset · pause/unpause · transect 1456 samples / 0 holes · wall probe 0/35 · façade probe 0/9 — all PASS (run twice; the harness is time-based and one loaded run reported a false failure). All eight buildings probed against the verified world spans. 67 tool tests pass. ### Review `Docs/reviews/0.1.4-review.md` — short intro, seven signoff items (all ticked 2026-11-09) and the four demo captures embedded inline. `Screenshots/` is now **demo-map only** and each shot carries expected content, a mechanical verified state and an approval state. Leftover geometry (retail neighbours from their own references, hero fluting/motto band, blockout cleaning, a 1440p re-measure) is carried to a new **`0.1.5` Façade finishing** patch rather than growing this one.
zwitschi added 12 commits 2026-11-08 20:24:48 +01:00
0.1.4 materials pass plus the camera fix levelling exposed.

Materials (Tools/ue_build_demo_map.py):
- ensure_material() gains optional masonry coursing (world-space course height,
  joint band, joint tint) and roughness variation, so facades read as coursed
  stone/stucco instead of one flat specular plane.
- WorldPosition is in centimetres: course heights in metres are scaled by 100
  (the first attempt divided by 0.55 and the coursing was invisible).
- connect_material_expressions returns False rather than raising, so every link
  now goes through a link() helper that logs failures; UE has no
  MaterialExpressionLess, so the joint mask is Frac -> Divide -> OneMinus -> Clamp.
- New materials: M_FacadeStoneShadow, M_FacadeGlass (specular 0.62 ~ IOR 1.5),
  M_FacadeBanner.
- Material assignment is now per SLOT keyed on the imported slot material name.
  It was slot-0 only, which on the hero is the banner, so stone, shadow stone and
  glazing still wore flat Blender materials. Hero now 4/4 slots.

Cameras (GigLineShotActor + ue_build_review_map):
- Optional per-shot ShotFieldOfView; the shot tuples take a 4th element.
- Elevations use a 42-55 deg lens from across the street: with the cameras
  levelled (0.1.2 follow-up) the building was small in frame, and tilting to fill
  it is what breaks the verticals. hero-facade-front sky 39% -> 20%,
  demo-spawn-view 23% -> 16%.

Screenshots re-rendered for the whole set.
New Tools/generate_facade_textures.py: deterministic, stdlib-only PNG generator for
four facade surface sets (ashlar stone, stucco, asphalt, concrete), each as base
colour (_BC) plus roughness (_R). Pure zlib encoder and hash-based value noise, so
re-running produces byte-identical files (verified by md5sum); ~14 s for eight 512²
maps.

ue_build_demo_map.py imports them into /Game/Hollywood/Textures and samples them
world-aligned: WorldPosition (cm) * 1/tile_cm -> ComponentMask(R,G) -> TextureSample
UVs, with per-material tile sizes (stone 440, stucco 260, asphalt 900, concrete
250 cm). A textured material skips the graph coursing deliberately - overlaying both
would double the course pattern.

Textures imported 8/8, hero 4/4 slots assigned, map saved; screenshots re-rendered.
- Tools/facade_kit_build.py: the reusable kit (pilaster, sill, lintel, window bay,
  shopfront bay, door bay, cornice, parapet + coping) at the measured 4.96 m bay
  and 3.10 m storey; 16 meshes exported per object through the shared preset with
  a JSON part report recording dims and evidence.
- Tools/ue_import_facade_kit.py: imports to /Game/Hollywood/Kit with
  complex-as-simple collision, so thin panes keep their real faces.
- Tools/ue_apply_facade_kit.py: assembles from each building's own bounding box
  (bays = round(width/4.96), storeys above the ground floor) with shopfronts at
  street level, windows above, pilasters on bay boundaries, cornice and parapet at
  the top. Clears a previous application; unique labels per building.
  638 pieces across six frontage buildings and both north buildings.

Two bugs fixed en route: the window piece was modelled entirely at +Y so it sat
inside the solid wall and was invisible (now projects 3 cm proud with glazing
6 cm inset), and clearing materials mid-build invalidated handles.

Screenshots re-rendered; window rhythm now reads (edge transitions per row rose
from flat to ~197 on the spawn view).
The 0.1.2 blockout regeneration ran without --origin, so Blosm centred on the
extract instead of fitting the project frame. The frontage shifted ~119 m in X and
~2.4 m in Y and the hero fell outside the 6902/6838 gap - the verified placement
was silently undone, while every render still looked like a plausible block.

- Blockout regenerated with --origin 34.101545,-118.338718 (affine residual 0.0 cm);
  frontage and north buildings re-exported and re-imported.
- Verified spans restored: 6922 -24276..-17700, 6902 -17749..-14591, hero
  -14644..-12028 between them, theatre -12082..-8210, TCL -22889..-18442,
  Tussaud's -27071..-22799.
- ue_apply_facade_kit now uses get_actor_bounds() (world space). It had used the
  static mesh bounding box, which is building-line-local, so every kit piece was
  placed ~12 km east of its building in empty ground.
- ue_import_north_buildings.py was missing 'import sys' (NameError, exit 255,
  import silently skipped) - the same trap as the hero importer.
- Kit re-applied: 625 pieces across eight buildings; packaged QA still PASS
  (walk, transect 0 holes, wall probe 0/35, facade probe 0/9).
- Kit pieces export as SM_Kit_* (Unreal static-mesh convention) while the Blender
  objects keep their readable names; the kit loader strips the prefix so layout
  still addresses pieces by short name.
- facade_kit_build.py validates each piece before handoff (non-manifold edges,
  loose vertices, triangle count) and records the result in the part report:
  16 pieces, all manifold, no loose geometry, 12 tris each.
- ue_import_facade_kit.py removes kit assets the current build no longer produces,
  so a rename cannot leave two generations of the same piece behind.
- Kit re-imported and re-applied (625 pieces); packaged QA still PASS.
Per the qa-review skill: explicit verdict, measured budgets, the screenshots that
carry the claim, defects by severity and what remains unverified.

Verdict SHIP WITH NOTES - geometry/placement/budgets verified by measurement, the
visual half explicitly pending human review (the vision pre-check is unreliable on
this content and was not used as evidence).

Also fixes the last QA finding: kit pieces kept the grey M_Kit_* material the FBX
import creates, so glazing was not glass and shopfronts were not stone. Assembly now
assigns M_FacadeGlass to glazing, M_FacadeStone to surrounds, M_FacadeStoneShadow to
doors and M_FacadeBanner to fascias (6/6 materials resolved), and the importer
deletes the unused M_Kit_* materials (Kit folder now exactly 16 SM_ meshes).

Packaged QA re-verified after the change: walk, transect 0 holes, wall probe 0/35,
facade probe 0/9, RESULT PASS.
Tools/visual_loop.py:
- --verify gates every capture against its expectation in Tools/visual_targets.json
  (missing, blank, tone-less or wrong-size shots fail), so 'each screenshot shows
  what was expected' is checked rather than assumed.
- --compare measures luminance, RMS contrast, edge density, palette distance and a
  3x3 luma grid against the reference photograph, with a 0-1 similarity score.
- --iteration N writes Art/reference/iterations/N/{metrics.json,feedback.md}; the
  feedback names the skill to consult (blender-modeler, archviz, materials, lookdev,
  camera-cinematography), so the next modelling pass starts from a measurement.
- Iterations are gitignored until the owner confirms a shot; only confirmed shots
  are promoted into Screenshots/.

Screenshots/ holds demo-map captures only now: render_screenshots.sh renders just
DemoMap, collects the shots and runs the verification gate (--verify); the review
staging map is no longer rendered for review and its PNGs are removed. The README
is rewritten around the four demo shots with per-shot expected content and a
verified column, and no longer claims the review staging set.

Tests: 67 pass (13 new) covering metrics on synthetic images, comparison scoring,
the feedback rules and the target spec (including that every target is a demo shot
and that iterations are gitignored).
Tools/theatre_trim_build.py builds the El Capitan Theatre's signature features in
world coordinates - projecting marquee (12.0 x 2.60 m canopy, 4.60 m soffit),
illuminated fascia, recessed soffit, vertical blade sign (1.30 x 5.20 m) with frame
and bracket - with a JSON part report. Tools/ue_stage_theatre_trim.py imports and
stages one actor per piece with site materials, clearing a previous run first.

Two bugs, neither visible in a render:
- Axis sign: Blender +Y is Unreal -Y, so the theatre face at Unreal Y +1001 is
  Blender Y -10.01; using +10.01 mirrored the marquee across the boulevard.
- Absolute Z: trim heights ignored the 4.56 m pavement, leaving the canopy 5 cm above
  the ground. GROUND_Z now offsets every height.

QA wall probe: the Y 1000 scan row sat ~1 cm from the building line and grazed the
theatre wall after the kit's proud shopfronts; rows now sample the street envelope
only. Packaged QA back to PASS (transect 0 holes, wall probe 0/35, facade probe 0/9).
Screenshots re-rendered and verified 4/4.
Consolidates the branch: what changed (9 commits, 89 files), the evidence that
holds up (packaged -qaselftest, coordinate probes, budgets, 67 tests), all 15
defects found this cycle with severity/root cause/how each was caught, the
iteration toolchain and its current measurements, known limitations, and an
explicit list of what is NOT verified and needs a human.

Also records two things the earlier QA doc did not: the QA self-test is time-based
and can flake (one run reported walk 246 cm and pause FAIL; an immediate re-run
reported 761 cm and PASS with identical content), and the visual-loop scores are a
trend across iterations rather than an absolute quality number, because a wide
block view compared with a tight facade crop always scores low on edge similarity.
249 -> 43 lines. Short intro, a seven-item signoff checklist, and the four demo
captures embedded inline with one line of expected content and the current metric
each. The long defect/evidence tables move to Docs/qa/0.1.4-facade-qa.md and the
git history, where they belong.

All four image links verified to resolve.
- Review doc: all seven signoff items ticked (owner reviewed the local renders).
- Screenshots README: per-shot Approved column, 4/4 approved 2026-11-09.
- CHANGELOG: full 0.1.4 entry (kit, textures, materials, theatre trim, visual loop,
  the five placement/collision fixes, verified results, limitations).
- TODO: 0.1.4 section removed; new 0.1.5 'Facade finishing' patch carries the retail
  neighbours (from their own references, not the theatre's), hero fluting and motto
  band, the blockout cleaning pass, and a 1440p performance re-measure with the kit
  in the map.
- ROADMAP status updated.
zwitschi added 1 commit 2026-11-08 20:24:48 +01:00
- Review doc: all seven signoff items ticked (owner reviewed the local renders).
- Screenshots README: per-shot Approved column, 4/4 approved 2026-11-09.
- CHANGELOG: full 0.1.4 entry (kit, textures, materials, theatre trim, visual loop,
  the five placement/collision fixes, verified results, limitations).
- TODO: 0.1.4 section removed; new 0.1.5 'Facade finishing' patch carries the retail
  neighbours (from their own references, not the theatre's), hero fluting and motto
  band, the blockout cleaning pass, and a 1440p performance re-measure with the kit
  in the map.
- ROADMAP status updated.
zwitschi added 1 commit 2026-11-08 20:29:08 +01:00
Docs/qa/0.1.4-facade-qa.md contained the QA-gate detail (budgets, defect table,
limitations) and Docs/reviews/0.1.4-review.md the signoff and images. One document
now: short intro, the ticked signoff list, the four embedded captures, and a compact
appendix holding the verified behaviour and placement, the defect table with root
causes, and the limitations.

All four image links verified; no other file referenced the removed document.
zwitschi merged commit 5e2c5e29c0 into main 2026-11-08 20:29:12 +01:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: zwitschi/gig-line#30