Verifying the GLBs in three.js (not just Blender) showed four assets reporting inflated bounds: tramp_01 came back 3.29 x 1.27 m against a true 2.96 x 0.78. Box3.setFromObject expands each mesh's LOCAL box by the world matrix, so a node carrying a rotation over-reports — the same trap Blender's obj.bound_box sets, and what three uses for frustum culling. Joined nodes inherited parts[0]'s rotation, which for an arc is half a segment step off-axis. Applying rotation at join time makes every local box axis-aligned, so the default Box3 path is now correct for consumers and culling is tight. World geometry is unchanged; the exported dims are identical. Adds tools/assetcheck/, the three.js harness that caught this. It's the only check that can: a Blender round-trip exports Z-up->Y-up and imports Y-up->Z-up, so a broken export_yup flips back and passes green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
51 lines
2.3 KiB
Markdown
51 lines
2.3 KiB
Markdown
# assets_in_three.html — verify the GLBs in the real consumer
|
||
|
||
`build_yard_assets.py` already re-imports every GLB into Blender and asserts
|
||
dims, tri budget, and node names. That is necessary but **structurally cannot
|
||
catch an axis error**: Blender exports Z-up→Y-up and imports Y-up→Z-up, so a
|
||
broken `export_yup` flips back on the way in and round-trips green. Only
|
||
something that reads glTF natively can prove the file is right.
|
||
|
||
This page is that check. It loads each GLB with three.js r175's `GLTFLoader` and
|
||
asserts:
|
||
|
||
- **Y-up**: a Blender asset measuring `(dx, dy, dz)` must arrive as `(dx, dz, dy)`.
|
||
- **node survival**: `branch_anchor_*`, `fascia_anchor_*`, `plants_*` etc. still
|
||
exist after the export — glTF has no "empty", anchors arrive as bare
|
||
`Object3D`, and exporters have been known to prune childless nodes.
|
||
- **anchors are usable**: `branch_anchor_01` resolves to a sane world position
|
||
with height on +Y.
|
||
|
||
Expectations are read from `tools/blender/asset_report.json`, so this stays in
|
||
sync with the factory automatically.
|
||
|
||
## Why it uses the default (non-precise) Box3
|
||
|
||
`THREE.Box3.setFromObject(obj)` expands each mesh's **local** bounding box by the
|
||
world matrix, so a node carrying a rotation reports an inflated box. That is the
|
||
same trap Blender's `obj.bound_box` sets, and it is what three uses for frustum
|
||
culling. `join_group()` therefore bakes rotation into the vertices so the local
|
||
box is axis-aligned and tight. Passing `precise: true` here would hide exactly
|
||
the regression this page exists to catch — so don't.
|
||
|
||
Before that fix, three reported `tramp_01` as 3.29 × 1.27 m against a true
|
||
2.96 × 0.78 m.
|
||
|
||
## Running it
|
||
|
||
Needs three.js on `/world/vendor/` and the models on `/models/`. Once Lane A's
|
||
`server.py` lands, serve `web/` and this can move next to `selftest.html`
|
||
(Lane A: happy to fold it in — see THREADS).
|
||
|
||
Until then, the standalone recipe:
|
||
|
||
```sh
|
||
D=$(mktemp -d) && mkdir -p "$D/world"
|
||
ln -s ~/Documents/90sDJsim/web/world/vendor "$D/world/vendor"
|
||
ln -s "$PWD/web/world/models" "$D/models"
|
||
ln -s "$PWD/tools/blender/asset_report.json" "$D/asset_report.json"
|
||
cp tools/assetcheck/assets_in_three.html "$D/index.html"
|
||
python3 -m http.server 8805 --directory "$D"
|
||
# open http://127.0.0.1:8805 — look for "SUMMARY: ALL PASS IN THREE.JS"
|
||
```
|