- kerb_height ramp run now derives from --max-ramp-grade (default 8%), giving 1.63 m instead of the fixed 1.5 m (8.7%). Crossing route measures 3.4 cm at 0.25 m sampling. - site_assembly pre-check: coverage is independent of --sample (it used to shrink the route), and it now prints the grade and the s/offset location of the worst step so a step can be located instead of guessed. - Documents the remaining south s=198 / north s=251 strip discontinuity as a finding on the 'audit collision gaps' item rather than claiming it fixed. - Street + site rebuilt, site re-imported (7/7), DemoMap rebuilt; packaged -qaselftest PASS.
180 lines
12 KiB
Markdown
180 lines
12 KiB
Markdown
# Blender sources
|
||
|
||
Editable `.blend` files. Everything here is regenerable or hand-editable, and every generated file records the exact command that produced it.
|
||
|
||
## Modelling skills
|
||
|
||
Optional local Blender skill packs are agent instructions, not add-ons; nothing in the pipeline depends on them. They are not distributed with the repository.
|
||
|
||
## Blockout
|
||
|
||
`blockout/blockout-2026-11-06.blend` — OSM blockout for the demo bounds, imported with Blosm from the committed extract. 276 objects, 87 meshes, in collections split by feature (`…_buildings`, `…_roads_secondary`, `…_paths_footway`, `…_roads_primary`, …).
|
||
|
||
### Rerun command
|
||
|
||
The Flatpak Blender cannot be launched with `flatpak run` from an agent shell, so the binary inside the app tree is called directly with the Flatpak user scripts path. This is exact, not approximate:
|
||
|
||
```bash
|
||
B=/var/lib/flatpak/app/org.blender.Blender/x86_64/stable/active/files
|
||
C="$HOME/.var/app/org.blender.Blender/config/blender/5.2"
|
||
|
||
LD_LIBRARY_PATH="$B/blender/lib" \
|
||
XDG_CONFIG_HOME="$HOME/.var/app/org.blender.Blender/config" \
|
||
BLENDER_USER_SCRIPTS="$C/scripts" \
|
||
"$B/blender/blender" -b --factory-startup \
|
||
--python Tools/blosm_blockout.py -- \
|
||
--osm Geo/raw/osm-api-map-2026-11-06.osm \
|
||
--bounds 34.1006,-118.3422,34.1020,-118.3370 \
|
||
--assets-dir /run/media/system/DATA/Downloads/blosm-assets/assets \
|
||
--out Art/blender/blockout/blockout-2026-11-06.blend
|
||
```
|
||
|
||
Run time is about 36 s for this extent. Two headless-only workarounds are baked into the script and must stay there:
|
||
|
||
1. Blosm refuses to import until an asset directory is set; the paid asset pack path is passed explicitly and is **not** committed.
|
||
2. In background mode the GUI never fills Blosm's default level table, and the add-on then takes a code path with a broken relative import. The script seeds one entry.
|
||
|
||
## Frame correction
|
||
|
||
Blosm projects with a **sphere** of radius 6 378 137 m about the origin, not an ellipsoid. Against EPSG:26911 that is conformal but about 0.4 % oversized and rotated by the meridian convergence, which put the theatre ~2 m off. `Tools/blosm_blockout.py --origin` therefore fits a six-parameter affine from Blosm's frame into UTM on five spread control points and applies it to the imported roots. Fit residual: **0.0 cm**. After it, the blockout and the terrain share one metric frame.
|
||
|
||
Two traps, both already handled in the script: transform only **root** objects (children inherit, and doing both applies the transform twice — that looked like a 2 m placement error), and fit an affine, not a similarity (a similarity leaves ~30 cm).
|
||
|
||
## Terrain
|
||
|
||
`terrain/terrain-2026-11-06.blend` — regular grid from the committed 3DEP DEM, built by `Tools/terrain_from_dem.py`.
|
||
|
||
```bash
|
||
B=/var/lib/flatpak/app/org.blender.Blender/x86_64/stable/active/files
|
||
LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b --factory-startup --python Tools/terrain_from_dem.py -- --dem Geo/raw/dem-3dep-1m-26911-2026-11-06.tif --osm Geo/raw/osm-api-map-2026-11-06.osm --out Art/blender/terrain/terrain-2026-11-06.blend
|
||
```
|
||
|
||
- 191 × 106 grid at 2 m over X −330…+50, Y −100…+110: 20 246 vertices, 13 640 faces.
|
||
- Z is NAVD88 minus 115.911 m, the DEM value at the origin, so the origin ground is Z 0.
|
||
- Building footprints from the OSM extract are **cut out** (6 310 cells), so rooftops never become terrain. 72 footprints masked.
|
||
- Z range −2.80…+8.19 m. The high values are the ground rising north of the boulevard, not rooftops: the maximum sits at the northern edge, Y +110.
|
||
|
||
Spot checks against the measured cross-sections:
|
||
|
||
| Point | Terrain Z |
|
||
| ----------------------------- | --------: |
|
||
| Origin, Hollywood × Highland | 0.00 |
|
||
| Orange Drive end of the block | +3.39 |
|
||
| North sidewalk mid-block | +1.43 |
|
||
| South gutter, mid-block | +0.93 |
|
||
| Road centre, mid-block | +1.38 |
|
||
|
||
That reproduces both the 3.4 m eastward fall and the ~2 % crown, so the DEM, the cross-sections, and this mesh agree.
|
||
|
||
## Street corridor
|
||
|
||
`street/street-2026-11-06.blend` — road, kerbs, and both sidewalks, built by `Tools/street_mesh.py` from the DEM and the centreline.
|
||
|
||
```bash
|
||
B=/var/lib/flatpak/app/org.blender.Blender/x86_64/stable/active/files
|
||
LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b --factory-startup \
|
||
--python Tools/street_mesh.py -- \
|
||
--osm Geo/raw/osm-api-map-2026-11-06.osm \
|
||
--dem Geo/raw/dem-3dep-1m-26911-2026-11-06.tif \
|
||
--out Art/blender/street/street-2026-11-06.blend
|
||
```
|
||
|
||
- `Road_Hollywood`: 8 120 verts, 7 812 faces, carriageway −10.5…+10.5 m, DEM elevations plus a 2 cm lift so it does not z-fight the terrain.
|
||
- `Sidewalk_South` 4.0 m wide, `Sidewalk_North` 5.3 m wide. The kerb upstand is
|
||
**full at the road-side edge and tapers to zero at the building-side edge**, so
|
||
the walk surface meets the terrain flush (before `0.1.1` the outer lip stood the
|
||
full kerb height above the DEM — a 15.8 cm ledge).
|
||
- `Kerb_South`, `Kerb_North`: vertical faces, mostly **0.13 m** — the 0.15 m assumption minus nothing on the road side — and flushed to 0 within ±2.5 m of each signalised crossing with a 1.5 m blend. Measured from the built mesh: 256 steps at 0.13 m, 15 flush, a few in transition.
|
||
|
||
Crown check on the built mesh at mid-block: gutter −10.5 m → +0.99, −5 m → +1.38, centre → +1.52, +5 m → +1.58, +10.5 m → +1.52. The crown sits just north of the centreline, as the cross-sections said.
|
||
|
||
Assumptions, recorded rather than hidden: kerb upstand 0.15 m (DEM cannot resolve it), sidewalk widths from the setback arithmetic, and crossing ramps modelled as kerb flushes rather than graded ramps. Crossing markings, kerb radii at the junctions, driveway aprons, drainage inlets, and pavement joints are **not** modelled.
|
||
|
||
## Site assembly
|
||
|
||
`site/site-2026-11-06.blend` — the three sources in one file, with a walkability pre-check.
|
||
|
||
```bash
|
||
B=/var/lib/flatpak/app/org.blender.Blender/x86_64/stable/active/files
|
||
LD_LIBRARY_PATH="$B/blender/lib" "$B/blender/blender" -b --factory-startup \
|
||
--python Tools/site_assembly.py -- --out Art/blender/site/site-2026-11-06.blend
|
||
```
|
||
|
||
Objects are appended from the source files, not regenerated, and grouped into `Site_Terrain`, `Site_Street`, `Site_Blockout` so collision authoring can address them by category. Totals: 281 objects, ~58 k triangles (street 26 784, terrain ~26 k, blockout 4 680).
|
||
|
||
### Walkability pre-check
|
||
|
||
A downward raycast on a 1 m grid along both sidewalks and the designated crossing, ignoring blockout meshes so marquees and canopies overhead do not count as ground:
|
||
|
||
| Route | Samples | Holes | Z range | Worst step |
|
||
| ----------------- | ------: | ----: | ------------- | ---------: |
|
||
| South sidewalk | 279 | 0 | −0.48 … +3.06 | 13.4 cm (s=198) |
|
||
| North sidewalk | 279 | 0 | +0.06 … +3.76 | 6.9 cm (s=33) |
|
||
| Crossing at 130 m | 26 | 0 | +1.14 … +1.80 | 9.0 cm (off −8.5) |
|
||
|
||
At `--sample 0.25` the same routes measure 11.6 cm / 8.0 cm / 3.4 cm. The
|
||
pre-check now prints the grade and the **location** of the worst step, and its
|
||
coverage no longer shrinks with `--sample`.
|
||
|
||
No holes anywhere, so nothing drops the player on either side. The two flagged steps:
|
||
|
||
- ~~15.8 cm at s≈207, the sidewalk's outer edge~~ — **fixed in `0.1.1`**: the
|
||
sidewalk upstand now tapers to zero at the building side, so the outer edge is
|
||
flush with the terrain (north route 15.1 → 6.9 cm).
|
||
- ~~10–13 cm steps at the crossings, ~10 % ramp over 1.5 m~~ — **fixed in `0.1.1`**:
|
||
the ramp run is now derived from a target grade (`--max-ramp-grade`, default 8 %),
|
||
giving 1.63 m instead of the fixed 1.5 m (8.7 %). Measured at 0.25 m sampling the
|
||
crossing now steps 3.4 cm (~1.4 % of the route) at the kerb line.
|
||
|
||
**Remaining finding (not a crossing, not the outer edge):** the south route still
|
||
measures a **13.4 cm step at s≈198 m** (11.6 cm at 0.25 m sampling) and the north
|
||
route 8.0 cm at s≈251 m. Neither is at a crossing and neither is the outer lip, so
|
||
this is a local discontinuity in the sidewalk strip — most likely the DEM sampling
|
||
or a centreline vertex near the block ends. Tracked under the `0.1.1` "audit any
|
||
collision gaps" item rather than left undocumented.
|
||
|
||
This is a pre-check, not the `0.1.0` release check: the release check is traversal in the engine.
|
||
|
||
### Collision is not authored yet
|
||
|
||
The site is geometry only. On Unreal import the proposal is complex-as-simple collision for terrain and street (they are the walkable surfaces and must not be approximated into ramps over kerbs), and simple convex hulls per building. That decision belongs to the engine step, not to this file.
|
||
|
||
## Scale check (blockout, 2026-11-06)
|
||
|
||
Blender works in metres, and the imported meshes match the OSM geometry, so the blockout is 1:1 before any Unreal export:
|
||
|
||
| Building | Blender dimensions | OSM way outline | Height source |
|
||
| --- | --- | --- | --- |
|
||
| El Capitan Entertainment Centre | 25.72 × 54.47 × 14.50 m | 25.75 × 54.88 m | `height` tag 14.5 |
|
||
| El Capitan Theatre | 38.66 × 54.46 × 20.96 m | 38.59 × 54.87 m | `building:levels=6` × 3.2 m, plus roof |
|
||
| Madame Tussaud's | 42.48 × 56.77 × 15.90 m | 42.0 m frontage | `height` tag 15.9 |
|
||
| TCL Chinese Theatre | 43.78 × 75.90 × 18.10 m | 44.0 m frontage | `height` tag 18.1 |
|
||
|
||
Widths agree to a few centimetres; depths differ by up to 0.4 m because Blosm assembles **multipolygon relations**, not the raw way I measured. Placement after the frame correction agrees with the UTM control points to 0.1–0.5 m per building — the residual is relation assembly and Blosm's edge straightening, not projection.
|
||
|
||
Buildings **without** a `height` tag get levels × 3.2 m, which is a placeholder, not evidence. Every such height is a modelling decision to be replaced from the reference photography.
|
||
|
||
## Relation completeness
|
||
|
||
The extract is complete for the block but not for every relation inside its bbox: Blosm's optional member fetch pulled six ways from Overpass, all belonging to one 213 × 152 m multipart complex about 100 m north of the boulevard — outside the `0.1.0` bounds and out of scope. That fetch is therefore **off by default** (`--load-missing` enables it), so the committed blockout is reproducible offline from the committed extract alone. If background massing later needs that complex, refetch a wider extract rather than reintroducing a network dependency.
|
||
|
||
## What this blockout is not
|
||
|
||
- Not cleaned, not subdivided into façade modules, not UV-mapped, not detailed.
|
||
- Materials are placeholders from Blosm's simple mode. Realistic mode needs the paid material pack and was not run.
|
||
- Terrain, kerbs, and crossing ramps are not in it: those come from the DEM cross-sections in `Geo/verification/2026-11-06-cross-sections.md`.
|
||
|
||
## Scale test and the Unreal frame (2026-11-07)
|
||
|
||
`Art/blender/scaletest/scale-test-2026-11-07.blend` — three 1 m cubes at origin, +10 m east, +10 m north, plus one red test material. Regenerate with `Tools/scale_test_export.py`; import with `Tools/ue_scale_test_import.py`. Both are the named-preset templates for production assets.
|
||
|
||
Export preset **`ue_metric_v1`** (Blender FBX): `apply_unit_scale`, `apply_scale_options='FBX_SCALE_NONE'`, `axis_forward='-Y'`, `axis_up='Z'`, `use_space_transform`, no bake-space-transform. Import preset **`ue_metric_v1`** (UE `FbxImportUI`): static mesh, import materials, uniform scale 1.0, no unit conversion, no force-front-X.
|
||
|
||
Measured result in Unreal centimetres: 1 m cube → exactly 100.00 cm; origin preserved. Axis mapping **east → +X, north → −Y, up → +Z**. The north mirror is inherent to the right-handed Blender → left-handed UE conversion; the FBX importer fixes triangle winding, so geometry is not visually mirrored. Compass conversions in game code must use north = −Y.
|
||
|
||
## Add-on compatibility (re-checked 2026-11-07)
|
||
|
||
`Tools/addon_compat_probe.py` loads both pinned add-ons headless and runs an MPFB smoke test. Result on Blender 5.2.0 LTS: Blosm 2.7.28 imports; MPFB 2.0.18 enables and `mpfb.create_human` generates a default human (19 158 verts, UVs, no materials, no armature — skeleton and baked materials are separate steps).
|
||
|
||
**Required invocation change:** every direct-binary headless run must now set `XDG_CONFIG_HOME="$HOME/.var/app/org.blender.Blender/config"`. Without it Blender resolves the extensions dir to `~/.config/blender/5.2/extensions`, where nothing is installed, and `bl_ext.blender_org.mpfb` is not discovered. Blosm is unaffected (it lives in `scripts/addons`, found via `BLENDER_USER_SCRIPTS`), but set the variable in all runs for consistency.
|