Files
Papay-Shooter/.claude/skills/character-pipeline/references/growing-cloth-bones.md
T
Nicholas ButzkeandClaude Opus 5 7892669319 feat(pipeline): grow skirt and hair bone chains for a costume that has none
Miku shipped with 0 cloth chains against Taila's 35, so her twin tails
hung off her skull like a helmet. Nothing downstream could fix it: the
spring solver simulates cloth BONES, and a garment with none is welded to
whatever body bone it was weighted to. Every auto-rigged model is in that
state, and her source was an unrigged mesh.

tools/cloth_bones.py builds them, which is the job a technical artist does
by hand on a model like this. It finds the geometry by MATERIAL SLOT — the
artist already answered which surface is hair, and on a joined mesh (what
the auto-rig leaves behind) the slot is the only separation left. Hair is
split into connected islands, because a strand is a connected piece of
surface and clustering by position would merge two ponytails passing near
each other. A skirt is split into radial wedges instead, because a skirt
is ONE connected surface and islands would return the whole thing as a
single piece — the bell-shaped failure. Each clump gets a polyline fitted
down its middle by binning vertices by distance and taking centroids, so
the chain follows the piece's own curve rather than cutting the corner on
a bend, and vertices are re-weighted onto it while the first 22% keeps its
original body weight so the scalp stays on the skull.

On Miku: 19 chains, 57 bones from one `hair` slot. Sidecar 0 -> 19 chains.
Idle stability 0.007-0.018 deg/frame. Mesh intact, verified by render.

Opt-in, via `pipeline.py --grow-cloth`, and run before the retarget so
describe_rig() finds the chains by name exactly as it would an artist's.

Known limits, recorded in the skill: it cannot find a garment sharing a
material with the body (Miku's skirt is on her `body` slot, so she got
hair and no skirt), and grown chains are a fallback — an artist's chains
carry intent that no geometric fit recovers.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-07-26 13:19:44 -04:00

3.5 KiB

Growing cloth bones on a model that has none

tools/cloth_bones.py, opt-in via pipeline.py --grow-cloth.

When you need it

The spring solver simulates cloth bones. A garment with none is welded to whatever body bone it was weighted to, and no runtime setting changes that. Every auto-rigged model is in this state, and so is many a "rigged" download whose skeleton is body-only.

Check before importing (no Blender needed — see separation.md): if the joint list has nothing matching hair|skirt|tail|ribbon, the costume will not move.

What it does

Runs on the rigged model, before the retarget.

  1. Finds the geometry by material slot. A slot called hair is hair. The artist already answered the question, and on a joined mesh — which is what the auto-rig leaves behind — the material slot is the only separation left.
  2. Splits it into clumps.
    • Hair: connected islands over the mesh's own edges. A strand is a connected piece of surface; clustering by position would merge two ponytails passing near each other and split one that bends.
    • Skirt: radial wedges around the body's up axis. A skirt is ONE connected surface, so islands would return the whole thing as a single piece — which is the bell-shaped failure. Wedges are the ZZZ-convention panel grid.
  3. Fits a polyline down each clump by binning vertices by distance from the anchored end and taking each bin's centroid, so the chain follows the piece's own curve. A straight root-to-tip line cuts the corner on a bent ponytail and every vertex on the outside of that bend ends up on a bone travelling the wrong way.
  4. Builds a bone chain along the polyline, parented to the body bone that was already holding that geometry.
  5. Re-weights each vertex onto the two bones either side of where it projects, blended by how far between them it lands — while keeping the ORIGINAL body weight over the first ROOT_BLEND (22%) of the chain, so the scalp stays on the skull and the waistband stays on the hips.

Then retarget.py::describe_rig finds the chains by name exactly as it would an artist's, and writes tips, hulls and neighbours to the sidecar.

Tuning

--hair-segments 3     bones per hair strand
--skirt-segments 4    bones per skirt panel
--skirt-panels 12     radial panels; more = opens around a leg more smoothly
--classes hair,skirt  which material names to look for

MIN_STRAND_LENGTH (60 mm) and MIN_STRAND_VERTS (12) drop fringe and ornaments. Simulating those costs the same as a ponytail and only ever produces jitter around the face.

Worked result: Miku

19 chains, 57 bones grown from one `hair` material slot
sidecar: 0 cloth chains -> 19
idle stability: 0.007-0.018 deg/frame (quiet)
mesh intact, no tearing (debug/character_look_capture.gd)

Limits

  • It cannot find a garment that shares a material with the body. Miku's skirt is on her body slot, so she got hair chains and no skirt. Splitting by geometry rather than by material would be the next step.
  • It does not set weights_authored. An auto-rigged model still gets the destructive load-time SkinLegRepair. That repair only touches cross-leg vertices, so it leaves hair alone, but it is worth knowing.
  • Grown chains are a fallback, not a substitute for a rigged source. They follow the geometry, but an artist's chains carry intent — where a panel should split, which strands move together — that no fit recovers.