Extend the v0.6.0 plan with the Blender asset library

Document the larger asset set produced by the running Blender generator
(tools/blender_assets.py): 8 NPC character variants, 18 gear pieces, and 22
street/venue props with a manifest, editable sources, and preview sheets.

- TODO gains Phase 3.5 with the audit/budget reconciliation (npc_casual is
  currently 7,756 tris / 5,616 verts, above the 6,000/4,000 contract), character
  selection by role, gear attach points, prop replacement/placement, emissive
  wiring, budgets, and screenshot gates
- PLAN's Visual Quality Direction describes the library, runtime selection, and
  offline fallbacks
- docs/plan-graphics-v0.6.md adds the library contract/output table and
  integration steps, and points Phase 4 at the Blender props
- MEMORY records the manifest-as-source-of-truth rule and the generator caveat

Generated library files stay untracked until the running build finishes and
passes the audit; the generator itself is committed so the plan is reproducible.
This commit is contained in:
zwitschi committed 2026-11-01 13:39:03 +01:00
1 parent a231f7588a
commit 7efb5024ec
5 files changed
+1766 -20

No files matched your search

+87 -13
View File
@@ -164,20 +164,89 @@ Outputs land under `assets/textures/ai/game_ready/` (or a new
6. Re-measure `smoke_npc_budget.gd`; adjust `LOD_TIERS` if the skinned rig is
heavier up close. The impostor path is unchanged.
### Phase 3.5 — Blender asset library (characters, gear, props)
The library generator is `tools/blender_assets.py` (flatpak Blender, headless).
It stages outputs for integration; nothing is wired into the game until the
audit and manifest are clean. While the generator is running, do not edit it.
**Outputs and contract**
| Kind | Path | Notes |
| --- | --- | --- |
| Characters | `assets/models/blender/npc/<name>.glb` | 8 variants: `npc_casual`, `npc_jacket`, `npc_coat`, `npc_vest`, `npc_dress`, `npc_hoodie`, `npc_firefighter`, `npc_guard` |
| Gear | `assets/models/blender/npc_gear/<name>.glb` | 18 pieces; authored in attach-point space (`head`, `hand`, `back`, `chest`) |
| Props | `assets/models/blender/props/<name>.glb` | 22 pieces; the first nine replace current generated/primitive street furniture, the rest are new venue dressing |
| Manifest | `assets/models/blender/manifest.json` | path, category, triangles, vertices, bounds, materials, roles, tint slots, attach points |
| Sources | `assets/models/blender_src/<name>.blend` | committed, editable source |
| Previews | `docs/blender_previews/*.png` + `sheet_<category>.png` | `render` / `sheet` for visual review |
All characters reuse the `npc_base` contract: mesh node `npc_base`, bones
`Head/HipL/R/KneeL/R/ShoulderL/R/ElbowL/R/HandL/R` (+ Hips/Spine/Neck),
material slots `skin/cloth/pants/accessory/hair`, front toward Blender `-Y`
(Godot `+Z`), feet at `y ~= 0`. Gear origins are the attach points (head at
`Rig/Head`, hand at the hand proxy, back at the spine, chest at the sternum).
Props are grounded except `wall_lantern` and `marquee`; both may be emissive.
**Integration steps**
1. **Audit the finished build.** `python3 tools/blender_assets.py audit` and
`sheet`; fix assets or reconcile the budgets. The first `npc_casual` result
is 7,756 tris / 5,616 verts, above the current 6,000 / 4,000 character
contract — either simplify the mesh or explicitly raise and document the
character budget before wiring variants in.
2. **Commit the library and sources.** Add `assets/models/blender/**`,
`assets/models/blender_src/**`, the generator, manifest, previews, and
`docs/blender-assets.md`; generated folders that CI can rebuild offline may
stay ignored. `blender_assets.py audit` must work without Blender.
3. **Select characters by role.** Extend `NpcAvatar` to pick a variant from the
manifest using the profile's role and `outfit_for`/`layer_for` (casual,
jacket, coat, vest, dress, hoodie, firefighter, guard). Fall back to
`npc_base.glb`, then to the procedural rig, and record the chosen path.
4. **Tint and anchor.** Apply `outfit_for` to every variant's five slots via
`SurfaceMaterials.npc_slot()`; keep `Rig/Head` for the focus circle, name tag,
reaction tag, and accessories. Keep the walk/idle/escalation bone-driving
wrapper.
5. **Replace procedural gear.** Use the `npc_gear` catalogue for caps, hoods,
helmets, backpacks, lanyards, hand items (phone, cup, clipboard, umbrella,
camera, sign, flashlight, wand, radio) and the SCBA tank; attach at the
documented points and fall back to the current primitives when an asset is
missing.
6. **Replace and extend props.** Load the replacement set through
`WorldBuilder` (`bollard`, `bench`, `trash_bin`, `planter_box`,
`newspaper_box`, `fire_hydrant`, `street_lamp`, `street_tree`,
`traffic_cone`), then place the new dressing (`palm_tree`, `round_planter`,
`a_frame_sign`, `wall_lantern`, `crowd_barrier`, `stanchion`, `handrail`,
`security_podium`, `double_door`, `marquee`, `sedan`) using the existing
placement table/collider/avoidance contract. No prop may enter the
door/steps/guest lane.
7. **Wire emissives to the phase.** Street-lamp bulbs, wall lanterns, the door
lock LED, marquee bulbs/sign face, and sedan headlights should follow the
existing day/night lighting rather than staying always on.
8. **Measure and gate.** Re-run `smoke_npc_budget.gd` with the new characters
before raising `MAX_LIVE_NPCS`; add a prop triangle/draw budget check. Then
recapture `docs/screenshots/` and run `screen_designs.py compare` + `judge`
plus a close-up target shot for character readability.
9. **Fallbacks stay offline.** A fresh checkout with no Blender and no network
must boot on the committed library (or `npc_base.glb`/procedural rig when an
asset is absent); CI still runs the Godot import and headless suite.
### Phase 4 — Environment and lighting lift (after NPCs land)
1. **Baked AO on props:** export the existing prop set through Blender (or bake
AO in `npc_pipeline`-style tooling) so contact shadows read without SSAO.
This replaces the pure box/cylinder builder with Blender-authored props
behind the same `assets/models/generated/<prop>.glb` contract (ADR-0012's
follow-up).
1. **Baked AO on props:** use the Phase 3.5 Blender prop replacements
(`street_lamp`, `street_tree`, `bench`, …) and bake AO into their
albedo/ORM maps so contact shadows read without SSAO. Keep the same
`WorldBuilder` load/fallback contract (ADR-0012's follow-up).
2. **Higher-resolution environment textures:** regenerate brick/concrete/asphalt
through `asset_pipeline.py` with normal maps, keeping the current UV scales.
through `asset_pipeline.py` with normal maps, keeping the current UV scales;
use the same sRGB/albedo + packed ORM discipline as the library assets.
3. **Evaluate a desktop-only Forward+ preset** (SSAO/SSIL/volumetrics) while the
Web export preset keeps `thread_support=false` and GL Compatibility. Decide
explicitly in an ADR addendum; do not silently change the renderer.
4. Regenerate `docs/screenshots/` with `capture_screenshots.gd`, then run
`screen_designs.py compare` and `judge` as the regression gate.
`screen_designs.py compare` and `judge` as the regression gate, plus
`blender_assets.py sheet` for the character/gear/prop library.
### Phase 5 — Verification and release
@@ -204,15 +273,20 @@ Outputs land under `assets/textures/ai/game_ready/` (or a new
## Acceptance criteria (definition of done)
1. NPCs are Blender-authored skinned meshes with baked maps; they read as people
at conversation distance and survive a cinematic close-up.
1. NPCs and street furniture are Blender-authored meshes with baked maps; the
character variants, gear, and props read as people/objects at conversation
distance and survive a cinematic close-up.
2. `Rig/Head`, the focus cone, nametag, theater poses, crowd reactions, and LOD
all still work; all existing NPC tests pass unchanged or are updated with
clear reasons.
3. The game boots and plays from a fresh checkout with **no** Blender and no
network (committed assets + procedural fallback).
4. `npc_pipeline.py build` is deterministic and `audit` enforces the contract.
5. 208 headless + 56 Python tests stay green (Python audit tests skip when
Blender is absent); NPC-budget and movement smokes pass; screenshot
`compare`/`judge` show no regressions.
6. Version bumped to v0.6.0, docs and ADR-0013 updated, release published.
5. 212 headless + 60 Python tests stay green (Blender-dependent Python tests
skip with a reason when Blender is absent); `npc_pipeline.py audit` and
`blender_assets.py audit` pass; NPC-budget and movement smokes pass;
screenshot `compare`/`judge` and the library contact sheets show no
regressions.
6. The library is committed with its generator/manifest/previews, runtime
selection and fallbacks are covered by tests, version bumped to v0.6.0,
docs and ADR-0013 updated, release published.