Files
animation/characters/work/lena_leafbikini/README.md
T
jeremy 3f335ee2d7 docs(lena): land pending stage-07 crotch-fill recipe
`07_fill_crotch.py` and its README autopsy were written in an earlier session
and had been sitting uncommitted. Committing them unchanged, separately from
today's hand-weight work, so neither is misattributed to the other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 11:31:55 -07:00

174 lines
12 KiB
Markdown
Raw 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.
# 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 0205 |
| `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 |
| `06_open_in_blender.py` | opens a lane mesh in the Blender GUI, framed on her front, Material Preview |
| `07_fill_crotch.py` | **v02**: Barbie-fills the crotch — melts the briefs leaves into a smooth featureless surface, bust holes stay open. See below |
## 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.050.09 and any threshold catching the leaf also catches shadow noise on skin.
Hue separates them outright — skin 2040°, leaf 6080° — 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.6310.755 of height)
and briefs (z 0.4550.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.4550.755 of height (bust + briefs bands only) |
## v02 — the Barbie crotch fill (stage 07)
Target: "Barbie doll anatomy" — a completely smooth, undifferentiated pelvic surface, no
cleft, no features, belly flowing into thighs. Jeremy's "take the distance and angle
between the two sides" is precisely a bi-harmonic membrane: the rim supplies POSITION, the
collar behind it supplies SLOPE through the second Laplacian application, and L²x = 0
cannot invent detail. Bust holes stay cut open (v01 behaviour); only the briefs band gets
the treatment.
Getting there burned through roughly ten runs; the recipe header carries the full autopsy,
the short version is:
| attempt | verdict |
|---|---|
| triangle_fill the v01 holes + membrane | the briefs rim is ONE ~2,500-vert loop snaking front → between the legs → back; beauty triangulation bridges the WRONG BANKS at the bends, and the rim itself still carried leaf-root crumple the membrane faithfully anchored to |
| + rim erosion + Delaunay flips + double solve | better rims, same disease — flips are local, the mis-bridging is global; sliver strands shot off the hips |
| **melt instead of fill** (the pivot) | the leaf shell IS the disk that spans the hole — the scan's own manifold surface. Free its verts + a skin collar, solve; wrong-bank bridging becomes impossible. This produced the first genuinely smooth pelvis |
| proudness detectors + deflation for the leftovers | fully-masked leaves are PENDANT BALLOONS — closed shells whose excess area the (no-maximum-principle) bi-harmonic parks as smooth raised caps. Smoothing-built references partially follow any bump wider than their radius, and **Taubin references are worse than useless here: shape-preserving by design, a 1.5 cm cap sits inside the passband and reads ~0** |
| density excision + scar refill | catches the FLAT wads (the melted shell lies ~4 layers deep, and piles would z-fight) but not inflated caps, which sit BELOW the piled median. Scar refill needs: per-sweep densify scope with a floored target (a sliver scar once re-densified everything to 3.3M faces / 17 h), a slit weld first (scars meeting Tripo slits are ribbons, not loops — fill ops refuse them, and degenerate output crashed Blender once), and a >900-edge refusal |
| occlusion / fin / diffusion detectors for the last four "caps" | all near-zero. A pixel-ray probe finally explained why: **the last bumps were not leaf debris at all — they are the melt web itself bridging taut over the inguinal hollow.** There was never skin under the vine, and every rim-anchored method spans its anchors by construction |
| **+ the flow finish** (the guarantee) | damped pure-Laplacian flow over the whole changed region, no detector at all: the maximum principle sinks any pendant cap while the 5-10× wider pubic web barely moves. Ramp weight 0→1 over **3** rings — at 8 rings the hip-vine channel (1020 rings wide) sat entirely in the damped zone |
| **+ the solid-welt pass** | some leaf roots are SOLID skin-painted ridges, not shells — free them (0.5 mm proudness against a whole-band 400-sweep reference; honest skin reads p95 +0.13 mm) and re-solve locally; converges in 2 passes (5,375 verts, then 1) |
Pipeline as shipped in `07_fill_crotch.py`: weld → cut bust open (+despike) → free briefs
leaves + collar → remnant sweep (relaxed hue/blown-white key near the melt, no speckle
filter) → bi-harmonic melt (matrix-free Jacobi-PCG, harmonic warm start) → solid-welt pass
×2 → density excision of flat wads + occlusion pass → slit weld + degenerate dissolve →
three scar-fill sweeps + patch solve → flow finish. Melted faces get one donor texel
(thigh-band vertex nearest the band's median tone with the most neutral normal texel) —
the atlas is Tripo chart soup, so interpolating UVs across the fill would sample garbage.
```
"$B" --background --factory-startup --python $L/07_fill_crotch.py -- \
characters/originals/female/female_lena_leafbikini_tripo.glb $L/leaf_mask.npz \
$L/v02/lena_leafbikini_crotchfill_sculpt_glb_v02.glb --free-rings 3
```
## Open
- **The hip-side shelf bulges are a known consequence, not a bug to chase further.** Where
the vine crossed the inguinal crease there was never skin underneath, and "take the
distance and angle between the two sides" — the membrane — spans its anchors by
construction. Any method anchored at the rims produces the same taut bridge (harmonic,
bi-harmonic, and flow all agree; the maximum principle *protects* a two-sided span).
Killing them means SCULPTING the crease through the strip — invented anatomy, its own
decision, its own stage. Ten runs of detector archaeology confirmed there is nothing
foreign left there to remove.
- **The bust holes are not filled, by request** (v01 deliverable; v02 fills the crotch
only). Whatever fills the bust has to rebuild breast anatomy, not just span it — see
`tools/make_lena_nude_body.py` for how the nude lane sculpted hers procedurally.
- The base-colour map still carries the leaves and their baked contact shadows. Around the
v01 holes and the v02 fill alike, the surviving skin reads darker than her surrounding
tone — an albedo re-author job for a later stage (the nude lane's harmonic refill is the
template).
- **Both artifacts are unrigged**, because they were authored on the pristine original.
They transfer to the shipped body's frame 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 either mesh. Re-running 05/07 against the shipped
GLB is a first-argument change — but the result is a new ship folder, never an edit to
the frozen one.