2026-08-06 15:55:43 -07:00
|
|
|
|
# Rig-graft lane — AccuRig skeleton onto pristine Tripo GLBs (PLAN, not executed)
|
|
|
|
|
|
|
|
|
|
|
|
**Repo home:** this plan and its tools moved from ariki-game into the animation repo
|
|
|
|
|
|
2026-08-06 — the lane authors characters, so `characters/REGISTRY.md` governs it (see
|
|
|
|
|
|
`.agents/wiki/ARCHITECTURE.md` "Which repo does a non-gameplay tool belong to"). Paths
|
|
|
|
|
|
below are animation-repo-relative unless prefixed `ariki-game/`.
|
|
|
|
|
|
|
|
|
|
|
|
**Status 2026-08-04: PLAN ONLY. Jeremy has explicitly held execution — no model
|
|
|
|
|
|
files are to be created or modified until the naming convention is decided.**
|
|
|
|
|
|
|
|
|
|
|
|
## Goal
|
|
|
|
|
|
|
|
|
|
|
|
Rig Ozlem's two unrigged Tripo bodies without the FBX→GLB quality loss the male
|
|
|
|
|
|
lane hit in July (mangled textures, bad hand skinning). The move: FBX is only a
|
|
|
|
|
|
**disposable rig carrier** through AccuRig; the **GLB is the sole source of truth**
|
|
|
|
|
|
for mesh + materials and only ever *gains* bones and weights.
|
|
|
|
|
|
|
|
|
|
|
|
## Source files (curated 2026-08-04)
|
|
|
|
|
|
|
|
|
|
|
|
Byte-identical copies live in both repos: `characters/originals/` here (checksummed in
|
|
|
|
|
|
`characters/REGISTRY.md`) and `ariki-game/assets/models/characters/race-sources/`. Read
|
|
|
|
|
|
from this repo's copies.
|
|
|
|
|
|
|
|
|
|
|
|
| file | verts | tris | height | feet @ Z0 | axis | textures |
|
|
|
|
|
|
|---|---|---|---|---|---|---|
|
|
|
|
|
|
| `female_lena_tripo.glb` | 974,478 | 1,907,931 | 0.979 m | yes (0.0) | upright, rot 0, scale 1 | 3 packed 4K (basecolor/normal/rm) |
|
|
|
|
|
|
| `female_lena_tripo.fbx` | 953,968 | 1,907,931 | 0.979 m | — | upright | 5 external JPEGs (.fbm removed; git-recoverable) |
|
|
|
|
|
|
| `male_base_bald_tripo_v1.glb` | 969,881 | 1,901,449 | 0.980 m | yes (0.0) | upright, rot 0, scale 1 | 3 packed 4K, clean |
|
|
|
|
|
|
| `male_base_bald_tripo_v1.fbx` | 950,729 | 1,901,449 | 0.980 m | — | **lying down (bad axis)** | 6 packed, all mislabeled "Diffuse Texture.NNN", duplicated basecolor |
|
|
|
|
|
|
|
|
|
|
|
|
Census facts that shape the plan:
|
|
|
|
|
|
|
|
|
|
|
|
- **No bones anywhere** — all four files are truly unrigged, so no rig standard is
|
|
|
|
|
|
imposed by the sources. The 65-bone Quaternius game standard is unaffected.
|
|
|
|
|
|
- **Identical surfaces per pair** (tri counts match exactly); vertex counts differ
|
|
|
|
|
|
~2% from format-specific UV-seam splitting → index-exact weight copy is off the
|
|
|
|
|
|
table, nearest-surface transfer is the mechanism (surfaces coincide, so it is
|
|
|
|
|
|
near-exact everywhere except close-packed fingers — see step 4).
|
|
|
|
|
|
- The male FBX's axis + texture mangling is the July failure mode reproduced in
|
|
|
|
|
|
data — never source visual data from FBX.
|
|
|
|
|
|
|
|
|
|
|
|
## Decisions (Jeremy, 2026-08-04)
|
|
|
|
|
|
|
|
|
|
|
|
1. **NO scaling to standard height.** Bodies stay at Tripo's native ~0.98 m.
|
|
|
|
|
|
(Any scale handling happens later, downstream, not in this lane.)
|
|
|
|
|
|
2. **Axis check + ground the feet** — wanted, and the probe shows both GLBs
|
|
|
|
|
|
already pass (rot 0 / scale 1 / min-Z exactly 0.0). These become verify-only
|
|
|
|
|
|
gates, mutating nothing unless a future source fails them.
|
|
|
|
|
|
3. **HOLD before decimation** until the naming convention for derived files is
|
|
|
|
|
|
agreed. Nothing below the line runs until then.
|
|
|
|
|
|
|
|
|
|
|
|
## The lane (each step gated on the one before)
|
|
|
|
|
|
|
|
|
|
|
|
1. **Verify** (read-only, DONE for the two current GLBs): upright axis, unit
|
|
|
|
|
|
scale, feet at Z=0, centered X, packed textures present.
|
|
|
|
|
|
2. **Rig bait** *(HELD — naming)*: from the GLB, decimate a disposable copy and
|
|
|
|
|
|
export FBX for AccuRig. **Confirmed 2026-08-04: AccuRig refuses the raw
|
|
|
|
|
|
1.9 M-tri FBX outright** (Jeremy tried; July hit the same wall). Use the
|
|
|
|
|
|
`ariki-game/tools/male_mesh_decimate.py` precedent: region budgets body 24k / head 14k /
|
|
|
|
|
|
**hands 10k as their own protected region** (global-ratio decimation webs the
|
|
|
|
|
|
fingers — half of the historic hand-mangling happened here, pre-AccuRig).
|
|
|
|
|
|
Apply the July male-lane traps: Dummy-export quirk, the 4 cm offset.
|
|
|
|
|
|
No scale change on the GLB — but if AccuRig misplaces joints on a 0.98 m
|
|
|
|
|
|
body, scale the DISPOSABLE BAIT up 2× and scale the returned skeleton back
|
|
|
|
|
|
down in the graft; the GLB never changes size.
|
|
|
|
|
|
3. **AccuRig** (manual, Jeremy/Ozlem): rig the bait FBX. Export rigged FBX.
|
|
|
|
|
|
4. **Graft** (headless Blender): import rigged bait FBX + pristine GLB; snap rest
|
|
|
|
|
|
poses; transfer skeleton + skin weights decimated→full-res by nearest-surface
|
2026-08-12 07:17:15 -07:00
|
|
|
|
with tight max-distance. Export GLB: original mesh + original packed
|
2026-08-06 15:55:43 -07:00
|
|
|
|
textures + new rig. FBX artifacts are discarded.
|
2026-08-12 07:17:15 -07:00
|
|
|
|
**Hands are no longer part of this step — see "Hands" below.**
|
2026-08-06 15:55:43 -07:00
|
|
|
|
5. **QC**: pose sweep incl. finger curls; then (if/when destined for game) the
|
|
|
|
|
|
existing AccuRig→Quaternius conversion (`ariki-game/tools/make_male_ib_quatskin_accurig.py`
|
|
|
|
|
|
lineage) picks it up.
|
|
|
|
|
|
|
2026-08-12 07:17:15 -07:00
|
|
|
|
## Hands: transplanted, not solved (RESOLVED 2026-08-07)
|
|
|
|
|
|
|
|
|
|
|
|
The hands come off the bait entirely and are transplanted from a body that already
|
|
|
|
|
|
ships working ones — `tools/graft_hands.py`, wrist-aligned. Three measurements
|
|
|
|
|
|
decided this:
|
|
|
|
|
|
|
|
|
|
|
|
- **There is nothing to solve.** The nude lane never touched the hands: hand-region
|
|
|
|
|
|
displacement from the Tripo original is mean **0.010 mm**, p50 exactly 0.000, only
|
|
|
|
|
|
0.06% beyond 1 mm (the 12.6% vertex churn there is micron jitter from the v03
|
|
|
|
|
|
despeckle pass). A donor's hand weights fit this mesh as-is.
|
|
|
|
|
|
- **A mitten rig would cost real animation.** Fingers move *relative to each other*
|
|
|
|
|
|
by up to **89°** over a clip (fertility 89.4°, taming 77.6°, nd_01 46.7°,
|
|
|
|
|
|
canoedismount 26.4°); only `war_dance_01` and `hakadance1_static` hold them still.
|
|
|
|
|
|
So four of six dances would visibly flatten. Rejected.
|
|
|
|
|
|
- **The bone list is not negotiable anyway.** 40 of the 65 joints are hands, every
|
|
|
|
|
|
clip carries tracks for all 40, and `tools/verify_body_variant.py` gates on "65
|
|
|
|
|
|
joints in identical order". A mitten could only ever have been a *skinning* choice.
|
|
|
|
|
|
|
|
|
|
|
|
`graft_hands.py` edits the glTF node graph directly rather than round-tripping the
|
|
|
|
|
|
armature through Blender, because Blender re-derives bone rest orientation from
|
|
|
|
|
|
edit-bone head/tail — the exact failure `ariki-game/tools/rig_pose_gate.py` exists to
|
|
|
|
|
|
catch. Validated: two self-tests (identity, and a 0.55× + 7° similarity) place every
|
|
|
|
|
|
hand joint to **5e-16 u** and recover 100% of donor weights; output passes
|
|
|
|
|
|
`verify_body_variant.py`; and `rig_pose_gate.py` reports **max error 0.000° over 260
|
|
|
|
|
|
(bone, clip, sample) comparisons** under the two most finger-heavy dances.
|
|
|
|
|
|
|
|
|
|
|
|
Two self-inflicted bugs the similarity test caught, worth not re-introducing: the
|
|
|
|
|
|
wrist scale gets applied **twice** if you compose the target's wrist matrix without
|
|
|
|
|
|
stripping its own scale first (the forearm ratio was measured in that same scaled
|
|
|
|
|
|
space), and the weight transfer must convert donor-local → world → target-local, not
|
|
|
|
|
|
compare raw POSITION arrays across two files.
|
|
|
|
|
|
|
|
|
|
|
|
**Still open on hands:** if AccuRig returns no wrist joint at all once the hands are
|
|
|
|
|
|
cut from the bait, `graft_hands.py` aborts — the `--wrist-from-forearm` fallback is
|
|
|
|
|
|
specified but not implemented, because what AccuRig actually returns is unknown until
|
|
|
|
|
|
step 3 runs.
|
|
|
|
|
|
|
2026-08-06 15:55:43 -07:00
|
|
|
|
## Naming + step 2 status (RESOLVED 2026-08-04, later same day)
|
|
|
|
|
|
|
|
|
|
|
|
Jeremy raised the hands budget and released the bait step. Built with
|
|
|
|
|
|
`tools/rigbait_decimate.py` (parameterized successor to male_mesh_decimate.py —
|
|
|
|
|
|
no scale/recenter, bbox-relative region cuts, budgets body 24k / head 14k /
|
|
|
|
|
|
**hands 40k**):
|
|
|
|
|
|
|
|
|
|
|
|
- `characters/rig-work/lena_tripo_rigbait.fbx` — 77,999 tris, QA'd
|
|
|
|
|
|
- `characters/rig-work/mako_tripo_rigbait.fbx` — 78,000 tris, QA'd
|
|
|
|
|
|
- `characters/rig-work/` is exempt from the naming grammar (REGISTRY.md rule 11) —
|
|
|
|
|
|
disposable carriers, no registry rows. In the game repo it had needed a `.gdignore`
|
|
|
|
|
|
to stop Godot importing it, which was the tell that it lived in the wrong repo.
|
|
|
|
|
|
- QA renders alongside (`*_qa_front.png`, `*_qa_hand.png`) — fingers fully
|
|
|
|
|
|
distinct at 40k, no webbing.
|
|
|
|
|
|
- Baits are geometry-only (~3.5 MB; the GLB's packed textures don't survive FBX
|
|
|
|
|
|
embed) — AccuRig shows a grey model, which is fine for rigging. It does mean
|
|
|
|
|
|
the July "Dummy001 export" check can't use textures: **verify AccuRig's output
|
|
|
|
|
|
by mesh name + ~78k tri count instead.**
|
|
|
|
|
|
|
|
|
|
|
|
**AccuRig exports must be saved as** (same folder):
|
|
|
|
|
|
- `characters/rig-work/lena_tripo_accurig.fbx`
|
|
|
|
|
|
- `characters/rig-work/mako_tripo_accurig.fbx`
|
|
|
|
|
|
|
|
|
|
|
|
## Open before execution
|
|
|
|
|
|
|
|
|
|
|
|
- Step 3 (AccuRig) — manual, waiting on Jeremy/Ozlem.
|
|
|
|
|
|
- Step 4 graft script — build once a rigged FBX exists to test against.
|
|
|
|
|
|
- Whether to restore the female FBX's `.fbm` texture folder from git (only needed
|
|
|
|
|
|
if the FBX is ever used for more than rigging; the lane says it shouldn't be).
|