3 Commits
Author SHA1 Message Date
zwitschi 5e328f5d3e fix(vehicle): enable ChaosVehiclesPlugin so the Chaos vehicle is actually created
The Chaos vehicle never existed: ChaosVehiclesPlugin is EnabledByDefault=false and
was absent from GigLine.uproject, so FChaosVehicleManager was null and
OnCreatePhysicsState skipped CreateVehicle() (read from the engine source). The
pawn stayed at setups=4 wheels=0 output=null and the mesh fell back to the regular
rigid-body solver, which is what teleported upward.

- Enable ChaosVehiclesPlugin in GigLine.uproject. CreateVehicle() now runs:
  'wheels 4', 'output present', 'setups=4 wheels=4'.
- Drop the constructor's SetSimulatePhysics(true) / collision-profile override: the
  Chaos movement component drives the mesh through async physics, and forcing the
  regular solver kept the body out of the vehicle solver.

The plugin fix turns the teleport into a stable 'float at Z 545' (540 cm above the
floor) in both probe maps - suspension tuning is the next bug.
2026-11-10 16:39:42 +01:00
zwitschi 620cbe181c docs(vehicle): fresh probe data — the writer is the physics sim, asset pipeline ruled out
Rebuilt and re-ran the vehicle probe workflow:

- Control (no terrain) falls and settles (300 -> 78 cm).
- Terrain rises (313 -> 545 cm) with body velocity pinned to 0 and zero overlaps.
- Turning physics OFF at 3 s stops the rise, so the Chaos vehicle solver is
  teleporting the body (transform set directly, no velocity) - not an external
  SetActorLocation.
- 0 wheels in both runs, so the missing wheels are not the trigger; the terrain is
  what flips fall to rise.

Ruled out the asset pipeline with commandlets: the FBX, the imported
SK_Vehicle_Sedan (476x228x144 cm), the physics asset (452x205x40) and Terrain_DEM
(380x210 m) are all correct; the logged '1 cm bounds' is a stale component read,
not a bad mesh.

Next: bisect step 2 - a stock AWheeledVehiclePawn beside AGigLineVehicle in the
terrain probe map.
2026-11-10 16:07:39 +01:00
zwitschi 66ca685059 fix: change order in screenshot capture 2026-11-10 15:47:12 +01:00
5 changed files with 87 additions and 41 deletions

No files matched your search

