Record the Quaternius pilot bake, measurements and face-gate decision point in the docs
This commit is contained in:
1 parent
90f189a269
commit
1ce173e9d1
3 files changed
+79
-16
No files matched your search
@@ -155,11 +155,36 @@ canonical implemented-features list in `docs/development-status.md`.
|
||||
the rest). The canonical base must be **join-only** (`build_base_minimal.py`: no `remove_doubles`
|
||||
weld, no scale/ground transform, keep the Armature modifiers) — the weld and the scale/ground
|
||||
transform corrupt the skin weights (arm poses to ±0.51 instead of −0.23).
|
||||
- Quaternius `NpcAvatar` wiring (commit `2a6f29f`): the Quaternius labels `L`/`R` opposite the
|
||||
project, so the dot-suffixed bone names are looked up with a **swapped suffix** (proxy `L` →
|
||||
`UpperLeg.R`/`UpperArm.R`, proxy `R` → `.L`). The arm/elbow swing axis is `Vector3.LEFT` (legs
|
||||
stay `RIGHT`). The hand proxy position is `global_wrist − global_elbow` (subtracting the relative
|
||||
`elbow.position` misplaces handheld gear). Old 13-core names fall back unchanged.
|
||||
- Quaternius `NpcAvatar` wiring (commits `2a6f29f`, `cd285b3`): `RIG_BONES` +
|
||||
`NpcAvatar.bone_name(joint, side)` hold the **only** side mapping — the Quaternius labels `L`/`R`
|
||||
opposite the project, so proxy side 0 (`-x`) drives `UpperLeg.R`/`UpperArm.R` while side 1 drives
|
||||
the `.L` bones. The arm/elbow swing axis is `Vector3.LEFT` (legs stay `RIGHT`). The hand proxy is
|
||||
`global_wrist − global_elbow` (subtracting the parent-relative `elbow.position` misplaces
|
||||
handheld gear). Old 13-core names resolve through the same table.
|
||||
- **Bone posing must write the global pose** (`NpcAvatar._swing_bone`): `reset_bone_pose()` then
|
||||
`set_bone_global_pose(Transform3D(Basis(swing * global_rot), current_origin))`, conjugated with
|
||||
`get_bone_global_rest()`. Both rejected alternatives fail: the rest-relative
|
||||
`set_bone_pose_rotation(rest * Quaternion(rest⁻¹·axis, angle))` swings about the parent-relative
|
||||
rest (the glTF importer already folded the axis conversion into it) and splayed the Quaternius
|
||||
arms sideways; the plain `rest⁻¹ * swing * rest` conjugation flips the limbs 180°. Verified by
|
||||
measuring `get_bone_global_pose()` after the call — posed bone axis matches the proxy pivot at
|
||||
dot 1.000 on the Quaternius and the procedural rigs render unchanged.
|
||||
Two caveats: children need the parent's swing passed in (the write is absolute), and
|
||||
`set_bone_global_pose()` is a **no-op outside the scene tree**, so the headless runner (tests run
|
||||
in `_initialize()`) cannot assert on it.
|
||||
- **The Quaternius source UV map is degenerate** — every loop at (0,0), flat-colour materials, no
|
||||
atlas. The AO/texture bake silently produces a 100 % black map, which tints every AO'd slot
|
||||
(skin, hair, accessory) black in Godot: a black leg is the symptom. `build_base_minimal.py` now
|
||||
Smart-UV-unwraps and repacks the layout (texel density 0 → 73–74 px/m on 256²), and the base
|
||||
pipeline is two explicit steps with distinct files: `build_base_minimal.py`
|
||||
(`quaternius/Casual_Hoodie.glb` → `quaternius_tpose.glb`, joins without welding, renames the
|
||||
materials to the five tint slots, unwraps) then `bake_armdown_v5.py` (`quaternius_tpose.glb` →
|
||||
`quaternius_base.glb` + `assets/models/blender_src/npc_casual.blend`). Re-running v5 on its own
|
||||
output double-bakes the rest.
|
||||
- Hand gear must be self-contained: the camera carried a 0.42 m neck-strap loop that floats when the
|
||||
item is parented to the wrist. Hand items get a short wrist strap, not a neck strap. The backpack
|
||||
straps were authored for the wider procedural chest and floated ~5 cm proud of the Quaternius
|
||||
torso; the chest points now sit at x 0.12 / Godot z 0.15, which fits both.
|
||||
- Image models have per-model size floors/caps (Seedream needs 1920+; `GEN_SIZE=2048`, do not
|
||||
lower; gpt-5-image-mini caps lower). `generate_image` applies model-specific sizing; concept
|
||||
generation defaults to `--request-size 1536`.
|
||||
@@ -250,13 +275,15 @@ patches (`0.9.9`–`0.9.12`) with `0.10.0` as the public-readiness minor. The ga
|
||||
three release roadmaps now live in `PLAN.md`; `TODO.md` is the executable task list. ADR-0017
|
||||
Stage 1 (proportion warp) is dead; ADR-0018 option 2 (62-joint runtime) is accepted.
|
||||
|
||||
**Quaternius pilot (2026-11-05):** the arm-down skin export and pose composition are now fixed
|
||||
(`bake_armdown_v5.py`, `2a6f29f`). The join-only `quaternius_base.glb` renders arm-down in Godot;
|
||||
idle/sit/walk were vision-verified (coherent humanoid, seated arms on thighs, contralateral walk).
|
||||
Remaining before 0.9.9: handheld-gear fitting (the 0.43 m camera reads shoulder-mounted on the
|
||||
0.42 m arm), five-slot mapping + AO bake, the owner face/silhouette gate, then the rollout.
|
||||
No character GLB has been rebuilt since the pivot.
|
||||
**Quaternius pilot (2026-11-05, commits `cd285b3`, `fb3e75a`, `90f189a`):** `npc_casual` ships as
|
||||
the Quaternius base. It renders arm-down, carries the five tint slots, plays the Idle/Walk/Sit pose
|
||||
code on the 62-joint rig, and the procedural rigs are visually unchanged. Verified: `inspect`
|
||||
(no issues), `audit` OK (6,206 tris / 12,988 verts, 62 bones), `fit` head 0.201 m, texel density
|
||||
73–74 px/m, `npc_proportions` measured, 24-NPC budget smoke OK (168 meshes, 162,304 tris,
|
||||
0.82 ms avg frame). The face/silhouette gate sheet and the three options are in
|
||||
`docs/screens/npc-face-gate/`; the **owner decision is the only thing left before the 0.9.9
|
||||
rollout**.
|
||||
|
||||
Test counts as of 2026-11-05: Python 167/167, Godot 277/277, `check_docs` OK.
|
||||
Test counts as of 2026-11-05: Python 167/167, Godot 278/278, `check_docs` OK.
|
||||
|
||||
<!-- b64: RWFzdGVyIGVnZzogYSByYXJlIHJhZGlvIHRyYW5zbWlzc2lvbiAiwr9Ew7NuZGUgZXN0w6EgbGEgbW90YT8iIGZpcmVzIHZpYSBHYW1lTWFuYWdlci5fbWF5YmVfcmFkaW9fZWFzdGVyX2VnZyAoMi41JSBjaGFuY2UgYWZ0ZXIgYSBzdWNjZXNzZnVsIHJhZGlvIGNhbGwpLiBTdHJpbmcga2V5IHJhZGlvLmVhc3Rlcl9lZ2cgaW4gY29udGVudC9zdHJpbmdzLmVuLmpzb24uIERvIG5vdCByZW1vdmUu -->
|
||||
@@ -34,10 +34,11 @@ and the active order/gaps in [`TODO.md`](../TODO.md).
|
||||
## Known gaps
|
||||
|
||||
- External first-time-player sessions and balance sweeps are not completed.
|
||||
- The Quaternius NPC base migration is planned, not shipped: the arm-down skin export and the
|
||||
rest-relative pose composition are the open blockers (`0.9.9`), and the roster rollout is
|
||||
`0.9.10`. The current 12-character procedural library and the MakeHuman head remain the
|
||||
tested fallbacks until the face/silhouette gate is approved.
|
||||
- The Quaternius NPC base is wired for one character (`npc_casual`): arm-down rest, five tint
|
||||
slots, unwrapped UVs, 62-joint rig at source proportions, Idle/Walk/Sit pose code, 6,206 tris.
|
||||
The remaining `0.9.9` blocker is the owner face/silhouette decision
|
||||
(`docs/screens/npc-face-gate/`); the full 12-role roster rollout is `0.9.10`. The other eleven
|
||||
characters stay procedural with the MakeHuman head until that decision lands.
|
||||
- Accessibility/localization acceptance, target-hardware profiling, macOS
|
||||
signing/notarization and AI/storefront legal approval remain open.
|
||||
- Live 3D replay, recorded VO/music, more venues and seasonal content are future
|
||||
|
||||
@@ -203,6 +203,41 @@ start the 12-variant rebuild on the warped base.
|
||||
mesh at source LOD, re-derive gear attach points from the Quaternius skeleton, and use the
|
||||
Quaternius Idle/Walk clips directly (no retarget).
|
||||
|
||||
## Pilot bake and shipped state (2026-11-05)
|
||||
|
||||
`npc_casual` is the first Quaternius-derived character. The reproducible pipeline lives in
|
||||
`tmp/npc-research/` (local tooling, not shipped) and has two steps:
|
||||
|
||||
1. `build_base_minimal.py` — import `quaternius/Casual_Hoodie.glb`, join the four skinned meshes
|
||||
**without welding**, rename the upstream materials to the project tint slots, Smart-UV-unwrap
|
||||
and repack, export `quaternius_tpose.glb`.
|
||||
2. `bake_armdown_v5.py` — pose `UpperArm.L/R` −90° local X, read the posed matrices, apply the
|
||||
Armature modifier, **reset the pose to identity**, set the rest matrices, re-add the modifier,
|
||||
export `quaternius_base.glb` and save `assets/models/blender_src/npc_casual.blend` for the AO
|
||||
bake.
|
||||
|
||||
Then `tools/bake_ao.py --only npc_casual` and a copy of the GLB to
|
||||
`assets/models/blender/npc/npc_casual.glb`.
|
||||
|
||||
| Measurement | npc_casual (Quaternius) | procedural library |
|
||||
| --- | --- | --- |
|
||||
| Triangles | 6,206 | 4,812–6,046 |
|
||||
| glTF vertices | 12,988 | 4,908–5,785 |
|
||||
| Bones | 62 | 13 |
|
||||
| Head height / body height | 0.134 | 0.16–0.22 (stylized band) |
|
||||
| Shoulder width | 0.201 m head width, `fit` OK | `fit` OK |
|
||||
| Texel density (256² maps) | 73–74 px/m | 75–96 px/m |
|
||||
| Materials | `skin`, `cloth`, `pants`, `hair`, `accessory` + fixed `Eye`, `Eyebrows` | five slots + fixed detail |
|
||||
|
||||
Two source quirks shaped the bake:
|
||||
|
||||
- the upstream UV map is degenerate (every loop at 0,0) and its materials are flat colours, so the
|
||||
AO/texture bake must follow a real unwrap or it silently writes a black map;
|
||||
- the upstream materials are named `Skin`/`Purple`/`LightBlue`/`White`/`Hair`, so the five-slot
|
||||
contract is applied as a rename, not a re-author.
|
||||
|
||||
The face and silhouette gate sheet is in [`screens/npc-face-gate/`](screens/npc-face-gate/README.md).
|
||||
|
||||
## Contract mismatch
|
||||
|
||||
The expensive part is the rig and proportions, not the mesh. The source has a
|
||||
|
||||
Reference in new issue
Block a user