Commit Graph
21 Commits
Author SHA1 Message Date
zwitschi bd1f8a9c2e feat(qa): reference-vs-render iteration loop; screenshots are demo-only
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).
2026-11-08 19:52:25 +01:00
zwitschi ad5bb25009 qa(0.1.4): verdict document with budgets, evidence and defect severities
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.
2026-11-08 19:44:17 +01:00
zwitschi 1b069188a2 refactor(kit): SM_ asset naming and topology validation per the modeling checklist
- 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.
2026-11-08 19:38:29 +01:00
zwitschi 32dff056c3 fix(blockout): regenerate with --origin; frontage back on the verified spans
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).
2026-11-08 19:32:47 +01:00
zwitschi c9d603f754 feat(kit): façade module kit at the 4.96 m bay, assembled onto eight buildings
- 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).
2026-11-08 19:12:45 +01:00
zwitschi 73e535a24b feat(materials): generated facade texture maps, sampled world-aligned
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.
2026-11-08 19:04:03 +01:00
zwitschi 9a3784683f feat(materials): masonry coursing, glass/banner materials, per-slot assignment, telephoto elevations
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.
2026-11-08 19:00:41 +01:00
zwitschi ba68dcfdbc feat(hero): v0.1.2 — scale calibration, façade detail, export preset refactor (#28)
Merged PR #28: v0.1.2 — scale calibration, façade detail, export preset

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 18:48:33 +01:00
zwitschi 640bff9631 screenshots: re-render the whole set after the 0.1.2 height calibration (review) (#27)
Merged PR #27: 0.1.2 screenshot set (approved)

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:44:00 +01:00
zwitschi 5ffe62f6aa feat(geo): adopt Mapbox building calibration (3.1 m per level) (#26)
Merged PR #26: adopt Mapbox building calibration

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:38:28 +01:00
zwitschi e75e5500a7 fix(street): 0.1.1 collision patch — flush sidewalk edge, graded crossing ramps (#21)
Merged PR #21: 0.1.1 collision patch (flush sidewalk edge, graded ramps)

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:19:11 +01:00
zwitschi 88b0149bfa screenshots: regenerate set after placement release check (review pending) (#15)
Merged PR #15: regenerated screenshot set (approved)

Co-authored-by: Zwitschi <zwitschi82@gmail.com>
2026-11-08 16:08:14 +01:00
zwitschi fee26ade10 frontage: south block frontage, plus the placement bug it exposed
Adds the five remaining verified south-side buildings to the demo block
(6922, 6902, 6838 El Capitan Theatre, 6822 Budget, 6806-6820, 6800 Lee Drug),
exported in place from the OSM blockout by Tools/export_block_frontage.py,
imported to /Game/Hollywood/Frontage/ and staged by the demo builder with the
look material set (stone for the theatres, stucco for the retail run).

Adding neighbours exposed a pre-existing placement bug that was invisible while
the hero facade stood alone in an empty field:

- UE south is +Y here (south sidewalk Y +718..+1447), but the hero sat at
  Y -1450 on the NORTH side of the street.
- It was also at X -12024..-9420, 26 m east of the 6840 footprint; the frontage
  gap between 6902 and 6838 is X -14591..-12082.
- The two north-side buildings were on the SOUTH side, because their exporter
  mirrored Y.

Fixes: hero moved to X -13336 / Y +1307, inside its frontage gap; the frontage
and north-building exporters no longer apply a Y mirror (the FBX preset already
lands Blender -Y south on UE +Y south); player start and demo cameras moved to
the north sidewalk looking south; sun raised to pitch -62 so both frontages read
instead of the north side silhouetting.

Result: the demo is a street - continuous south frontage with the hero in it,
both sidewalks, the road with the designated crossing, and the north-side
buildings across the road.

Screenshots re-rendered and approved by the owner.

Squash of branch frontage-block-0.1.0 (PR #6).
2026-11-08 09:20:11 +01:00
zwitschi 62a41bf904 materials: look-developed surface materials for every exported asset
Completes "Materials and look development for all exported assets". Every
exported surface previously carried a flat Constant3Vector fill, which read as
plastic. ensure_material() in Tools/ue_build_demo_map.py now builds a
procedural material per surface:

- base colour blended between two shades by world-space noise
  (WorldPosition -> Multiply -> Noise -> Lerp -> BaseColor) for large-scale
  variation,
- an explicit roughness and specular so the surface type is readable.

  M_Asphalt 0.92, M_Concrete 0.88, M_KerbConcrete 0.85, M_Ground 0.98,
  M_RoadPaint 0.62, M_FacadeStone 0.72, M_Stucco 0.86

Site meshes take their material by mesh name; the hero facade and the two
north-side buildings take theirs by actor label, so they are covered even
though other scripts stage them. Materials are deleted and rebuilt on every
run, so a look change cannot be masked by a stale asset.

Result: the facade reads as warm stone with surface variation, asphalt as dark
asphalt with grain, concrete and kerbs lighter and matte, and the north
buildings in stucco instead of flat grey.

Screenshots re-rendered and approved by the owner. The richer texture-based
pass (baked/procedural brick_facade, seamless_concrete, glass, material
instances) stays in the 0.1.4 facade patch.

Squash of branch materials-lookdev-0.1.0 (PR #5).
2026-11-07 20:34:57 +01:00
zwitschi 80ef80b490 attribution: in-game ODbL credit via AGigLineHUD
Completes "Geographic attribution display" for 0.1.0. The demo is built from
OpenStreetMap data (ODbL 1.0) and needs attribution wherever the derived work
is shown, so the credit now lives in the running game, not just the documents.

- AGigLineHUD (C++): plain AHUD::DrawText in the bottom-left draws
  "(c) OpenStreetMap contributors" and "Data (c) OpenStreetMap contributors,
  ODbL 1.0 - openstreetmap.org/copyright", with a shadow pass so it stays
  legible over bright pavement and sky. No UMG widget asset is involved, so a
  cook cannot drop the attribution through a missing widget reference.
- AGigLineGameModeBase: HUDClass = AGigLineHUD, so the credit is on by default
  in both the DemoMap and the ReviewMap.
- AGigLineShotActor: screenshots are requested with the UI shown, so the credit
  appears in every capture under Screenshots/ - the obligation is provable from
  the images rather than only described.

Docs:
- THIRD_PARTY_NOTICES records that the attribution is displayed in-game and
  where the code lives.
- Screenshots/README documents the overlay.
- TODO marks the item done and narrows the remaining ODbL question to the
  shipped-derivative-database posture.

Squash of branch gameplay-attribution-0.1.0 (PR #4).
2026-11-07 18:47:31 +01:00
zwitschi accf3a5306 lighting: fixed daytime rig, real surface materials, dynamic lights
Completes "Fixed daytime lighting and basic ambience" for 0.1.0. All 14
screenshots approved by the owner.

Lighting rig (Tools/ue_build_demo_map.py):
- Sun pitch -50 / yaw 120, intensity 4, warm (255/245/230), atmosphere sun light
- Sky light 2.6 with real-time capture, sky atmosphere, height fog (density 0.008)
- Unbound post-process volume with fixed exposure (min == max brightness) so a
  shot cannot wash out or crush to black depending on how much sky it frames
- Dynamic-only: r.AllowStaticLighting=False plus MOVABLE lights and mesh
  components, so the editor's "LIGHTING NEEDS TO BE REBUILT" warning no longer
  fires and nothing needs baking

Bugs found and fixed on the way:
- Blender diffuse colours do not survive the FBX -> Unreal import: every site
  material arrived white and the terrain arrived with WorldGridMaterial, which
  is what actually made the scene look blown out. The demo builder now creates
  and assigns M_Asphalt, M_Concrete, M_Ground and M_RoadPaint.
- Only one of the three crossings reached the game: each zebra band was its own
  object, so Blender renamed the duplicates .001/.002 and exact-name site
  assembly skipped them. All bands are now one Crossing_Markings mesh.
- Demo cameras: street-level sat inside the facade body (rendering its unlit
  back face) and the crossing camera aimed at the s=36.6 crossing instead of
  the designated s=130.1 (UE X -14956).
- The terrain had no material and imported as a bright default grid.
- Cleared a committed Android File Server SecurityToken (plugin disabled and
  shipping-excluded; the value must stay empty).

Docs:
- Screenshots/README.md: one consolidated table for all 14 shots with map,
  camera view and description; all approved.
- MEMORY.md: records the material-import, exposure, light_color struct,
  band-naming, camera-bounds and lighting-build traps.
- TODO.md: lighting item marked done.

Squash of branch gameplay-lighting-0.1.0 (PR #3).
2026-11-07 18:22:19 +01:00
zwitschi c9e933376c review: restore character + cubes in ReviewMap, re-render all shots
Root cause of the empty review frames: EditorLevelLibrary.load_level/new_level
are deprecated no-ops in -nullrhi commandlets, so staged actors landed in the
current world and got saved over the wrong map. Switched both map builders to
the LevelEditorSubsystem and reordered the review builder to save ReviewMap
before the DemoMap section (the switch-back to a map that only exists in
memory silently failed, writing demo content over ReviewMap).

Rebuilt both maps, re-rendered every screenshot; user visual check passed.
Screenshots/README.md cube naming corrected (A grounded, B floating), approval
states updated; TODO.md visual-review notes closed. MEMORY.md records the
deprecated-call and save-order traps.
2026-11-07 16:23:59 +01:00
zwitschi 985dfcbac7 npc: AGigLineNPCPerson prefab + stable-named screenshots
- New C++ AGigLineNPCPerson: reusable NPC/pedestrian prefab built on the MPFB
  human. ACharacter capsule half-height 83 cm (total 1.66 m, head top ~1.66 m
  so a 1.60 m camera doesn't clip), the character skeletal mesh on the built-in
  mesh as the visible body (feet on Z 0), AutoPossessAI for 0.5.0 pedestrians.
  Staged at Z 0 in the review scene; captured as review-npc-prefab.png.
- AGigLineShotActor now names screenshots by stable camera name (no list-index
  prefix): inserting or reordering cameras no longer renumbers files or orphans
  the old ones. Re-rendered all review/demo shots with stable names.
- ue_build_review_map.py: chmod the target .umap before save_map (git marks maps
  444 on checkout, silently making save_map return False and dropping stages).
- Screenshots/README.md, ROADMAP, TODO updated for the prefab + stable names.
- DemoMap.umap rebuilt by the render pipeline (north buildings + demo cameras).
2026-11-07 15:28:42 +01:00
zwitschi 91fd123ab4 repo: allow screenshots in the repository
- Drop the /Screenshots/* gitignore exclusion so review PNGs are committed
  (LFS-tracked) alongside the review README.
- AGENTS.md Visual review: PNGs are now committed, not kept only on disk.
- 13 review/demo screenshots tracked (25 MB LFS).
2026-11-07 15:01:09 +01:00
zwitschi c11cb4caa4 character: idle standing pose and warm skin, not the grey mannequin
- mpfb_character_export.py: new --pose idle folds the A/T-bind arms down to
  a relaxed standing rest pose (baked via pose.armature_apply before export);
  new make_diffuse synthesizes a warm skin-tone diffuse with a darker
  shorts-suggestive band, replacing the Cycles v2-skin bake that came out
  black and was slow at 1024^2.
- write_png now encodes from img.pixels via numpy (fast) because img.save()
  writes black for an in-memory image.
- Re-exported idle character, re-imported to /Game/Test/Character (138 bones,
  warm M_Character_Export/T_Character_Diffuse); removed stale T_Skin_Diffuse.
- Untracked the review PNGs again: the Screenshots/ gitignore rule had been
  dropped and the parallel session had committed the PNGs, against the
  AGENTS.md 'never commit the PNGs' rule. Restored the ignore rule; only
  Screenshots/README.md stays tracked.
- README/roadmap/memory updated; review-01-character re-pended for approval.
2026-11-07 14:11:06 +01:00
zwitschi cf392a02f7 gameplay: walkable demo map, reset and pause
Tools/ue_build_demo_map.py builds /Game/Hollywood/DemoMap: sun, sky, the hero
facade on the building line, six site meshes imported with collision, and a
player start on the north sidewalk. Tools/ue_import_site.py imports the site
FBXs; terrain, road and sidewalks use complex-as-simple so a simple hull cannot
ramp over the kerbs. Art/blender/site/export_site_fbx.py exports one FBX per
object so each can carry its own collision.

Reset (R) and pause (Escape) join the character and the input context: reset
restores the spawn transform and clears momentum, pause is a real game pause that
releases the cursor. DefaultInput.ini captures the mouse on launch.

Three placement defects found by measuring the imported actors rather than
trusting the plan: the spawn was on the wrong sidewalk because the FBX flip
inverts north, a mirror I added to the exporter double-corrected an already
correct sidewalk, and the street meshes only carry part of the north walk - the
rest is terrain.
2026-11-07 13:17:24 +01:00