Files
jeremy eae8327811 feat(characters): ship lena_leafbikini_base_v01 as female Ariki default
Lena with the leaf bikini sculpted into the mesh — a separate character
descending from her own Tripo original, not a lena_base_v02. Full-res
(1,029,360 v) at 1.777 m, now Ariki_Female_QuatSkin.glb + LOD1.

First nearest-surface graft in the rig lane: AccuRig had to be fed a 20:1
decimated bait, so the index-exact graft the two earlier ships used was
impossible. The bait recovers AccuRig's 9.346 mm offset in closed form, which
makes it a required input forever — copied into the ship folder, and rig-work's
"disposable" rule amended to say so. Mesh moved 0 mm, 0 unweighted verts.

lena_base_v01 goes superseded, not rolled-back: she lost the default slot but
Ariki_Female_QuatSkin_Nude.glb is untouched, so per rule 9 her folder stays put.

Also lands the leaf-cut lane (work/lena_leafbikini): hue-keyed seam detection
that removes the leaf shell and leaves both holes open by request, registered
as a lane milestone with its sha256. Corrects the rig-work trap note — baits do
carry embedded textures; it is AccuRig that strips them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:09:45 -07:00

105 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# lena_leafbikini_base_v01 — SHIPPED 2026-08-13
**Frozen.** Nothing in this folder is ever edited or re-exported (REGISTRY rule 2).
Any change at all becomes `lena_leafbikini_base_v02`.
The game's female base body. Lena wearing a leaf bikini that is **sculpted into the
mesh**, not a garment — there is no cloth to fit, no OutfitCatalog entry, and no way to
take it off. Full-resolution Tripo scan (999,823 v after weld) on the 65-bone Quaternius
skeleton. She replaced the nude `lena_base_v01` body as `Ariki_Female_QuatSkin.glb`.
First ship for the `lena_leafbikini` character. She is a **separate character lineage**
from `lena`, not a `lena_base_v02` — she descends from her own Tripo original
(`originals/female/female_lena_leafbikini_tripo.glb`, registered 2026-08-13) and shares
no geometry with the nude sculpt.
## Contents
| file | what |
|---|---|
| `lena_leafbikini_base_accurig_glb_v01.glb` | the body as it left this repo — pristine mesh + 3× 4K atlas + AccuRig skeleton, 1,029,360 v / 101 joints |
| `rig/lena_leafbikini_base_accurig_fbx_v01/` | **irreplaceable.** Output of a manual AccuRig 1.10.1822.1 session — no script regenerates this. Settings JSON kept alongside as provenance |
| `rig/lena_leafbikini_base_decimated_fbx_v01.fbx` | the 51,682 v carrier fed *into* that AccuRig session. Regenerable (`tools/rigbait_decimate.py`) but kept because the graft **cannot run without it** — see "the bait is the bridge" below |
| `preview/` | renders of the shipped body; `rigbait_qa_front.png` is the pre-rig carrier for comparison |
## How she was built
| step | what happened |
|---|---|
| bait | `tools/rigbait_decimate.py`, budgets body 24k / head 14k / hands 40k → 51,682 v / 77,999 tris, no scale, no recenter |
| rig | AccuRig 1.10.1822.1, manual, on the bait → 101 `CC_Base_*` bones, 38 finger bones, both wrists |
| graft | **nearest-surface**, `work/lena_leafbikini/01_graft.py` → weights off the 51,682 v carrier onto the pristine 1,029,360 v mesh. Mesh moved 0.000000 mm, 0 unweighted verts, weight sums exactly 1.0, deformed-at-rest drift 0.000239 mm |
| quatskin | `ariki-game/tools/make_lena_fullres_quatskin.py` with `LENA_CLEAR_SPLIT_NORMALS=1` → 65 joints, 1.777 m, rigid-mitt fingers |
## The bait is the bridge
This is the one structural difference from `lena_base_v01` and `mako_base_v01`, and it is
worth understanding before touching the lane again.
Both of those grafted **index-exact**: AccuRig was handed the shipping mesh whole and gave
back the same vertices in the same order, so weights copied index-to-index. Here AccuRig was
handed a carrier decimated **20:1** from the shipping mesh, so there is no index
correspondence and proximity is the only available mechanism.
That leaves the problem of *space*: AccuRig returns the carrier moved (measured here at
**9.346 mm** in Y, scale exactly 1.000000 — the same family as the July lane's 4 cm offset
trap), so its skeleton is in AccuRig's space, not the GLB's. Nothing is guessed to fix this.
The rigged FBX is index-exact against **the bait** (51,682 v both, same order), and the bait
is in the GLB's space by construction because `rigbait_decimate.py` applies no scale and no
recenter — confirmed exactly, bait and GLB sharing height 0.9792 and half-span 0.4583 to four
decimals. So fitting rigged→bait recovers AccuRig's transform in closed form.
**This is why the bait is in this folder.** Delete it and `01_graft.py` has nothing to fit
against and cannot run at all.
## Three facts that bite
- **`LENA_CLEAR_SPLIT_NORMALS=1` is load-bearing.** A raw Tripo delivery carries custom split
normals *and* a `sharp_edge` layer; left in place they are the "v8 specks"/faceting defect.
The converter's default is OFF because its default input is the v02 head-transplant body,
which needs them kept. Both layers must go together — clearing only the normals lets Blender
re-detect sharpness by angle and the facets come straight back.
- **She is single-sided**, unlike `lena_base_v01`, whose README calls `doubleSided=true`
load-bearing. That is not a regression: the inward-wound patches that forced it were an
artifact of the nude lane's re-atlas/membrane work, and this mesh never went through any of
it. Verified against the pristine delivery: `doubleSided` unset on the original.
- **AccuRig tidied one armpit.** Rigged-vs-bait residual is p50 **0.0009 mm** — bit-exact for
the bulk — with 1.01% of verts over 1 mm, all one cluster at height fraction 0.690.75 around
x=0.23. The hands, which is where a bad proximity transfer actually hurts, came back at mean
**0.020 mm** / max 1.45 mm. The graft's carrier gate measures the *shape* of that distribution
for exactly this reason; an earlier max-only threshold rejected a graft that is fine.
## Where it went
Converted by `ariki-game/tools/make_lena_fullres_quatskin.py` and imported as:
- `Ariki_Female_QuatSkin.glb` — sha256 `b6ca465ae3623e9fb3cc969f521d7cb89ad54b74271bb743fc594374864d56e6`.
The body she replaced is kept as `Ariki_Female_QuatSkin_PRESWAP_2026-08-13.glb.bak`.
- `Ariki_Female_QuatSkin_LowPoly_40.glb` — LOD1, sha256
`e770e4dce506492a28d0dffcaf609b6adbab35a7b63681923bea9028970ce47d`, rebuilt from her by
`tools/make_lena_lowpoly.py -- 0.4`. Predecessor kept as
`Ariki_Female_QuatSkin_LowPoly_40_PRESWAP_2026-08-13.glb.bak`.
Textures are packed in the GLB; nothing ships loose.
**Known decision:** no `Ariki_Female_QuatSkin_LeafBikini.glb` companion file. `lena_base_v01`
shipped one (`_Nude.glb`) byte-identical to the canonical body, because that is simply where
its converter wrote. Repeating it here would have put a second 79 MB full-res body into LFS and
made Godot import a duplicate 1 M-vertex mesh. The converter was pointed at the canonical name
via the new `LENA_OUT_GLB` override instead, and this folder is the repo-side master.
## Rebuilding / continuing
Recipe is `characters/work/lena_leafbikini/01_graft.py`. It needs three inputs, all preserved:
the pristine original, the AccuRig return in `rig/`, and the bait beside it.
```
blender --background --factory-startup --python characters/work/lena_leafbikini/01_graft.py -- \
characters/originals/female/female_lena_leafbikini_tripo.glb \
<rigged.fbx> <bait.fbx> <out.blend> <out.glb>
Q_CACHE=<qcache.json> LENA_SRC_BLEND=<out.blend> LENA_CLEAR_SPLIT_NORMALS=1 \
LENA_OUT_GLB=<ship.glb> blender --background --factory-startup \
--python ariki-game/tools/make_lena_fullres_quatskin.py
```