From cba00facf57c1e9b94a56bc9fcca5c77939c1dfa Mon Sep 17 00:00:00 2001 From: Zwitschi Date: Fri, 6 Nov 2026 18:05:57 +0100 Subject: [PATCH] Record the roster fixes, material-list traps and head-gear offset in MEMORY.md --- MEMORY.md | 63 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index 510a0c4..f85edc3 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -119,22 +119,54 @@ canonical implemented-features list in `docs/development-status.md`. library with a sculpted realistic face, so the 0.9.9 gate is a product decision, not just an art check. Owner picks full swap / crowd-only / extra head detail. Do not lower character fidelity silently. -- **Pose composition is rest-relative (resolved 2026-11-05):** Godot's `set_bone_pose_rotation` - offsets from the bone rest, so the correct swing around a world axis is - `rest * Quaternion(rest.inverse() * axis, angle)`. For the old 180° rest this reduces to the - legacy `rest * Quaternion(axis, angle)`, so the 13-core fallback is unchanged (commit `8b1bf73`). +- **Pose composition is rest-relative (resolved 2026-11-05):** see `_swing_bone()` in the gotchas — + the rest-relative `set_bone_pose_rotation` form was abandoned; the global-pose write replaced it. - **Full roster swap (2026-11-05, owner):** at the `0.9.9` face gate the owner chose option (a), full swap. All twelve public character names are baked from the three CC0 Quaternius sources (`casual`, `hoodie`, `worker`); variety comes from the five tint slots, the outfit rules and the gear library. The procedural library + MakeHuman head stay in the tree as the tested fallback (`build --source procedural`), not in the shipped roster. Silhouette variety is the known regression — three meshes for twelve roles — and the modular part library is the `0.9.10` fix. +- **No hats except the firefighter helmet (2026-11-06, owner):** the iconography is not worth the + cost — a cap or hood on this head hides the face, and every hat needed a lift+scale hack to clear + the 0.228 m hair shell. `ACCESSORIES` maps no role to `cap`/`hood`, the guard/vest per-character + caps are gone, the performer cone was removed, and the primitive cap/hood fallbacks were deleted + with their `GEAR_OFFSETS`/`GEAR_SCALE` compensation. `firefighter_helmet` is the only head item. + Do not re-add head gear without an owner decision and a fit measurement. +- **Mouths are authored, not upstream (2026-11-06):** none of the three Quaternius heads has a mouth + material, so the faces read as brow-and-eye masks. `_add_quaternius_mouth()` places a small lip + block on the measured skin surface (front-most skin vertex in the 1.600–1.632 m band, ±35 mm of + centre) at 1.616 m. One rule covers all three bases; it runs before the slot map, so match the + material as `_base_name(m.name).lower() == "skin"`. - **One character source, one fallback:** no new NPC source without an ADR. MPFB body work stays closed, the Stage-1 proportion warp is not reopened, and the procedural `npc_base` + MakeHuman head stay tested until the Quaternius base passes its gate. ## Gotchas / Known Issues +- **Blender material-list edits corrupt polygons silently.** Two separate bugs, same root: + `obj.data.materials.clear()` resets **every polygon to slot 0**, so the per-face indices must be + captured *before* the clear and reassigned after; and `IDMaterials.pop(index=)` repoints the + polygons that used the slot, which once painted a whole face with the eye material. The safe + pattern is `_purge_unused_materials()`: read the per-face material **names**, rebuild the slot + list from the names, then write the indices back by name. +- **A zero-user material still owns its name.** Removing a slot leaves the datablock behind, so a + donor material renamed to the freed name lands as `Eye.001` and every `m.name == "Eye"` rule + silently misses it. Purge the datablocks (`bpy.data.materials.remove(m)` when `m.users == 0`) or + match on `_base_name()`. +- **Blender node colours are linear; Godot tonemaps them.** A mouth lip at `0.16` linear rendered as + salmon/mauve. Divide by roughly 3–4 versus the intended sRGB value: the hair uses 0.027 linear, + the lip 0.055/0.018/0.02. +- **The modular Quaternius Worker has no torso under its vest and no crown under its hard hat.** + Deleting either material leaves real holes (that is what shipped in the first 0.9.9 build: guard + and firefighter showed the inside of the head and torso). Remap instead of deleting; the only + geometry the build removes is the Worker brow bar, which is replaced by a donor part. +- **Head gear authored for the 0.315 m procedural head is wrong on the 0.20 m Quaternius head.** Gear + is authored around the head *centre* (1.62) while the attach node is the Head *bone* (1.587), and + the Quaternius centre is 1.69 — a 7 cm error put every cap brim across the brows, which I spent + several passes misreading as a mesh hole (the band was pure black and no material had faces + there). `HEAD_GEAR_LIFT = 0.103` fixes the common case. With the hats removed this only affects + the firefighter helmet. - **Two character builders — do not confuse them.** `tools/blender_assets.py` is the real builder for the **eight library characters, 18 gear pieces and props** (it has the 0.9.4 face/hand sculpting in `_face()`/`_hands_and_shoes()`); `tools/npc_pipeline.py` builds **only** @@ -281,14 +313,21 @@ 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. -**Full roster (0.9.9, commits `a6ccd86`, `04d211b`, `b3acf37`):** all twelve characters run on -the Quaternius bases (4,458–6,424 tris, 62 joints, 73–74 px/m texel density), built by the -shipped `tools/blender_assets.py` two-pass pipeline (`_quaternius_tpose_glb` → -`_bake_quaternius_rest`). Gates: `audit` 12/12, `inspect` clean, `fit` OK, 24-NPC budget -160,608 tris / 0.84 ms, Godot 278/278, Python 167/167. The owner visual signoff page is -`docs/npc-visual-review.md`. Release packaging was also fixed the same day: excluding -`tmp/`, `build/`, `docs/`, `tools/`, `src/test/` and `.agents/` from the export presets cut the -Linux binary from 426 MB to 273 MB, and `tools/build_releases.sh` now writes a SHA256SUMS file. +**Full roster (0.9.9, commits `a6ccd86` … `9fd4824`):** all twelve characters run on the +Quaternius bases (62 joints, 73–74 px/m texel density), built by the shipped +`tools/blender_assets.py` two-pass pipeline (`_quaternius_tpose_glb` → `_bake_quaternius_rest`). +The owner signed the roster off **with follow-ups** and rejected three review rows; the Worker +body defects (holes, unibrow, missing eyes) and the head-gear seating are fixed, every hat except +the firefighter helmet is removed, and every head has an authored mouth. Gates: `audit` 12/12, +`inspect` clean, `fit` OK, 24-NPC budget 174,976 tris / 0.85 ms, Godot 278/278, Python 167/167. +Owner review page: `docs/npc-visual-review.md`. Release packaging was fixed the same day: +excluding `tmp/`, `build/`, `docs/`, `tools/`, `src/test/` and `.agents/` from the export presets +cut the Linux binary from 426 MB to 273 MB, and `tools/build_releases.sh` writes a SHA256SUMS file. + +**Open after the swap:** hand-held gear and role props are still authored for the old body (wrist +y 0.78 → 1.017, arm shorter), so the clipboard and umbrella are oversized; the eyes have no whites; +the arms graze the torso on the `worker` base; roster variety is three meshes for twelve roles. The +prop/gear fit pass is queued in `TODO.md` under 0.9.10. **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