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

+102
View File
@@ -2192,3 +2192,105 @@ variants, the four crowd-variety characters and the per-role pools — as a **pa
**Exit:** met — 0.9.7 ships the 12-character library (face realism + crowd variety) with the pose
harness fixed; the runtime contract is unchanged. The Quaternius NPC base and the map rebuild are
not in this patch (they target 0.10.0).
## 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.
**Completed 2026-11-06.** Shipped as `v0.9.9` (tagged, local release build with checksums)
and accepted by the owner after the follow-up fixes. Durable evidence: `docs/3d-model-review.md`,
`docs/blender-assets.md`, `docs/adr/0018-quaternius-stage2-runtime-rig.md`.
### 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.
- [x] Idle and Walk verified on the 62-joint rig through the pose code, not the clips: the 24
upstream clips stay authoring reference only, because `_animate()` + `_sync_skeleton()`
already drive sitting, hand-raising and head turns, and playing clips would replace that
state machine rather than supplement it. Recorded in ADR-0018 and `MEMORY.md`.
- [x] Poses the clips do not cover are driven by the same proxy pivots (`_legs`, `_knees`,
`_arms`, `_elbows`, `_head`), which is why no clip retarget was needed.
- [x] Fallback stays tested: `_build_body()` still builds the 13-core rig, and
`test_forced_fallback_still_builds_the_procedural_rig` now asserts the hip swings and a hand
pivot exists on that path. No MPFB or Stage-1 proportion work reopened.
- [x] Backpack straps re-fitted for the Quaternius torso (`fb3e75a`) and the back attach raised to
shoulder-blade height; the camera kept its wrist strap.
### 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).
- [x] Re-fit every gear attach point against the Quaternius skeleton and test each piece on the
character (the 0.9.10 *Prop and gear fit pass* below carries the measurements).
- [x] Wired the approved base into all twelve roles, with the procedural library as the instant
fallback; no runtime download or optional dependency.
- [x] Ran `inspect` (clean), `audit` (12/12), `fit` (OK), `npc_proportions` (measured), the 24-NPC
budget smoke (175,264 tris, 0.87 ms) and the capture gates before/after the fixes.
- [x] Released `0.9.9`: `config/version` 0.9.9, `CHANGELOG.md` entry, local build with checksums,
commit, tag `v0.9.9` and push. Owner accepted the roster on 2026-11-06.
**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.