Files
animation/garments/glm-advice-glm52.md
jeremy 3ba86b2ea8 feat: clothing lane, character sources, and DCC bridges
Bulk import of the working lanes that were living untracked on the PC.

Content:
- characters/  Lena/male body lanes, bakes, texture work, run logs
- clothing/    garment pipeline, configs, gates, contract docs
- garments/    MD-authored garment sources (.zprj/.zpac)
- UAL-Lib/     Universal Animation Library 2 source (.blend/.fbx/.glb)
- tools/       blender_bridge, iclone_bridge, md_bridge, tailor, glm_agent
- docs/, plans/, dev/, .agents/plans/

Repo hygiene:
- .gitattributes: LFS now covers .blend, .zprj, .zpac, .obj, .npy and the
  Reallusion .iAvatar/.ccAvatar/.ccRestore containers. Without this the
  ~3.8 GB in this commit would land as raw blobs. .png/.jpg are left out
  on purpose — ~250 are already tracked raw and converting them would
  rewrite every one without shrinking history.
- .gitignore: exclude /accurig/ (~1 GB AccuRig program files, redistributable
  from Reallusion, nothing authored here) and /dev/null/ (git-lfs hook copies
  dropped by a `>/dev/null` redirect on Windows).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 15:55:43 -07:00

