Files
animation/tools/tailor/md_pari_seamsweep.py
T
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

88 lines
4.0 KiB
Python

# Seam-flag sweep for the top (topTest1 / pari). Diagnostic, exports nothing.
#
# python tools/md_bridge.py --file tools/tailor/md_pari_seamsweep.py --timeout 880
#
# WHY: the untextured back render shows the back panel rucked up with its REVERSE
# FACE exposed. Reverse faces mean the seam is twisting the panel, not that there is
# surplus cloth — so the fix is the seam pairing, not the pattern.
#
# md_pari.py sews same-index with (False, False). The skill's rule is "pair the same
# line index on MIRRORED front/back panels with (False, False)" — but these panels
# are NOT mirrored: both are the identical point list, only offset by dx. Sewing
# front-right to back-right on non-mirrored panels needs one edge traversed in
# REVERSE, which is what the two booleans do. md_piupiu_v3.py sidesteps this by
# pairing right<->left, which is equivalent to a reversal — and it drapes clean.
#
# Sweeps the two flags on the SIDE seams only, keeping shoulders at (False, False)
# since the front and shoulder line look correct. Also tested separately and
# DISPROVED: crossing every pair (7<->9 AND 0<->5) makes the garment slide to the
# hips, because cross-wired straps cancel and it falls off the shoulders.
#
# 4 combos x Simulate(200) ~= 3 min. Reads back the turntable rear frame per combo.
import os
import shutil
import tempfile
AVATAR_FBX = r"C:\Users\Jeremy\tinqs\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
W_FRONT, W_BACK = 570.0, 510.0
TOP, TOP_BACK = 350.0, 350.0 # both full height — isolate the seam flags
SCOOP_FRONT, SCOOP_BACK = 105.0, 45.0
SIDE_Y = 185.0
COMBOS = [(False, False), (False, True), (True, False), (True, True)]
report = {"combos": {}}
def panel(width, scoop, dx, top):
c = width / 2.0
pts = [(c - 210.0, top - 25.0), (c - 120.0, top),
(c - 70.0, top - scoop * 0.75), (c, top - scoop),
(c + 70.0, top - scoop * 0.75), (c + 120.0, top), (c + 210.0, top - 25.0),
(width, SIDE_Y), (width, 0.0), (0.0, 0.0), (0.0, SIDE_Y)]
return pattern_api.CreatePatternWithPoints([(x + dx, y, 0) for (x, y) in pts])
for fa, fb in COMBOS:
key = "%s_%s" % (int(fa), int(fb))
utility_api.NewProject() # also deletes the avatar
op = ApiTypes.ImportExportOption()
op.scale = 10.0
op.bAddArrangementPoints = True
op.bAutoTranslate = True
import_api.ImportFBX(AVATAR_FBX, op)
pf = panel(W_FRONT, SCOOP_FRONT, 0.0, TOP)
pb = panel(W_BACK, SCOOP_BACK, 900.0, TOP_BACK)
for line in (0, 5): # shoulders: leave alone
pattern_api.AddSeamlinePairGroup(pf, line, pb, line, False, False)
for line in (7, 9): # sides: the variable under test
pattern_api.AddSeamlinePairGroup(pf, line, pb, line, fa, fb)
fab = fabric_api.AddFabric(ZFAB) # PLAIN — judge shape, not motif
for p in (pf, pb):
pattern_api.SetPatternPieceFabricIndex(p, fab)
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
for a in pattern_api.GetArrangementList()}
pattern_api.SetArrangement(pf, arr["Body_Front_Center_1"])
pattern_api.SetArrangement(pb, arr["Body_Back_Center_1"])
pattern_api.SetArrangementPosition(pf, 50, 55, 50)
pattern_api.SetArrangementPosition(pb, 0, 55, 50)
utility_api.ResetClothArrangement()
ok = utility_api.Simulate(200)
utility_api.Refresh3DWindow()
shots = export_api.ExportTurntableImages(4) # 0 front, 1 side, 2 BACK, 3 side
saved = {}
for idx, label in ((0, "front"), (2, "back")):
if idx < len(shots) and os.path.exists(shots[idx]):
dst = os.path.join(tempfile.gettempdir(),
"tinqs_seamsweep_%s_%s.png" % (key, label))
shutil.copyfile(shots[idx], dst) # turntable reuses output*.png names
saved[label] = dst
report["combos"][key] = {"sim": ok, "flags": [fa, fb], "shots": saved}
result = report