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>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
# Armhole-scoop sweep for topTest1. Diagnostic, exports nothing.
|
||||
#
|
||||
# python tools/md_bridge.py --file tools/tailor/md_pari_armsweep.py --timeout 880
|
||||
#
|
||||
# HYPOTHESIS (Jeremy's): the persistent diagonal crease across the back is surplus
|
||||
# WIDTH bunching where the two panels meet. The numbers say he's right, but not at
|
||||
# the bust or hem — those are matched:
|
||||
# bust 570 + 510 = 1080 vs bust 1083 (matched)
|
||||
# hem 380 + 320 = 700 vs waist 675 (+25 ease)
|
||||
# The surplus is ABOVE the bust. The panels stay near-full width up to the armhole
|
||||
# while the body narrows, giving ~968 mm of cloth around a much smaller torso at
|
||||
# underarm height. And the side seam only runs y 0..185, so above that the front and
|
||||
# back edges are FREE — nothing stops the surplus from overlapping and pushing a
|
||||
# diagonal fold across the back, which is exactly where the crease sits.
|
||||
#
|
||||
# Fix under test: a concave ARMHOLE SCYE. Insert one mid-point per armhole, pulled
|
||||
# inward by ARM, so the upper panel narrows without touching bust width, hem taper,
|
||||
# or strap position (moving the straps would re-expose the body's baked-in bra
|
||||
# straps, which is the whole reason the straps exist).
|
||||
#
|
||||
# Inserting points SHIFTS THE LINE INDICES, so indices are computed here rather than
|
||||
# hardcoded — hardcoded 0/5/7/9 has bitten this recipe twice already.
|
||||
#
|
||||
# 4 values x Simulate(250) ~= 4 min. PLAIN so shape is judged, not motif.
|
||||
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 = 350.0
|
||||
SCOOP_FRONT, SCOOP_BACK = 105.0, 15.0
|
||||
SIDE_Y = 185.0
|
||||
TAPER = 95.0
|
||||
ARM_H = 70.0 # mid-point sits ARM_H above SIDE_Y, i.e. y = 255
|
||||
SWEEP = [0.0, 30.0, 55.0, 80.0] # mm pulled inward per side. 0 == current shape.
|
||||
SIDE_FLAGS = (True, True)
|
||||
SHOULDER_FLAGS = (False, False)
|
||||
ARR_X = 50
|
||||
|
||||
report = {"combos": {}, "hypothesis": "surplus width ABOVE the bust, free edges above SIDE_Y"}
|
||||
|
||||
def build(width, scoop, dx, arm):
|
||||
"""Return (pattern_id, idx) where idx names the line indices we must sew."""
|
||||
c = width / 2.0
|
||||
pts = [(c - 210.0, TOP - 25.0), # 0 strapL_outer
|
||||
(c - 120.0, TOP), # 1 strapL_inner line0 = SHOULDER_L
|
||||
(c - 70.0, TOP - scoop * 0.75), # 2 neck
|
||||
(c, TOP - scoop), # 3 neck
|
||||
(c + 70.0, TOP - scoop * 0.75), # 4 neck
|
||||
(c + 120.0, TOP), # 5 strapR_inner line5 = SHOULDER_R
|
||||
(c + 210.0, TOP - 25.0)] # 6 strapR_outer
|
||||
if arm:
|
||||
pts.append((width - arm, SIDE_Y + ARM_H)) # 7 armhole R mid (concave scye)
|
||||
pts += [(width, SIDE_Y), # sideR_top
|
||||
(width - TAPER, 0.0), # hemR
|
||||
(TAPER, 0.0), # hemL
|
||||
(0.0, SIDE_Y)] # sideL_top
|
||||
if arm:
|
||||
pts.append((arm, SIDE_Y + ARM_H)) # armhole L mid
|
||||
# line i runs pts[i] -> pts[i+1]; derive the seam indices from the layout
|
||||
n_arm = 1 if arm else 0
|
||||
side_r = 6 + n_arm + 1 # sideR_top -> hemR
|
||||
hem = side_r + 1
|
||||
side_l = hem + 1 # hemL -> sideL_top
|
||||
idx = {"shoulder_l": 0, "shoulder_r": 5, "side_r": side_r, "side_l": side_l,
|
||||
"hem": hem, "n_points": len(pts)}
|
||||
pid = pattern_api.CreatePatternWithPoints([(x + dx, y, 0) for (x, y) in pts])
|
||||
return pid, idx
|
||||
|
||||
for arm in SWEEP:
|
||||
key = "arm%02d" % int(arm)
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
|
||||
pf, ixf = build(W_FRONT, SCOOP_FRONT, 0.0, arm)
|
||||
pb, ixb = build(W_BACK, SCOOP_BACK, 900.0, arm)
|
||||
|
||||
pattern_api.AddSeamlinePairGroup(pf, ixf["shoulder_l"], pb, ixb["shoulder_l"], *SHOULDER_FLAGS)
|
||||
pattern_api.AddSeamlinePairGroup(pf, ixf["shoulder_r"], pb, ixb["shoulder_r"], *SHOULDER_FLAGS)
|
||||
pattern_api.AddSeamlinePairGroup(pf, ixf["side_r"], pb, ixb["side_r"], *SIDE_FLAGS)
|
||||
pattern_api.AddSeamlinePairGroup(pf, ixf["side_l"], pb, ixb["side_l"], *SIDE_FLAGS)
|
||||
|
||||
# Verify the computed indices actually point at the edges we think: shoulders
|
||||
# ~93 mm, sides ~208 mm. If these drift, the index math is wrong, not the cloth.
|
||||
lens = {k: [round(pattern_api.GetLineLength(pf, ixf[k]), 1),
|
||||
round(pattern_api.GetLineLength(pb, ixb[k]), 1)]
|
||||
for k in ("shoulder_l", "shoulder_r", "side_r", "side_l")}
|
||||
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
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, ARR_X, 55, 50)
|
||||
pattern_api.SetArrangementPosition(pb, ARR_X, 55, 50)
|
||||
utility_api.ResetClothArrangement()
|
||||
|
||||
ok = utility_api.Simulate(250)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
shots = export_api.ExportTurntableImages(4)
|
||||
saved = {}
|
||||
for i, label in ((0, "front"), (2, "back")):
|
||||
if i < len(shots) and os.path.exists(shots[i]):
|
||||
dst = os.path.join(tempfile.gettempdir(),
|
||||
"tinqs_armsweep_%s_%s.png" % (key, label))
|
||||
shutil.copyfile(shots[i], dst)
|
||||
saved[label] = dst
|
||||
report["combos"][key] = {"sim": ok, "arm": arm, "idx_front": ixf,
|
||||
"seam_lengths": lens, "shots": saved}
|
||||
|
||||
result = report
|
||||
Reference in New Issue
Block a user