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>
9.2 KiB
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 8–10° 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, 28–32 segments, 3–4 vertical loops, knee length, denser waistband ring. ShrinkwrapModifier(wrap_mode='NEAREST_SURFACE', offset=0.002–0.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 6–8mm 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 5–7mm and reduce pleat segment counts before sim — gives a 50–100k 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:
- 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.
- 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. - Transfer cone→skirt:
DataTransferModifier(vert_mapping='NEAREST_SURFACE', layers='ALL'), apply, thenbpy.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; 6–8mm 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 = 6–8mm). 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 1–2mm 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 ~30–45°): 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), thenmesh.smooth_normals(). Baketype='NORMAL',space='TANGENT',use_selected_to_active=True,cage_extrusion=0.0005–0.001(0.5–1mm). Cycles. - AO: bake separately,
type='AO',samples=64. Multiply in shader at 0.5–0.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 2–5mm 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 300–500, bodice 1000–1200, skirt 2000–2500. If 1500 is a hard total-per-character crowd budget, state it as a total and allocate.
(c) Poke-through is under-addressed. 6–8mm 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 3–5mm 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 (400–500 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.