86 lines
9.2 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.
# GLM advice (glm-5.2 via api.z.ai)
## 1. Weld+decimate 4.3M→1.5k: better approach
Collapse-decimating unwelded MD soup at ~3000:1 will eat pleats. Three concrete changes:
**(a) Reorder the pipeline: weld → fit (shrinkwrap high-poly) → decimate → bake.** Fitting before decimating lets Shrinkwrap use real pleat geometry; fitting a faceted 1500-tri proxy to a 25k body gives poor contact and lost silhouette. This is the single biggest fix to the plan.
**(b) Use Decimate in DISSOLVE (planar) mode for flat-panel parts**, not COLLAPSE. MD panels are nearly planar, so `DecimateModifier(decimate_mode='DISSOLVE', angle_limit=rad(5°))` merges coplanar faces and preserves panel boundaries + UVs far better than collapse. Use 810° for the bow. Collapse mode is only acceptable on truly curved regions.
**(c) For the pleated skirt, do not decimate the MD mesh — build a low-poly proxy.** Cylinder, 2832 segments, 34 vertical loops, knee length, denser waistband ring. `ShrinkwrapModifier(wrap_mode='NEAREST_SURFACE', offset=0.0020.003)` to the high-poly skirt. Bake normals high→low (see Q5). At 1500 tris, geometric pleats read as noise; normal-map pleats read as pleats.
Reject voxel remesh: destroys UVs, loses 68mm pleats at any feasible voxel resolution (you'd need ~0.5mm voxels = tens of millions). Reject Quad Remesher add-on: not headless-stable, license-bound. If you can re-export from MD, lower particle distance to 57mm and reduce pleat segment counts before sim — gives a 50100k mesh that decimates cleanly.
Keep the high-poly around (hidden, excluded from export) for baking.
## 2. Skirt weights without extra bones
Nearest-vertex KDTree is the wrong tool — it snaps to the closer leg, giving a hard medial seam. Standard recipe is a **weight-transfer proxy**:
1. **Build a skirt cone**: duplicate Lena's body, keep pelvis→mid-thigh, bridge the leg gap into a tapered cylinder covering the skirt volume (waist ring at pelvis, knee ring at hem). Or extrude the pelvis ring downward to a knee-level ring scaled to skirt radius.
2. **Weight the cone by Z-gradient**: top ring = copy body weights via `DataTransferModifier(vert_mapping='NEAREST_SURFACE', data_type='VGROUP_WEIGHTS')`. Bottom ring = 100% pelvis, 0% thighs. Blend linearly by world-Z between waist and hem. Add a small L/R thigh bias by X-sign so the hem still leans slightly with the stance leg.
3. **Transfer cone→skirt**: `DataTransferModifier(vert_mapping='NEAREST_SURFACE', layers='ALL')`, apply, then `bpy.ops.object.vertex_group_smooth(repeat=3, factor=0.5)`.
This gives smooth L/R blend at the crotch (continuous cone surface) and pelvis-dominant hem. No hard seam. The Z-gradient is forward-compatible with future skirt bones — you can blend skirt-bone weights in by Z-band without redoing the transfer.
Fallback if you can't build the cone: per-vertex, compute distance to each bone segment (pelvis, thigh L, thigh R) with Gaussian falloff (σ≈15cm), normalize. Fast, scriptable, fuzzier than the cone.
## 3. Multi-layer shrinkwrap pitfalls
Three issues:
**(a) Offset vs. low-poly faceting.** At 1500 tris, facet normals deviate from the true surface; 68mm along vertex normals can still poke through at facet edges on curved regions (bust, scapula, glutes). Use `wrap_mode='NEAREST_SURFACE'` with offset, and keep the shrinkwrap **target** high-poly (original MD mesh or Lena's 25k body), not the decimated garment. Apply shrinkwrap before decimation (Q1).
**(b) Layer-to-layer wrapping.** Don't shrinkwrap the bow to the body — it'll sit inside the bodice. Stack: bow → bodice (offset = bodice thickness + 1mm), bodice → body (offset = 68mm). Or wrap all to body with cumulative offsets (body+6mm, body+10mm, body+14mm) — simpler to script but breaks if layers aren't concentric.
**(c) Self-intersection at boundaries.** Where bow meets bodice, low-poly faceting causes z-fighting. Add 12mm depth_bias per layer in Godot material, or ensure geometric offset exceeds the low-poly facet amplitude (~2mm at 1500 tris on a 30cm-radius curve).
Also: shrinkwrap inverts normals on concave regions (armpits, under-bust). After applying, run `bpy.ops.mesh.normals_make_consistent(inside=False)` and check for flipped faces.
## 4. Re-posing sleeves to T-pose (v2)
Two scripted options:
**(a) Rigid rotation (fast, OK for slight arms-down ~3045°):** detect sleeve vertices by material or bbox (|X| beyond shoulder ± threshold). Shoulder pivot = Lena's `upper_arm_L/R` bone head. Build rotation matrix: axis = forward (Y), angle = -(current_arm_angle 90°). Apply via `mesh.transform(matrix, vertex_group='sleeve_L')`. Fine if sleeves are near-cylindrical; test the cap — if it kinks, use (b).
**(b) 2-bone armature per sleeve (cleaner):** create a 3-bone chain (shoulder→elbow→wrist) per arm along the sleeve's medial axis (PCA on sleeve vertices, or sample). Parent sleeve vertices to nearest bone with `bpy.ops.object.parent_set(type='ARMATURE_AUTO')` restricted to the sleeve vertex group. Rotate elbow+wrist to bring cuff to T-pose height. `bpy.ops.pose.armature_apply(selected=False)`, apply armature modifier. Preserves sleeve length and cap shape.
For "slightly arms-down", (a) is ~10 lines of script. For full A-pose or reaching, use (b). Pitfall: if the jacket torso has shoulder wrinkles from the arms-down pose, rigid rotation leaves them — they'll bake into the normal map, which may be fine.
## 5. Baking normals/AO at 1.5k tris
Worth it. At 1500 tris, geometric pleats are noise; normal-map pleats read as pleats. AO grounds the garment. Do it.
Workflow notes for MD unwelded sources:
- **UVs**: MD gives per-panel islands (one per pattern piece). After welding they're still clean — good. But decimated low-poly UVs will distort. **Create a second UV map** ("bake_uv") on the low-poly, `bpy.ops.uv.smart_project(angle_limit=1.15)`, bake to that. Keep original MD UVs as UV1 for future texture work. Godot 4.7 supports 2 UV channels.
- **Normals**: MD unwelded output has inconsistent normals across seams. On the high-poly: `mesh.normals_make_consistent(inside=False)`, then `mesh.smooth_normals()`. Bake `type='NORMAL'`, `space='TANGENT'`, `use_selected_to_active=True`, `cage_extrusion=0.00050.001` (0.51mm). Cycles.
- **AO**: bake separately, `type='AO'`, `samples=64`. Multiply in shader at 0.50.7. Or bake Combined with world light disabled for AO+curvature in one texture.
- **Layer bleed**: multi-layer cloth — bake each layer separately with others hidden, or cage_extrusion < layer separation. MD layers are 25mm apart; use cage_extrusion=1mm.
- **Color**: flat MD material colors → assign directly as base color on the low-poly material. No bake needed. One material per part: base color + normal map + AO multiply.
Texture size: 512² for bodice/bow, 512×1024 for skirt (pleats need vertical resolution). 1500-tri parts don't justify 2K.
## 6. Overall plan critique
Do differently:
**(a) Reorder: fit before decimate, bake after decimate.** Current plan decimates then fits. Pipeline should be: split → weld → (build proxy for skirt) → fit high-poly to body → decimate → bake high→low → weight transfer → export. This is the biggest issue.
**(b) Per-part tri budget should vary.** 1500 for bow is wasteful; 1500 for skirt is starving. Suggest: bow 300500, bodice 10001200, skirt 20002500. If 1500 is a hard total-per-character crowd budget, state it as a total and allocate.
**(c) Poke-through is under-addressed.** 68mm offset on 1500-tri garments in walk/dance will poke at crotch, armpits, under-bust, and back of skirt during forward leg swing. Build an **inner shell**: a 35mm inflated copy of Lena's body; shrinkwrap garments to the shell, not the body. Test in the in-game test bed immediately after weight transfer, not at the end.
**(d) Weight transfer: use Data Transfer (Nearest Surface), not KDTree nearest-vertex, for body-conforming parts.** KDTree is fine for the snug bodice but fails on overhangs (collar, bow tails) where the nearest body vertex is on the wrong side. KDTree is also non-deterministic at equidistant vertices — add a lowest-index tiebreak if you keep it.
**(e) Shrinkwrap mask must be scripted.** Build the "fit influence" vertex group from world-Z relative to pelvis bone head: 1.0 above waist, linear ramp to 0.0 at hip-crotch height. Don't hand-paint in a headless pipeline.
**(f) Missing: LOD strategy.** 1500 tris is LOD0 for a hero, LOD1 for crowd. If crowd-scale, plan LOD2 (400500 tris) with aggressive decimate + no normal map. Mention now even if deferred.
**(g) Missing: determinism audit.** KDTree, Smart UV Project, and auto-weights have non-deterministic corners. Pin `bpy.context.scene.cycles.seed` and `random.seed`, and add a regression check: hash exported GLB vertex positions; fail the pipeline if the hash changes between runs on the same input.
**(h) 12 materials → 3 parts: verify contiguity.** MD sometimes assigns multiple materials to one panel (trim + shell). After splitting, check `bmesh` connectivity; if a "part" has >1 connected component, merge materials or split further.
**(i) Test bed timing.** After weight transfer, do a quick GLB round-trip into Godot with the walk cycle before finalizing bake/export. Catch tearing early — don't wait until the end.