+4
View File
@@ -14,6 +14,10 @@
{
"Name": "EnhancedInput",
"Enabled": true
},
{
"Name": "ChaosVehiclesPlugin",
"Enabled": true
}
]
}
@@ -65,9 +65,12 @@ AGigLineVehicle::AGigLineVehicle(const FObjectInitializer& ObjectInitializer)
{
Body->SetSkeletalMesh(MeshFinder.Object);
}
Body->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
Body->SetCollisionProfileName(TEXT("PhysicsActor"));
Body->SetSimulatePhysics(true);
// The Chaos vehicle movement component drives this mesh through its async physics; it
// calls CreateVehicle() on the movement component, which builds the wheels and the
// vehicle state. Calling SetSimulatePhysics(true) here instead put the mesh into the
// REGULAR rigid-body solver, which is why CreateVehicle() never ran (output null,
// wheels 0) and why the plain body then teleported upward in DemoMap. Leave the physics
// to the movement component.
}
if (UChaosWheeledVehicleMovementComponent* Movement =
+35
View File
@@ -680,3 +680,38 @@ A visual change needs **build → import → render**, never just a render: `ren
- The hero facade rework (split out of 0.3.0) is **closed at "surface detail that reads at 45 m"**. Done and committed: carved inscription, stepped medallions, light motto band + proud surround (all three had been buried inside the parapet), and gold JIMMY KIMMEL LIVE banner lettering.
- **Banner lettering is procedural, not ComfyUI.** `Tools/gen/generate_banner_texture.py` draws the exact title with Pillow + Liberation Sans Bold. An image model (Qwen-Image 2.1) would mangle a trademark string and is research-only, so for a _known_ string a font rasteriser is strictly better than txt2img. Reserve ComfyUI/Qwen for things that need a model, not for literal text.
- **Deferred to 0.9.0 (owner's instruction):** volute capital depth, lattice grille depth, and the full realism pass (banded rustication, measured materials, texel density, LOD/collision). The 0.9.0 "Hero façade (6840)" item records the hand-off.
## 2026-11-10 — Vehicle launch: the asset pipeline is ruled out
Re-checked the three "asset is broken" suspects with commandlets and each is **correct**:
- `vehicle_skeletal.fbx` geometry is X −2.38..2.38 m (the full car, 296 verts), not degenerate.
- Imported `SK_Vehicle_Sedan` bounds are **origin (0,0,72) extent (238,114,72) cm** — the correct 4.76 x 2.28 x 1.44 m car, so the import scale is fine.
- `Terrain_DEM` bounds are 380 x 210 m with no degenerate/NaN scale, and its body setup reports no convex/box/sphere elements.
So the "1 cm bounds" logged in the vehicle diagnostic is a **stale runtime read of the component bounds**, not an asset defect — the skeletal mesh is fine and the symptom is the teleport writing the actor transform, not a bad mesh. The launch is a runtime (Chaos movement / map) problem, not an import or build one.
## 2026-11-10 — Vehicle launch: fresh probe data, the writer is the physics sim
Rebuilt and re-ran the `ue_vehicle_probe_map.py` workflow (after `chmod u+w` the read-only `.umap`s and `rm` the four stale `VehicleProbe*` maps — `delete_asset` leaves the `.umap` on disk so the tool's own fallback never fires):
| t | control (no terrain) | terrain |
| ---- | ------------------------- | ------------------------------- |
| 0.03 | Z 300 vZ 0 | Z 313 vZ 0 |
| 1.50 | Z 306 vZ 0 | Z 442 vZ 0 |
| 2.25 | Z 299 **vZ −242** (falls) | Z 545 **vZ 1** (jumps up) |
| 3.0 | settles Z 78 | settles Z 545, then physics OFF |
- **Control falls and settles** (300 → 78 cm); **terrain rises** (313 → 545 cm) with the body velocity pinned to 0 throughout and `overlaps: 0 []`.
- **Turning physics OFF at 3 s stops the rise**: `physics OFF at Z 545` → `after 1 s without physics, Z 545`. So the writer is the physics simulation (Chaos vehicle solver teleporting the body, transform set directly), **not** an external `SetActorLocation` — the "transform written directly" reads that way because the solver moves the body without a velocity.
- **0 wheels in both runs** (control also has `setups=4 wheels=0`), so the missing wheels are not the trigger — control falls with 0 wheels too. The terrain is what flips fall → rise.
- The `1 cm` bounds (`extent 1,1,1`) persist in the diagnostic and are a **stale component read**, not the mesh (the imported `SK_Vehicle_Sedan` bounds are the correct 476 × 228 × 144 cm).
Next: the bisect plan step 2 — spawn a **stock `AWheeledVehiclePawn`** with `SK_Vehicle_Sedan` beside `AGigLineVehicle` in the terrain probe map. If the stock pawn also rises, the asset + terrain interaction is at fault; if it settles, `AGigLineVehicle`'s setup (movement subclass, mass override, panel attachment) is.
## 2026-11-10 — Vehicle "0 wheels" root cause: ChaosVehiclesPlugin was disabled
- **The Chaos vehicle never existed because `ChaosVehiclesPlugin` was not enabled.** It is `EnabledByDefault: false`, it was absent from `GigLine.uproject` (only `EnhancedInput`), and absent from `Config/*.ini`. Consequence, read straight from the engine source (`ChaosVehicleMovementComponent.cpp` `OnCreatePhysicsState`): `CreateVehicle()` runs only when `World->IsGameWorld() && GetPhysicsScene() && FChaosVehicleManager::GetVehicleManagerFromScene(PhysScene)` — and the manager is null when the plugin module never started. So the vehicle stayed at `setups=4 wheels=0 output=null`, and the mesh fell back to **regular** rigid-body physics (the constructor's `SetSimulatePhysics(true)`), which is what teleported upward.
- **Fix:** add `{"Name": "ChaosVehiclesPlugin", "Enabled": true}` to `GigLine.uproject`. Result: `CreateVehicle() entered → wheels 4`, `first UpdateState - output present`, `diag ... setups=4 wheels=4`.
- **Also removed** `SetSimulatePhysics(true)` / `SetCollisionProfileName("PhysicsActor")` / `SetCollisionEnabled` from the `AGigLineVehicle` constructor: the Chaos movement component drives the mesh through its async physics, and forcing the regular rigid-body solver is what kept the body out of the vehicle solver.
- **The plugin fix converts "teleport up" into "float at Z 545".** With 4 wheels the pawn now settles at a stable Z 545 (540 cm above the ReviewMap floor at Z 5) in *both* the control and terrain probe maps — no teleport, but the suspension holds the chassis ~5 m too high. That is the next bug: wheel radius / suspension rest-length / chassis-box offset, not the vehicle creation.
+4
View File
@@ -11,6 +11,8 @@ Actionable task list for this project. This file is the single, central place fo
## Toolchain — end-to-end asset check (done 2026-11-10)
> [!IMPORTANT] Plan for 0.3.1 before other patches
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`.
@@ -133,6 +135,8 @@ Deferred rather than guessed. What a fresh session needs:
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.
**Fresh probe data (2026-11-10) — the writer is the physics sim, not an external setter.** Control (no terrain) falls and settles (300 → 78 cm); terrain rises (313 → 545 cm) with body velocity pinned to 0 and `overlaps: 0`. **Turning physics OFF at 3 s stops the rise** (`physics OFF at Z 545` → `after 1 s without physics, Z 545`), so the Chaos vehicle solver is teleporting the body (transform set directly, no velocity). Both runs have `setups=4 wheels=0`, so the missing wheels are not the trigger — control falls with 0 wheels too; the terrain is what flips fall → rise. The asset pipeline is ruled out (FBX, `SK_Vehicle_Sedan` import 476×228×144 cm, physics asset 452×205×40, `Terrain_DEM` 380×210 m all correct; the `1 cm` bounds is a stale component read). Next: bisect step 2 — a stock `AWheeledVehiclePawn` beside `AGigLineVehicle` in the terrain probe map.
### 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. **Deferred**: the chassis box, mass and gravity all measure correct, so this is not the shape of the body.
+38 -38
View File
@@ -34,45 +34,14 @@ run_cmdlet() {
# Order matters. The demo builder rebuilds the site materials, so any actor staged
# by another tool must be (re)staged after it or it keeps a reference to a material
# that no longer exists - that is how 604 actors ended up untextured once.
run_cmdlet ue_build_demo_map.py "1/5 rebuild the demo map (materials, site, frontage)"
run_cmdlet ue_apply_facade_kit.py "2/5 assemble the facade kit"
run_cmdlet ue_stage_theatre_trim.py "3/5 stage the theatre trim"
run_cmdlet ue_audit_scene.py "4/6 audit the scene (materials, placement, labels)"
run_cmdlet ue_build_review_map.py "5/6 stage the demo shot cameras"
run_cmdlet ue_build_demo_map.py "1/7 rebuild the demo map (materials, site, frontage)"
run_cmdlet ue_apply_facade_kit.py "2/7 assemble the facade kit"
run_cmdlet ue_stage_theatre_trim.py "3/7 stage the theatre trim"
run_cmdlet ue_audit_scene.py "4/7 audit the scene (materials, placement, labels)"
run_cmdlet ue_build_review_map.py "5/7 stage the demo shot cameras"
tail -3 /tmp/ue-review-map-result.txt 2>/dev/null || true
echo "== 6/6 capture the demo map =="
# Clear the engine's screenshot folder first. The collect step below copies every
# review-*.png it finds in Saved/, so without this a shot retired from the camera list
# keeps coming back as a stale file - that is how a removed walk shot reappeared with
# byte-identical content after a run that never captured it.
rm -rf "$REPO"/Game/GigLine/Saved/Screenshots/* "$HOME"/.config/Epic/GigLine/Saved/Screenshots/* 2>/dev/null || true
# Recreate the folder: the engine writes into it and does not recreate a deleted
# directory, which silently produced zero captures in the run that removed it.
mkdir -p "$REPO/Game/GigLine/Saved/Screenshots/LinuxEditor"
# The engine path is absolute: this step runs from the repo, not from $ENGINE, and a
# bare ./Engine/... failed with "No such file or directory" while every commandlet
# above succeeded through run_cmdlet's cd.
"$ENGINE/Engine/Binaries/Linux/UnrealEditor-Cmd" "$PROJ" /Game/Hollywood/DemoMap \
-game -windowed -ResX=1920 -ResY=1080 -nopause -nosplash -thirdperson -stdout
echo "== collect the demo screenshots =="
mkdir -p "$REPO/Screenshots/demo"
rm -f "$REPO"/Screenshots/demo/review-*.png
found=0
for src in \
"$REPO/Game/GigLine/Saved/Screenshots"/*/review-*.png \
"$REPO/Game/GigLine/Saved/Screenshots"/*/*/review-*.png \
"$HOME/.config/Epic/GigLine/Saved/Screenshots"/*/review-*.png; do
[ -e "$src" ] || continue
case "$(basename "$src")" in
*demo-*) cp -f "$src" "$REPO/Screenshots/demo/"; found=1 ;;
esac
done
[ "$found" = "1" ] || { echo "ERROR: no demo screenshots found"; exit 1; }
ls -1 "$REPO/Screenshots/demo"
echo "== 6b/7 capture the review map (asset staging) =="
echo "== 6a/7 capture the review map (asset staging) =="
# The ReviewMap stages the models on their own - imported assets, camera angles and the
# lighting comparison - which is a different question from "does the game map look right".
# Its shots collect into Screenshots/review/ so the two reviews stay separate.
@@ -81,7 +50,7 @@ mkdir -p "$REPO/Game/GigLine/Saved/Screenshots/LinuxEditor"
"$ENGINE/Engine/Binaries/Linux/UnrealEditor-Cmd" "$PROJ" /Game/Test/ReviewMap \
-game -windowed -ResX=1920 -ResY=1080 -nopause -nosplash -stdout
echo "== 6c/7 collect the review-map screenshots =="
echo "== 6b/7 collect the review-map screenshots =="
mkdir -p "$REPO/Screenshots/review"
rm -f "$REPO"/Screenshots/review/review-*.png
found_review=0
@@ -98,6 +67,37 @@ done
[ "$found_review" = "1" ] || echo "WARN: no review-map screenshots found"
ls -1 "$REPO/Screenshots/review" 2>/dev/null | head -20
echo "== 6c/7 capture the demo map =="
# Clear the engine's screenshot folder first. The collect step below copies every
# review-*.png it finds in Saved/, so without this a shot retired from the camera list
# keeps coming back as a stale file - that is how a removed walk shot reappeared with
# byte-identical content after a run that never captured it.
rm -rf "$REPO"/Game/GigLine/Saved/Screenshots/* "$HOME"/.config/Epic/GigLine/Saved/Screenshots/* 2>/dev/null || true
# Recreate the folder: the engine writes into it and does not recreate a deleted
# directory, which silently produced zero captures in the run that removed it.
mkdir -p "$REPO/Game/GigLine/Saved/Screenshots/LinuxEditor"
# The engine path is absolute: this step runs from the repo, not from $ENGINE, and a
# bare ./Engine/... failed with "No such file or directory" while every commandlet
# above succeeded through run_cmdlet's cd.
"$ENGINE/Engine/Binaries/Linux/UnrealEditor-Cmd" "$PROJ" /Game/Hollywood/DemoMap \
-game -windowed -ResX=1920 -ResY=1080 -nopause -nosplash -thirdperson -stdout
echo "== 6d/7 collect the demo screenshots =="
mkdir -p "$REPO/Screenshots/demo"
rm -f "$REPO"/Screenshots/demo/review-*.png
found=0
for src in \
"$REPO/Game/GigLine/Saved/Screenshots"/*/review-*.png \
"$REPO/Game/GigLine/Saved/Screenshots"/*/*/review-*.png \
"$HOME/.config/Epic/GigLine/Saved/Screenshots"/*/review-*.png; do
[ -e "$src" ] || continue
case "$(basename "$src")" in
*demo-*) cp -f "$src" "$REPO/Screenshots/demo/"; found=1 ;;
esac
done
[ "$found" = "1" ] || { echo "ERROR: no demo screenshots found"; exit 1; }
ls -1 "$REPO/Screenshots/demo"
# The scene audit is a gate: a wrong-material or misplaced actor is exactly the
# kind of failure that still renders plausibly.