From 0189ff00fe227988b185ba6242619dea68573386 Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Tue, 10 Nov 2026 13:48:05 +0100 Subject: [PATCH] docs(todo): bring the task list up to the state the work actually reached - New 'Toolchain - end-to-end asset check (done 2026-11-10)' section: what the e2e command runs, the last PASS, and the seven steps that got it there. Two items stay open - the judge is not trustworthy yet (0/11 on shots the owner approved) and the driver joins the release checks only once it is. - Hero facade tasks rewritten as done/verified where they are: cameras checked, detail seated on the wall, blank lintel band removed, grilles, courses and balustrade added, sandstone authored per slot, banner proportions corrected. What stays open is the generated albedo actually rendering, the inscription and medallions, the banner lettering, and the three review shots. - Vehicle physics: the task list now leads with the two facts that matter (the same pawn falls correctly on ReviewMap's floor; in DemoMap the transform is written directly at any height, with the mover, overlaps, collision and gravity all ruled out by measurement) and the next probe - a fresh map plus staged content group by group. - 0.3.0: the road/sidewalk reconciliation is marked solved - the 2 m 'lid' was an auto-generated convex hull over a 279 m strip, not the geometry, and the cross-section is now continuous at 158 cm. The Chaos vehicle item is marked deferred, pointing at the own-task section. --- TODO.md | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index e100e0d..f6fd8d7 100644 --- a/TODO.md +++ b/TODO.md @@ -9,6 +9,20 @@ Actionable task list for this project. This file is the single, central place fo - When all steps in a version section are done: write a `CHANGELOG.md` entry, then remove the version section from this file. - Release gate: a version is tagged only on the owner's explicit go-ahead once its release checks pass, not automatically when the checkboxes close. +## Toolchain — end-to-end asset check (done 2026-11-10) + +The chain that answers "does the asset look right in both the staging map and the game map" is now one command: `python3 Tools/review/e2e_asset_check.py`. It renders the Blender source, empties both maps, runs both builders, captures, judges with two models, and regenerates `Screenshots/README.md`. Last full run: **PASS on all six steps** (empty maps 9 s, demo build 10 s, review build 9 s, captures 80 s, judge 388 s). + +- [x] Group the sixty tools by sandbox: `Tools/unreal/`, `Tools/blender/`, `Tools/review/`, `Tools/gen/`, `Tools/input/`, with the layout documented in `Tools/README.md`. +- [x] `Tools/unreal/ue_recreate_maps.py`: empties both maps and verifies 0 actors left. Deliberately does not delete the `.umap` - measured that `new_level()` refuses a path whose package is still in memory. +- [x] Whole-level clear in both builders; a prefix-only clear let experiment actors survive into saved maps. +- [x] Two-model judge with reconciliation, and a two-checkpoint texture generator that compares before choosing. +- [x] Texture generation through the documented Stability Matrix workflows (`texture` subcommand). +- [x] Local ComfyUI documented, including "start Stability Matrix first" and the per-model licence rules. +- [x] Driver hardening: unlink result files before each step, stream child output to a per-step log, refuse to start while another editor is alive. +- [ ] **Make the judge useful again.** It reports 0/11 on shots the owner has approved and has been wrong in both directions. Until its expectations are re-derived, treat a _model disagreement_ as the signal and the verdict as noise. +- [ ] Wire the e2e driver into the release checks once the judge can be trusted. + ## Vehicle physics — Chaos rig (own task, from `0.3.0`) Split out of `0.3.0` because it is a physics problem, not an asset one. **The Chaos pawn is parked**: with it staged the actor is launched to **Z 1993 cm** (18 m up) and reports **0 wheels**, so it litters the demo without being drivable. The visible car is the plain panel set, which looks right and is what the review shots show. @@ -113,9 +127,14 @@ Deferred rather than guessed. What a fresh session needs: 2. In parallel, spawn a stock `AWheeledVehiclePawn` with `SK_Vehicle_Sedan` and default settings in the same spot: if the stock pawn settles, the difference is in `AGigLineVehicle`'s setup (mass override, stability control, our movement subclass). 3. Only after the bisect: fix, then confirm `Wheels.Num() == 4`. +### Where it was left (2026-11-10) + +Two facts that matter more than the hypothesis list above: on `ReviewMap`'s flat floor the **same pawn falls correctly** (Z 200 -> 87, vZ -663), and in `DemoMap` it teleports upward at any height - including 25 m in the air - with the transform written directly (clamping velocity to zero every frame does not stop it) while the body reports a near-zero velocity. Disabling the movement component's tick changes nothing; there are zero overlaps; the body is genuinely dynamic (`profile=PhysicsActor`); `shadow`-style collision explanations were ruled out by staging the terrain with **collision disabled entirely** and seeing the pawn still rise. + ### Tasks -- [D] Give `SK_Vehicle_Sedan` a physics asset whose single chassis body matches the car's box and is positioned below the shell, then confirm the pawn settles on the road instead of launching. +- [D] Give `SK_Vehicle_Sedan` a physics asset whose single chassis body matches the car's box and is positioned below the shell, then confirm the pawn settles on the road instead of launching. **Deferred**: the chassis box, mass and gravity all measure correct, so this is not the shape of the body. +- [ ] Find what writes the actor transform in `DemoMap` but not in `ReviewMap`. The map diff is empty where it matters - same `kill_z`, same gravity, no World Partition, neither has a physics volume - so the next probe is a fresh map with staged content added group by group (`Tools/unreal/ue_vehicle_probe_map.py` already does the one-mesh version). - [ ] Confirm `Wheels.Num()` becomes 4 once the vehicle is created; log it at the settle check. - [ ] Only then re-stage the pawn, re-add enter/exit and the driving route. @@ -189,10 +208,20 @@ Measured against the plate, that splits into: ### Tasks -- [x] Confirm the hero captures frame `Hero_Facade` - **done**: the cameras are aimed at (-13336, 1307), the hero actor is there, and the frontage is at the origin. -- [ ] Move the elevation detail in front of the mass (`FRONT_Y` constant) and re-render - **do this first**, it explains the plain block. -- [ ] Add surface detail the reference demands: rusticated banding, carved lettering on the motto band, window grilles, balustrade and finials on the parapet. -- [ ] Rebuild the El Capitan hero facade to match the reference photography: cornice depth, the banner proportions, window rhythm, and the three entry portals. +Done on 2026-11-09/10, each verified by a capture: + +- [x] Confirm the hero captures frame `Hero_Facade` - cameras at (-13336, 1307), hero actor there, frontage at the origin. +- [x] Seat the elevation detail in front of the mass (`FRONT_Y` + `seat_on_front()`, 99 parts moved) - banners, windows and portals render now. +- [x] Remove the blank lintel band across the portals; the three doorways are 1.2 m deep with five steps each. +- [x] Window grilles (7 vertical + 5 horizontal bars per bay), five ashlar courses, roof balustrade with 38 balusters. +- [x] Warm sandstone in the engine - `tint_imported_materials()` authors one material per slot from the reference. +- [x] Banner proportions 1.35 x 6.2 m hung from 7.2 m, matching the photographs. + +Open: + +- [ ] **Make the generated ashlar albedo render.** It is imported to `/Game/Hollywood/Textures/T_FacadeAshlar_AI`, the material contains `TextureSampleParameter2D` -> `Multiply` -> Base Color with 6x UV tiling, and the mesh has UVs - but the elevation still shows the flat tint. Probe the compiled Base Color pin, and whether `TextureSampleParameter2D` needs its sampler type set explicitly. +- [ ] Carved inscription on the motto band and medallion relief that reads at 45 m (texture work, not geometry). +- [ ] Crimson banner tone and the JIMMY KIMMEL LIVE lettering. - [ ] Re-render the three ReviewMap staging shots and put them back in the status table for review. ## 0.3.0 — Chaos vehicle, enter/exit, closed driving route (weeks 10–13) @@ -202,7 +231,7 @@ Measured against the plate, that splits into: - [A] Model one vehicle in Blender with collision meshes; export to Unreal. **Model done** (`Tools/blender/vehicle_build.py` → `Art/blender/vehicle/gigline-sedan.blend`, preview in `Art/blender/vehicle/preview.png`): 4.72 x 1.80 x 1.44 m, 2.78 m wheelbase, 1.62 m track, 0.33 m wheels, 252 triangles, four `UCX_` convex hulls. Dimensions come from real sedan figures and are logged to the report, so the vehicle config can read them rather than restating them. - **Imported into Unreal** (`Tools/unreal/ue_vehicle_import.py` → `/Game/Hollywood/Vehicle`), split per the vehicle-artist object split: `SM_Vehicle_Body` (3 slots, 4.76 x 1.76 x 1.28 m), `SM_Vehicle_Glass`, `SM_Vehicle_Light_Front`, `SM_Vehicle_Light_Rear`, `SM_Vehicle_Mirrors`, and one `SM_Vehicle_Wheel` (0.22 x 0.66 x 0.66 m) reused four times. The body FBX carries the `UCX_` hulls as simple collision. - **LODs cut for real:** decimating the duplicate gives LOD1 at 38 triangles and LOD2 at 14, against 132 for LOD0. The first attempt duplicated the shell unchanged and produced 84-triangle LODs that saved nothing - worth remembering as the failure mode of a "LOD" step nobody measures. - **LOD group wiring is open:** `StaticMeshEditorSubsystem.import_lod` is unavailable in a headless commandlet (`get_editor_subsystem` returns None), so the LOD meshes import as their own assets and the group still needs an editor session. -- [~] Set up Chaos Vehicle with wheel and physics configuration. **It sits on the road now; it does not drive yet.** +- [D] Set up Chaos Vehicle with wheel and physics configuration. **Deferred to its own task** (`Vehicle physics — Chaos rig`): the pawn is parked, the visible car is the panel set, and the remaining question is what writes the actor transform in `DemoMap` but not in `ReviewMap`. - **Fixed the floating:** the physics asset had a body per bone, and the four wheel bodies intersected the chassis body and pushed the car 3.7 m up. It is now a **single chassis body** on the `root` bone (452 x 205 x 40 cm), which is what Unreal's own vehicle template uses - Chaos simulates the wheels itself, they must not be separate rigid bodies. Settle check: **Z 119 cm** at a spawn of 120 (was 494). - **Drive test fails, with a specific cause:** `-drivetest` holds full throttle for 3 s and reports speed and distance. Result: `speed=0 cm/s, travelled 2.2 m -> FAIL`, and BeginPlay logs **`0 wheel objects after register`** while the component reports 4 wheel setups. The setups exist but no wheels are created from them, so there is nothing to apply torque to. - **Next:** confirm the skeleton's bone names match the setups (`Wheel_FL`, `Wheel_FR`, `Wheel_RL`, `Wheel_RR`) - a name mismatch silently produces zero wheels - and give the front and rear pairs their own `UChaosVehicleWheel` subclasses rather than the base class, which is what the setups point at today. @@ -212,12 +241,12 @@ Measured against the plate, that splits into: - [x] Fix the character and car floating. **The measurement was taken at the wrong moment.** The foot probe ran in `BeginPlay`, while the pawn is still at its spawn height and falling, so every trace reported a surface far below it (`ground 366` against an actor at 561) and read as a float that was not there. The probe now runs **three seconds after spawn**, from the capsule's feet, on three channels, and names the actor it hits. Character: the player start at Z 600 left the soles 39 cm in the air (the capsule settles at 561 on this pavement); the start is now the measured 561. Car: the template's lowest geometry is exhaust, so grounding on the whole model put the tyres 4 cm above the origin - it is now grounded on its wheels, staged at Z 342 after the traced road height (366) disagreed with the visible road by ~25 cm. - [x] Fix the vehicle's material colour. The template's `car paint` is a legacy mix-shader graph that the FBX exporter cannot map, so `SM_Vehicle_Body` imported holding `WorldGridMaterial` and rendered black while Blender showed red. Legacy graphs are now converted to Principled before export (saturated colour wins over the grey diffuse next to it), and the staged body panel is assigned `M_Vehicle_HatchPaint`. Judge: `verdict=yes confidence=0.9`. - [x] Fix the missing vehicle glazing. The `windows` material was metallic 1.0 with roughness 0.0 - a black void that read as an empty cabin. Now tinted translucent (opacity 0.85, roughness 0.08); opacity 0.45 was tried first and made the glass invisible. The vision judge still returns `verdict=no` for the frame, disagreeing with what is visibly tinted glass; it is advisory, and the human verdict decides. -- [A] Reconcile the road and sidewalk surfaces. **The road strip fans past the sidewalk at the curved end.** +- [x] Reconcile the road and sidewalk surfaces. **Solved: the road strip was a single 279 m mesh whose auto-generated convex hull sat 2 m above the visible surface.** - The site export now slices sidewalks and kerbs into ~20 m pieces with explicit `UCX_` boxes, and the slice cuts are fixed (the far cut kept the wrong half, so every slice spanned the whole street). Slice tops descend honestly along the street: 380, 340, 309, 284, 254, 231, 205, **169 at the player's X**, 138, 104 cm. - In the map at the same X: `Sidewalk_North_07` tops at **169 cm**, `Road_Hollywood` at **366 cm**. The road is ~2 m above its sidewalk, so the player lands on the road and no collision setting on the sidewalk can change that. - Neither slicing, `UCX_` hulls, `set_complex_collision_as_simple`, nor winding (all 2790 sidewalk faces point up) changed the outcome - each of those was the wrong layer. - **Cause found:** the road is built across -10.5..+10.5 m and the north sidewalk +10.5..+15.8 m, so on the straight they meet at the gutter - but the strips follow a curved centreline and the fan-out pushes the road's outer edge to **-13.8 m**, overlapping the sidewalk band (**-17.3..-11.8 m**). In that overlap the road sits at 366 cm and the sidewalk at 158 cm. - - **Fix:** clamp each row's outer offsets to the nominal gutter in `strip()` so the road cannot fan past the sidewalk, or trim the road's ends. One function in `Art/blender/street/street_mesh.py`, then re-export, re-import and the 14 s probe confirms it. + - **Resolved 2026-11-10:** the real cause was the **collision hull**, not the geometry. A 279 m strip imports with one auto-generated convex hull whose top is the mesh's _maximum_ height, so every downward trace landed on a flat lid at 366 cm. Slicing the road like the sidewalks, and removing the single `Road_Hollywood` asset from the map so the slices win, gives a continuous cross-section: `Terrain 154 / Sidewalk_North_07 158 / Road_Hollywood_07 158`. The player now stands on `Sidewalk_North_07` at 158 cm with feet at 161. - **Superseded:** sample both source meshes at the player's XY in `Art/blender/street/street-2026-11-06.blend`. The road is built as `dem_z + 0.02` and the sidewalk as `dem_z + kerb * t` from the _same_ DEM sampler, so a 2 m gap cannot come from that code - the suspect is the DEM lookup or the mesh's coordinate frame, not the assembly logic. - [ ] Implement enter/exit interaction. - [ ] Build a closed driving route with boundaries.