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>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# work/lena_leafbikini — the leaf-bikini lena lane
|
||||
|
||||
Grammar-exempt (REGISTRY rule 11). This lane has already produced one ship —
|
||||
`characters/female/lena_leafbikini_base_v01`, the game's female default since 2026-08-13,
|
||||
which is **frozen** (REGISTRY rule 2). Everything still here is lane material governed by
|
||||
`.agents/rules/working-files.md`; when the next body ships it graduates into
|
||||
`characters/female/lena_leafbikini_base_v02/` and gets its own Ships row.
|
||||
|
||||
Parent original: `characters/originals/female/female_lena_leafbikini_tripo.glb`
|
||||
(sha256 `977104ba…66cf29`, 1,029,360 v / 1,992,503 f, 0.9792 units tall → 1 unit = 1.815
|
||||
of a 1.777 m body). Read-only, and re-hashed by every stage that opens it.
|
||||
|
||||
## Layout
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| `NN_*.py` | the recipes. **These are the history** — kilobytes each, and they regenerate any state below from the original |
|
||||
| `leaf_mask.npz` | the leaf mask (stage 04): per welded point, plus the vertex→welded map and the hue/sat/val the key was cut from. Regenerable, kept because stage 05 consumes it and re-deriving it costs a full import |
|
||||
| `v01/` | stage output. **gitignored** (`characters/work/*/v0[0-9]/`) — registered artifacts inside it are `git add -f`'d by hand |
|
||||
| `v01/review/` | QA renders. gitignored, regenerable, reused rather than re-minted |
|
||||
|
||||
## The stages
|
||||
|
||||
| stage | what it does |
|
||||
|---|---|
|
||||
| `01_graft.py` | grafts the AccuRig skeleton onto the pristine GLB (nearest-surface, not index-exact — the bait was decimated 20:1). This is what produced `lena_leafbikini_base_v01`. Independent of 02–05 |
|
||||
| `02_probe_leaves.py` | what are the leaves? Reports the albedo key candidates and per-vertex proudness |
|
||||
| `03_render_leaves.py` | textured **and clay** turnaround of any mesh in the lane. The clay pass is what settled the question |
|
||||
| `04_leaf_mask.py` | builds and *proves* the leaf mask: hue key → component filter → close → hole fill → grow, baked to vertex colour and rendered |
|
||||
| `05_cut_leaves.py` | deletes the masked faces. Holes left open, on purpose |
|
||||
|
||||
## What the leaves turned out to be
|
||||
|
||||
The clay render (stage 03) shows every leaf, curled tip and hip vine with all materials
|
||||
stripped, so:
|
||||
|
||||
1. **They are real geometry, not paint.** This is the opposite of Lena's game-body
|
||||
underwear, where a ray-crossing census found the bra *was* the skin and deleting it
|
||||
opened a hole — the whole reason `tools/make_lena_nude_body.py` re-fairs a rim band
|
||||
instead of cutting. Here there is a solid shell to remove.
|
||||
2. **They are welded into the body.** One Tripo mesh, one material, one UV map: the
|
||||
leaves are a bulge in the body surface, not a separable object, material slot or UV
|
||||
island. Nothing can be selected "by object"; the seam has to be found.
|
||||
3. **The seam is both a colour edge and a crease** — where a leaf meets skin the surface
|
||||
folds back on itself.
|
||||
|
||||
## Why the key is hue
|
||||
|
||||
Stage 02 first keyed on green dominance, `G - max(R, B)`, and topped out at 0.20: Tripo
|
||||
painted these leaves a dark desaturated olive (sRGB ~0.27/0.35/0.20), so the channel gap
|
||||
is only ~0.05–0.09 and any threshold catching the leaf also catches shadow noise on skin.
|
||||
Hue separates them outright — skin 20–40°, leaf 60–80° — and is invariant to exactly the
|
||||
thing that ruins the channel gap, which is how dark the pixel is.
|
||||
|
||||
Everything after the key is repaired **on the mesh, over position-welded adjacency**, not
|
||||
in texture space:
|
||||
|
||||
| step | why |
|
||||
|---|---|
|
||||
| min-comp 200 | drops JPEG speckle |
|
||||
| close 6 rings | fills specular blowouts inside a leaf, where the highlight clips to near-white and its hue becomes noise. At `--val-max 0.62` the hip vine leaves came back half-grey |
|
||||
| enclosed-hole fill | a mask hole fully surrounded by leaf is a mask defect, not a skin island |
|
||||
| grow 2 rings | lands the cut just outside the rim. A hole one ring too big is invisible; a leftover leaf stub is not |
|
||||
| z ≤ 0.85 of height | **her irises and eyebrows are green too.** Without this the key takes her eyes (929 verts) |
|
||||
|
||||
Result: 239,561 welded points in exactly **two** islands — bust (z 0.631–0.755 of height)
|
||||
and briefs (z 0.455–0.594). Two islands is itself the check that nothing else keyed.
|
||||
|
||||
Welded adjacency is not optional anywhere here: the glTF importer splits every UV seam
|
||||
into separate Blender vertices, so on the raw mesh a face on a texture-chart border is
|
||||
indistinguishable from a face on a hole rim, and ring operations would leak along the
|
||||
seams (33,202 of the 1,029,360 verts are seam duplicates).
|
||||
|
||||
## The cut rule
|
||||
|
||||
A face dies only if **all** of its vertices are masked. With the 2-ring grow that puts the
|
||||
surviving rim about one ring outside the green, i.e. just onto skin. Both directions of
|
||||
that asymmetry are deliberate: "any vertex masked" erodes a further ring into her skin and
|
||||
leaves single triangles hanging off every zig-zag in the mask edge, while a cut one ring
|
||||
short leaves leaf root standing proud — the one outcome that would make the file useless
|
||||
for judging the seam.
|
||||
|
||||
Then two passes that can only remove things that are already not part of a smooth surface:
|
||||
dangling-face erosion (a face with ≥2 welded-boundary edges is joined to the surface by at
|
||||
most one edge; no such face exists on a closed surface, so it cannot bite into skin) and
|
||||
detached-shell removal. On this mesh they found **2 faces and 0 shells** — the colour cut
|
||||
was already clean, which is the strongest evidence the mask was right.
|
||||
|
||||
## Regenerating `v01/lena_leafbikini_leafcut_sculpt_glb_v01.glb`
|
||||
|
||||
```
|
||||
B="/c/Program Files/Blender Foundation/Blender 5.1/blender.exe"
|
||||
L=characters/work/lena_leafbikini
|
||||
"$B" --background --factory-startup --python $L/04_leaf_mask.py -- \
|
||||
characters/originals/female/female_lena_leafbikini_tripo.glb $L/v01/review
|
||||
"$B" --background --factory-startup --python $L/05_cut_leaves.py -- \
|
||||
characters/originals/female/female_lena_leafbikini_tripo.glb $L/leaf_mask.npz \
|
||||
$L/v01/lena_leafbikini_leafcut_sculpt_glb_v01.glb
|
||||
"$B" --background --factory-startup --python $L/03_render_leaves.py -- \
|
||||
$L/v01/lena_leafbikini_leafcut_sculpt_glb_v01.glb $L/v01/review cut
|
||||
```
|
||||
|
||||
Stage 05's gates, all reported and the first two fatal:
|
||||
|
||||
| gate | result |
|
||||
|---|---|
|
||||
| every surviving vertex position present in the input | 0 strays — this is a deletion and only a deletion |
|
||||
| loose vertices | 0 |
|
||||
| surviving shells | 1 |
|
||||
| removed geometry's extent | z 0.455–0.755 of height (bust + briefs bands only) |
|
||||
|
||||
## Open
|
||||
|
||||
- **The holes are not filled, by request.** Filling is a separate and harder decision:
|
||||
the crotch/gusset history in `work/lena/06*.py` is what happens when a membrane spans a
|
||||
wide footprint — it flattens the anatomy it spans, which is why the nude lane only ever
|
||||
faired a narrow rim band. Whatever fills these has to rebuild bust and crotch anatomy,
|
||||
not just span them.
|
||||
- The base-colour map still carries the leaves and their baked contact shadows. The rim of
|
||||
each hole is skin painted with leaf shadow, so it reads darker than her surrounding tone.
|
||||
- **The cut is unrigged**, because it was authored on the pristine original. It transfers
|
||||
to the shipped body for free: `01_graft.py` moved the mesh 0.000000 mm, so
|
||||
`lena_leafbikini_base_v01` carries the *same* 1,029,360 vertices in the same order and
|
||||
`leaf_mask.npz` indexes it directly. Cutting the shipped GLB is running stage 05 with a
|
||||
different first argument — but the result is a new ship folder, never an edit to the
|
||||
frozen one.
|
||||
Reference in New Issue
Block a user