Close and archive the 0.9.9 milestone, record that the upstream clips stay unused, and harden the fallback test
Full build / Import + headless tests (push) Successful in 44s
Full build / Full desktop build + optional release (push) Skipped

This commit is contained in:
zwitschi committed 2026-11-06 18:39:53 +01:00
1 parent fcbeee0db2
commit c70a523f0f
6 files changed
+126 -108

No files matched your search

+2 -101
View File
@@ -755,107 +755,6 @@ reference-image licence and privacy gates above rather than replacing them.
passes visual, performance and provenance review; or the approach is rejected with
reproducible findings and removed from the release path.
## Milestone 0.9.9 — Quaternius NPC base swap (patch)
Goal: make one Quaternius-derived NPC render and animate correctly in Godot and ship it as the
pilot base, with the procedural library still selectable as the fallback. This is the first
versioned character milestone; it contains the rig correction that has been blocking the
ADR-0018 rollout.
**Why this is a patch:** it changes character presentation and animation quality but adds no new
player-facing system. The 0.10.0 minor is reserved for the release gates (see below), so a
blocked rig can no longer block the whole release.
### Rig and export correction
- [x] Reproduce and record the failure: the `armature_apply` + `export_apply=True` bake wrote
wrong inverse bind matrices (Godot rendered A-pose while the rest was arm-down). Recorded
in `MEMORY.md`; `bake_armdown_clean.py` was the failing recipe.
- [x] Fix the arm-down bake so the exported skin matches the rest. `tmp/npc-research/bake_armdown_v2.py`
(pose-rotate → apply modifier → reset pose → edit-mode rotate arms → re-add modifier →
export `export_apply=False`) now yields a correct arm-down base: Blender deformed x ±0.221
and the rest bone tail points down. Still local (`tmp/`), not shipped.
- [x] Re-derive the pose composition for a non-180° rest. Superseded by the rig-agnostic
`_swing_bone()` below: the rest-relative `set_bone_pose_rotation` form was never exact,
because `get_bone_rest()` is parent-relative and already carries the importer's axis
conversion. Kept in `MEMORY.md` as a rejected approach.
- [x] Fix the skinning/rest bake end to end (commit `cd285b3`):
(1) the canonical base is **join-only** (`tmp/npc-research/build_base_minimal.py`: no
`remove_doubles` weld, no scale/ground transform, keep the Armature modifiers) — the weld
and the transform corrupted the Quaternius weights;
(2) the arm-down bake (`tmp/npc-research/bake_armdown_v5.py` — pose, read pose matrices,
apply modifier, **reset pose to identity**, set rest matrices, re-add modifier) bakes the
rest correctly (DEFORMED x −0.228/0.228, Godot bind pose arm-down);
(3) `NpcAvatar._swing_bone()` now writes the **global** bone pose from
`get_bone_global_rest()`, so one formula drives both the 62-joint Quaternius rig and the
13-core fallback (measured: posed bone axis matches the proxy pivot at dot 1.000 on the
Quaternius, and the procedural rigs are unchanged);
(4) `RIG_BONES` + `NpcAvatar.bone_name()` hold the only side mapping (the Quaternius labels
`L`/`R` opposite the project), and the hand proxy is `global_wrist − global_elbow`.
Verified in Godot: idle/sit/walk captures on npc_casual plus the unchanged procedural rigs.
- [x] Add regression tests: `test_shipped_rig_resolves_the_animation_joints` covers the joint map,
the baked arm-down rest, the down-pointing arm axis and the proxy side mapping; the Blender
audit/`inspect` and `npc_proportions` now understand both rigs. Godot 278/278, Python
167/167.
- [x] Give the Quaternius base the five tint slots: `build_base_minimal.py` renames the upstream
materials to `skin`/`cloth`/`pants`/`hair`/`accessory` and keeps `Eye`/`Eyebrows` as
fixed-colour detail. The source UV map is degenerate (every loop at 0,0), so the build now
Smart-UV-unwraps and repacks the layout — texel density went from an unmeasurable 0 to
73–74 px/m on the 256² maps and the 256² AO bake works again.
- [ ] Verify Idle and Walk on the 62-joint rig: loop seam, foot contact, root motion and frame
rate. Record which of the 24 clips are in scope and which stay unused.
- [ ] Decide and record how poses the clips do not cover (seated, raise-hand, head turn) are
driven at runtime.
- [ ] Keep the fallback tested: `npc_base`, the MakeHuman head and `_build_body()` remain
selectable; no MPFB work is reopened and no Stage-1 proportion warp returns. (The procedural
library is still the majority of `CHARACTER_POOLS` and captures clean, but the fallback path
itself has no dedicated test yet.)
- [ ] Re-fit the remaining gear against the Quaternius torso: the `backpack` strap geometry was
authored for the old body width and now hangs in front of the chest. The camera was fixed
with a wrist strap (a neck strap floats when the item is hand-attached).
### Silhouette and face gate (owner)
- [x] Re-run the silhouette gate at gameplay distance and in portrait against the current
`npc_casual`, front / three-quarter / profile. ADR-0018 removed the proportion warp, so
source proportions are accepted by definition (head 13.4 % of height, measured by
`npc_proportions`).
- [x] Owner visual signoff obtained (2026-11-06) on the roster, the faces, the head gear and the
hand/back gear. The review page and its sheets were retired after acceptance; the measurements
live on in `docs/3d-model-review.md` and `docs/blender-assets.md`.
- [x] Face-fidelity comparison was made and the full swap chosen; the comparison sheets were
retired with the review pages, and the decision is recorded in the follow-up section of
[`docs/adr/0018-quaternius-stage2-runtime-rig.md`](docs/adr/0018-quaternius-stage2-runtime-rig.md).
- [x] **Owner decision:** option (a) full swap (2026-11-05). Applied: all twelve characters are
baked from the three Quaternius sources inside 24,000 tris / 24,000 glTF vertices
(`a6ccd86`), and the gate was re-run.
- [x] Record the decision and its consequence in `MEMORY.md`,
`docs/npc-model-sourcing.md#shipped-roster-099-owner-chose-the-full-swap` and the
follow-up decision section of
[`docs/adr/0018-quaternius-stage2-runtime-rig.md`](docs/adr/0018-quaternius-stage2-runtime-rig.md).
- [x] Owner visual signoff on the shipped roster (2026-11-06): accepted.
### Pilot rollout
- [x] Map the five tint slots onto the Quaternius materials and unwrap the degenerate source
UV map; bake the 256² AO and check texel density (73–74 px/m).
- [ ] Bake the per-slot albedo/normal/ORM maps and a per-slot atlas (the five slots currently
share one whole-body UV set).
- [-] Re-fit gear attach points against the Quaternius skeleton and test cap, helmet, backpack,
shoulder bag, lanyard, clipboard and firefighter tank. (Camera done: wrist strap instead of
the floating neck strap. Backpack straps still cut across the Quaternius chest.)
- [ ] Wire the approved base into one role (or the crowd roles if option b is chosen) with the
procedural model as an instant fallback; no runtime download or optional dependency.
- [ ] Run `blender_assets.py inspect`/`audit`/`fit`, `npc_proportions.py`, the 24-NPC budget smoke
and the capture gate; record the measurements before/after.
- [ ] Release `0.9.9`: update the version source in `project.godot` (`config/version`), write the
`CHANGELOG.md` entry, run `tools/build_releases.sh`, verify checksums, commit, tag and push.
**Exit:** one committed Quaternius GLB renders arm-down with correct skinning, plays Idle and
Walk on the 62-joint rig, poses correctly under the new composition, passes the owner face and
silhouette gate, fits the 18 gear pieces, stays inside budget, and ships as `0.9.9` with the
procedural library still available as a fallback.
## Milestone 0.9.10 — NPC roster rollout (patch)
Goal: extend the approved base to the full 12-role roster in asset-family batches, without
@@ -869,6 +768,8 @@ regressing gear fit, budget or readability.
upstream hivis vest and hard hat. All twelve built, AO-baked and committed (`a6ccd86`).
- [ ] Add the modular part library (hair styles, outfits) so the roster regains the silhouette
variety the twelve procedural meshes had; three shared meshes is the current ceiling.
- [ ] Bake per-slot albedo/normal/ORM maps and a per-slot atlas; the five slots currently share one
whole-body UV set, which caps how much the cloth/pants tints can differ.
### Owner review findings (2026-11-06)