tailor(voyager): strapless bandeau lane -- elastic-free zero-g recipe + 23-variant work log
Female voyager bandeau top from the fc-voyager-kilt-gpt refs. Winning construction (md_final_v16/v23): seamless-loop doctrine -- NO edge elastic (gathering is what notched the armpit junctions), body-snug cut, zero-g wrap (SetSimulationGravity(0) BEFORE ResetClothArrangement -- one full-gravity materialization tick drops the bistable tube into the low basin), stiff 40f positioning then soft 110f conform, self-measuring retry loop. Hard-won facts logged in the scripts: strapless garments never survive full gravity (frictionless skin + stretchy elastic); arrangement x IS azimuth (Body_Back_Center_1 native x=0, forcing 50/50 sews both panels into a front pouch); SetArrangementOrientation flips panel facing but mirrors it L/R; frozen cloth renders cyan; back panel textured face points at the skin -- fix is manual Flip Normal (no API). Texture: positioned plait/rope/fringe tile spanning the 170mm panel once (hem anchors at v=0.5 and wraps). manual_fit_backup.zprj preserves Can's hand-fitted drape. Exports still pending final drape approval. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
make_voyager_bandeau.py -- golden plaited-weave band with black rope trim and
|
||||
fringe for the female voyager bandeau top (lena_voyager_bandeau_v1).
|
||||
|
||||
python tools/tailor/textures/make_voyager_bandeau.py
|
||||
|
||||
Derived from the reference renders
|
||||
`fc-voyager-kilt-gpt-piece-top{,-front,-back}.png` (docs repo): a diagonal
|
||||
basket plait in warm golden tan, a black braided-rope band near each edge, and
|
||||
a short strand fringe extending to both the top and bottom edges.
|
||||
|
||||
POSITIONED TILE, same doctrine as make_kilt_cloth.py: spans the bandeau
|
||||
panel's full 170 mm height exactly once (dpi = SIZE / (170 / 25.4)), so every
|
||||
zone lands at a fixed garment height:
|
||||
|
||||
garment y (mm, hem=0) zone
|
||||
0-15 bottom fringe strands (painted, not geometry -- v1)
|
||||
15-27 black rope band (braided chevrons)
|
||||
27-143 diagonal basket plait
|
||||
143-155 black rope band
|
||||
155-170 top fringe strands (tips ragged toward y=170)
|
||||
|
||||
Horizontally the 170 mm tile repeats ~3.2x across the 550 mm panel; the plait
|
||||
pitch (17 mm) and rope chevron pitch (32 px) both divide the tile exactly, so
|
||||
the wrap is seamless.
|
||||
|
||||
IF THE ROPE BANDS RENDER SWAPPED TOP-FOR-BOTTOM, MD anchored the texture the
|
||||
other way up -- regenerate with FLIP=True rather than touching the pattern.
|
||||
(Anchor per probe 2026-08-18: pattern y=0 (hem) maps to image v=0.5 and wraps.)
|
||||
|
||||
Albedo baked in (pipeline has no alpha, texture replaces base color), warm
|
||||
ramp r>g>b, deterministic LCG noise.
|
||||
"""
|
||||
import os
|
||||
|
||||
from PIL import Image
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(HERE, "voyager_bandeau.png")
|
||||
|
||||
SIZE = 1024 # px, square
|
||||
CLOTH_MM = 170.0 # spans the bandeau panel height exactly once
|
||||
DPI = SIZE / (CLOTH_MM / 25.4)
|
||||
FLIP = False # set True if MD anchors the texture upside-down
|
||||
PX_PER_MM = SIZE / CLOTH_MM
|
||||
|
||||
# zone boundaries in garment mm (hem = 0)
|
||||
BOT_FRINGE_TOP = 15.0
|
||||
BOT_ROPE_TOP = 27.0
|
||||
TOP_ROPE_BOT = 143.0
|
||||
TOP_FRINGE_BOT = 155.0
|
||||
|
||||
PLAIT_PITCH_MM = 17.0 # strand pitch; 170/17 = 10 cells -> seamless wrap
|
||||
ROPE_CHEVRON_PX = 32 # divides 1024 -> seamless wrap
|
||||
|
||||
BASE = (203, 165, 110) # golden tan plait (reference lit mean ~(200,165,115))
|
||||
ROPE = (46, 40, 32) # near-black rope, warm
|
||||
ROPE_HI = (92, 80, 62) # braid ridge highlight
|
||||
FRINGE = (191, 152, 100)
|
||||
FRINGE_GAP = (140, 108, 70)
|
||||
SHADOW = (74, 60, 44) # past a fringe tip: painted shadow (no alpha in lane)
|
||||
|
||||
OVER_LIFT = 14
|
||||
UNDER_DROP = 18
|
||||
ROUND_SHADE = 12
|
||||
SLUB_RANGE = 8
|
||||
MOTTLE = 10
|
||||
MOTTLE_CELL = 64
|
||||
|
||||
|
||||
def lcg(seed):
|
||||
state = seed
|
||||
while True:
|
||||
state = (1103515245 * state + 12345) % (2 ** 31)
|
||||
yield state / float(2 ** 31)
|
||||
|
||||
|
||||
def value_noise(cells, seed):
|
||||
g = lcg(seed)
|
||||
grid = [[(next(g) * 2.0 - 1.0) for _ in range(cells + 1)] for _ in range(cells + 1)]
|
||||
|
||||
def sample(x, y):
|
||||
fx, fy = x * cells / SIZE, y * cells / SIZE
|
||||
x0, y0 = int(fx), int(fy)
|
||||
tx, ty = fx - x0, fy - y0
|
||||
tx, ty = tx * tx * (3 - 2 * tx), ty * ty * (3 - 2 * ty)
|
||||
a = grid[y0][x0] * (1 - tx) + grid[y0][x0 + 1] * tx
|
||||
b = grid[y0 + 1][x0] * (1 - tx) + grid[y0 + 1][x0 + 1] * tx
|
||||
return a * (1 - ty) + b * ty
|
||||
|
||||
return sample
|
||||
|
||||
|
||||
def mm_from_row(y):
|
||||
"""Garment height in mm for an image row (anchor: hem -> v=0.5, wraps)."""
|
||||
v = (y + 0.5) / SIZE
|
||||
return CLOTH_MM - CLOTH_MM * ((v - 0.5) % 1.0)
|
||||
|
||||
|
||||
def plait(xm, ym, slub_a, slub_b):
|
||||
"""Diagonal basket plait: two +/-45-degree strand families, over-under.
|
||||
Returns a brightness delta to apply on BASE."""
|
||||
u = (xm + ym) / PLAIT_PITCH_MM
|
||||
w = (xm - ym) / PLAIT_PITCH_MM
|
||||
a, b = int(u // 1), int(w // 1)
|
||||
fu, fw = u - a, w - b
|
||||
over_a = ((a + b) % 2) == 0
|
||||
if over_a:
|
||||
# family A on top: rounded across its width (fw), slub along it
|
||||
c = abs(fw - 0.5) * 2.0
|
||||
d = OVER_LIFT - int(ROUND_SHADE * c * c)
|
||||
d += slub_a[a % len(slub_a)]
|
||||
if fw < 0.06 or fw > 0.94: # crevice against the under strand
|
||||
d -= 26
|
||||
else:
|
||||
c = abs(fu - 0.5) * 2.0
|
||||
d = OVER_LIFT - int(ROUND_SHADE * c * c) - UNDER_DROP // 2
|
||||
d += slub_b[b % len(slub_b)]
|
||||
if fu < 0.06 or fu > 0.94:
|
||||
d -= 26
|
||||
return d
|
||||
|
||||
|
||||
def main():
|
||||
g = lcg(20260818)
|
||||
slub_a = [int((next(g) * 2.0 - 1.0) * SLUB_RANGE) for _ in range(64)]
|
||||
slub_b = [int((next(g) * 2.0 - 1.0) * SLUB_RANGE) for _ in range(64)]
|
||||
tip_noise = [next(g) for _ in range(64)]
|
||||
mottle = value_noise(SIZE // MOTTLE_CELL, seed=777)
|
||||
|
||||
img = Image.new("RGB", (SIZE, SIZE))
|
||||
px = img.load()
|
||||
|
||||
strand_w = 16 # fringe strand width px (~2.7 mm)
|
||||
for y in range(SIZE):
|
||||
mm = mm_from_row(y)
|
||||
ym = mm
|
||||
for x in range(SIZE):
|
||||
xm = x / PX_PER_MM
|
||||
wear = int(mottle(x, y) * MOTTLE)
|
||||
|
||||
if mm < BOT_FRINGE_TOP or mm > TOP_FRINGE_BOT:
|
||||
# fringe: vertical strands, ragged tips toward the edge
|
||||
sid = (x // strand_w) % len(tip_noise)
|
||||
ragged = tip_noise[sid] * 8.0
|
||||
past_tip = (mm < ragged if mm < BOT_FRINGE_TOP
|
||||
else mm > CLOTH_MM - ragged)
|
||||
if past_tip:
|
||||
base, d = SHADOW, wear // 2
|
||||
else:
|
||||
u = x % strand_w
|
||||
base = FRINGE_GAP if u < 2 else FRINGE
|
||||
d = slub_a[sid] + wear
|
||||
elif mm < BOT_ROPE_TOP or mm > TOP_ROPE_BOT:
|
||||
# braided rope: diagonal chevron ridges
|
||||
phase = ((x + int(mm * PX_PER_MM) * 2) % ROPE_CHEVRON_PX) \
|
||||
/ float(ROPE_CHEVRON_PX)
|
||||
base = ROPE_HI if phase < 0.30 else ROPE
|
||||
d = wear // 2
|
||||
else:
|
||||
base = BASE
|
||||
d = plait(xm, ym, slub_a, slub_b) + wear
|
||||
|
||||
r = base[0] + d
|
||||
gg = base[1] + int(d * 0.82)
|
||||
b = base[2] + int(d * 0.66)
|
||||
px[x, y] = (max(0, min(255, r)), max(0, min(255, gg)),
|
||||
max(0, min(255, b)))
|
||||
|
||||
if FLIP:
|
||||
img = img.transpose(Image.FLIP_TOP_BOTTOM)
|
||||
img.save(OUT, dpi=(DPI, DPI))
|
||||
print("wrote %s (%dx%d, dpi %.2f -> %.0f mm of cloth; ropes %d-%d & %d-%d mm, "
|
||||
"fringe 0-%d & %d-%d mm)"
|
||||
% (OUT, SIZE, SIZE, DPI, CLOTH_MM, BOT_FRINGE_TOP, BOT_ROPE_TOP,
|
||||
TOP_ROPE_BOT, TOP_FRINGE_BOT, BOT_FRINGE_TOP, TOP_FRINGE_BOT, CLOTH_MM))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "voyager_bandeau_v1",
|
||||
"_worksheet": {
|
||||
"block": "custom strapless band (fitted_top numbers, no straps)",
|
||||
"reference": "docs/conceptart/generated-images/female-clothing/fc-voyager-kilt-gpt-piece-top*.png",
|
||||
"placement": {"band_top_z": 1.31, "hem_z": 1.14, "tol_m": 0.03},
|
||||
"body_circ_mm": {"bust_max": 1083.4, "at_top_1.31": 917.4, "at_hem_1.14": 794.4},
|
||||
"ease_mm": 17,
|
||||
"panel": "hexagon: bust-width waist at y=123.6, tapered to snug top and hem",
|
||||
"hold_mechanism": "top edge cut 467 vs 550 needed to clear the bust; elastic cinch mid-settle (strength 60 -- default never reaches target)",
|
||||
"lines": {"top": 0, "side_r_up": 1, "side_r_low": 2, "hem": 3, "side_l_low": 4, "side_l_up": 5},
|
||||
"strapless_rationale": "reference has no straps; skill says straps-beat-tubes, but a tube can only slide down by stretching its 467mm top edge over the 550mm bust -- geometry blocks it. If QC shows it slid to the underbust anyway, v2 adds straps."
|
||||
},
|
||||
"md": {
|
||||
"reset": "new_project",
|
||||
"avatar_fbx": "C:/Users/CAN/tinqs-ltd/animation/tools/tailor/avatar/Lena_QuatSkin_Avatar.fbx",
|
||||
"avatar_scale": 10.0,
|
||||
"add_arrangement_points": true,
|
||||
"auto_translate": true,
|
||||
"zfab": "C:/Users/Public/Documents/MarvelousDesigner/New Assets/Fabric/(Default for Simulation).zfab",
|
||||
"texture": "C:/Users/CAN/tinqs-ltd/animation/tools/tailor/textures/voyager_bandeau.png",
|
||||
"panels": [
|
||||
{"name": "front", "dx": 0.0,
|
||||
"note": "strapless band: W 550.2 at bust (circ 1083.4 + ease 17), top 467.2, hem 405.7, H 170",
|
||||
"points": [[41.5, 170.0], [508.7, 170.0], [550.2, 123.6], [478.0, 0.0], [72.2, 0.0], [0.0, 123.6]]},
|
||||
{"name": "back", "dx": 800.2,
|
||||
"note": "identical panel; lines 0 top | 1 sideR-up | 2 sideR-low | 3 hem | 4 sideL-low | 5 sideL-up",
|
||||
"points": [[41.5, 170.0], [508.7, 170.0], [550.2, 123.6], [478.0, 0.0], [72.2, 0.0], [0.0, 123.6]]}
|
||||
],
|
||||
"seams": [
|
||||
{"a": "front", "a_line": 1, "b": "back", "b_line": 1, "reverse_a": true, "reverse_b": true},
|
||||
{"a": "front", "a_line": 2, "b": "back", "b_line": 2, "reverse_a": true, "reverse_b": true},
|
||||
{"a": "front", "a_line": 4, "b": "back", "b_line": 4, "reverse_a": true, "reverse_b": true},
|
||||
{"a": "front", "a_line": 5, "b": "back", "b_line": 5, "reverse_a": true, "reverse_b": true}
|
||||
],
|
||||
"arrangements": [
|
||||
{"panel": "front", "point": "Body_Front_Center_1", "offset": [50, 55, 50]},
|
||||
{"panel": "back", "point": "Body_Back_Center_1", "offset": [50, 55, 50]}
|
||||
],
|
||||
"sim": {
|
||||
"strengthen": true,
|
||||
"settle_frames": 250,
|
||||
"elastic": [
|
||||
{"panel": "front", "line": 0, "total_length": 450.0, "strength": 60},
|
||||
{"panel": "back", "line": 0, "total_length": 450.0, "strength": 60},
|
||||
{"panel": "front", "line": 3, "total_length": 390.0, "strength": 60},
|
||||
{"panel": "back", "line": 3, "total_length": 390.0, "strength": 60}
|
||||
],
|
||||
"elastic_frames": 80,
|
||||
"relax_frames": 50
|
||||
},
|
||||
"cam_viewpoint": 2,
|
||||
"presim_snapshot": "C:/Users/CAN/AppData/Local/Temp/claude/C--Users-CAN-tinqs-ltd-docs/3744fd8e-1342-446c-9677-7aafbafc8d18/scratchpad/voyager_bandeau_presim.png",
|
||||
"snapshot": "C:/Users/CAN/AppData/Local/Temp/claude/C--Users-CAN-tinqs-ltd-docs/3744fd8e-1342-446c-9677-7aafbafc8d18/scratchpad/voyager_bandeau_front.png",
|
||||
"back_snapshot": "C:/Users/CAN/AppData/Local/Temp/claude/C--Users-CAN-tinqs-ltd-docs/3744fd8e-1342-446c-9677-7aafbafc8d18/scratchpad/voyager_bandeau_back.png",
|
||||
"export_dir": "C:/Users/CAN/tinqs-ltd/animation/tools/tailor",
|
||||
"export_basename": "lena_voyager_bandeau_v1",
|
||||
"exports": []
|
||||
},
|
||||
"expect": {
|
||||
"bands": {
|
||||
"voyager_bandeau_v1": {"top_m": 1.31, "bottom_m": 1.14, "tol_m": 0.03, "from": "cover"}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
Binary file not shown.
@@ -0,0 +1,133 @@
|
||||
# FINAL v10: BACK SCOOP -- the construction fix for the back-edge flip.
|
||||
#
|
||||
# Every sim-side variant (v8 stiff, B brief-soften, C half-solidify) flips or rolls
|
||||
# the back panel's top edge, because at 1.31 m the back edge lands ON the baked-in
|
||||
# bra's back-band ridge: collision pushes it off and it folds. The reference back
|
||||
# sits LOWER between the shoulder blades anyway. Fix in the outline (never partial
|
||||
# seams): scoop the back top edge down 32 mm at the centre; the side edges are
|
||||
# untouched so all four seam pairs still fingerprint equal.
|
||||
#
|
||||
# Back top edge becomes 4 segments (lines 0-3); side/hem line indices shift +3.
|
||||
# No elastic on the scooped back top (it is below the ridge and shorter by cut);
|
||||
# front top + both hems keep the v8 elastic. Sim recipe = v8 (zero-g, stiff 60,
|
||||
# soften front only, 90).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
# back: same corners, top edge scooped 24/32/24 mm at 35%/50%/65% of the top span
|
||||
PTS_B = [(41.5, 170.0), (181.5, 146.0), (275.1, 138.0), (368.7, 146.0),
|
||||
(508.7, 170.0), (550.2, 123.6), (478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
# front lines: 0 top | 1 sideR_up | 2 sideR_low | 3 hem | 4 sideL_low | 5 sideL_up
|
||||
# back lines: 0-3 scooped top | 4 sideR_up | 5 sideR_low | 6 hem | 7 sideL_low | 8 sideL_up
|
||||
SEAMS = [(1, 4), (2, 5), (4, 7), (5, 8)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe10.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, True, True)
|
||||
|
||||
# fingerprint the pairs -- unequal seam edges are a construction bug
|
||||
_bad = []
|
||||
results["seam_lengths"] = []
|
||||
for lf, lb in SEAMS:
|
||||
fa = pattern_api.GetLineLength(f, lf)
|
||||
fb = pattern_api.GetLineLength(b, lb)
|
||||
results["seam_lengths"].append((lf, round(fa, 3), lb, round(fb, 3)))
|
||||
if abs(fa - fb) > 0.1:
|
||||
_bad.append("f.%d=%.3f vs b.%d=%.3f" % (lf, fa, lb, fb))
|
||||
if _bad:
|
||||
raise RuntimeError("seam length mismatch: " + "; ".join(_bad))
|
||||
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50)
|
||||
|
||||
# elastic: front top (line 0) + both hems (front 3, back 6); scooped back top bare
|
||||
pattern_api.SetPatternPieceElastic(f, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(f, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(f, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(f, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(f, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(f, 3, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(b, 6, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(b, 6, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(b, 6, 60.0)
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60) # stiff positioning
|
||||
pattern_api.SetPatternStrengthen(f, False) # soften only the front
|
||||
utility_api.Simulate(90)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final10_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final10_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final10_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,139 @@
|
||||
# FINAL v10: BACK SCOOP -- the construction fix for the back-edge flip.
|
||||
#
|
||||
# Every sim-side variant (v8 stiff, B brief-soften, C half-solidify) flips or rolls
|
||||
# the back panel's top edge, because at 1.31 m the back edge lands ON the baked-in
|
||||
# bra's back-band ridge: collision pushes it off and it folds. The reference back
|
||||
# sits LOWER between the shoulder blades anyway. Fix in the outline (never partial
|
||||
# seams): scoop the back top edge down 32 mm at the centre; the side edges are
|
||||
# untouched so all four seam pairs still fingerprint equal.
|
||||
#
|
||||
# Back top edge becomes 4 segments (lines 0-3); side/hem line indices shift +3.
|
||||
# No elastic on the scooped back top (it is below the ridge and shorter by cut);
|
||||
# front top + both hems keep the v8 elastic. Sim recipe = v8 (zero-g, stiff 60,
|
||||
# soften front only, 90).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
# back: same corners, top edge scooped 24/32/24 mm at 35%/50%/65% of the top span
|
||||
PTS_B = [(41.5, 170.0), (181.5, 146.0), (275.1, 138.0), (368.7, 146.0),
|
||||
(508.7, 170.0), (550.2, 123.6), (478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
# front lines: 0 top | 1 sideR_up | 2 sideR_low | 3 hem | 4 sideL_low | 5 sideL_up
|
||||
# back lines: 0-3 scooped top | 4 sideR_up | 5 sideR_low | 6 hem | 7 sideL_low | 8 sideL_up
|
||||
SEAMS = [(1, 4), (2, 5), (4, 7), (5, 8)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe11.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, True, True)
|
||||
|
||||
# fingerprint the pairs -- unequal seam edges are a construction bug
|
||||
_bad = []
|
||||
results["seam_lengths"] = []
|
||||
for lf, lb in SEAMS:
|
||||
fa = pattern_api.GetLineLength(f, lf)
|
||||
fb = pattern_api.GetLineLength(b, lb)
|
||||
results["seam_lengths"].append((lf, round(fa, 3), lb, round(fb, 3)))
|
||||
if abs(fa - fb) > 0.1:
|
||||
_bad.append("f.%d=%.3f vs b.%d=%.3f" % (lf, fa, lb, fb))
|
||||
if _bad:
|
||||
raise RuntimeError("seam length mismatch: " + "; ".join(_bad))
|
||||
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 78, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 78, 50)
|
||||
|
||||
# elastic: front top (line 0) + both hems (front 3, back 6); scooped back top bare
|
||||
pattern_api.SetPatternPieceElastic(f, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(f, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(f, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(f, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(f, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(f, 3, 60.0)
|
||||
# v11: the scooped back top needs its own anchor -- v10 (bare scoop) slid 10 cm.
|
||||
# Segment cut lengths 142/93.9/93.9/142; cinch to ~0.93.
|
||||
for _ln, _tl in ((0, 132.0), (1, 87.0), (2, 87.0), (3, 132.0)):
|
||||
pattern_api.SetPatternPieceElastic(b, _ln, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(b, _ln, _tl)
|
||||
pattern_api.SetPatternPieceElasticStrength(b, _ln, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(b, 6, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(b, 6, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(b, 6, 60.0)
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60) # stiff positioning
|
||||
pattern_api.SetPatternStrengthen(f, False) # soften only the front
|
||||
utility_api.Simulate(90)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final11_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final11_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final11_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,95 @@
|
||||
# FINAL v13: TWO FABRICS -- back panel on Tyvek (board-stiff MATERIAL), front on
|
||||
# the default sim fabric. Every strengthen-based recipe folds the back at the bra
|
||||
# ridge because SetPatternStrengthen is a solver constraint, not bending stiffness;
|
||||
# the crease forms during the phase-1 seam pull and survives. Tyvek resists the
|
||||
# crease itself. Back is NOT strengthened (material does the work), front keeps
|
||||
# the proven stiff-then-soft phases. Ends UNFROZEN (texture visible; don't press play).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB_SOFT = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
ZFAB_STIFF = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\V2_Non-Fabric_Tyvek_1.zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
|
||||
fab_soft = fabric_api.AddFabric(ZFAB_SOFT)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab_soft)
|
||||
fab_stiff = fabric_api.AddFabric(ZFAB_STIFF)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab_stiff)
|
||||
pattern_api.SetPatternPieceFabricIndex(f, fab_soft)
|
||||
pattern_api.SetPatternPieceFabricIndex(b, fab_stiff)
|
||||
for p in (f, b):
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 78, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True) # front: proven stiff-then-soft
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
utility_api.Simulate(90)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
path = os.path.join(SCRATCH, "_probe13.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
results["final"] = {"bottom_m": round(zmin * 0.001, 4), "top_m": round(zmax * 0.001, 4),
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final13_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final13_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final13_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
# UNFROZEN on purpose: Can inspects with texture; nothing simulates unless play is pressed
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab_soft,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,97 @@
|
||||
# FINAL v13: TWO FABRICS -- back panel on Tyvek (board-stiff MATERIAL), front on
|
||||
# the default sim fabric. Every strengthen-based recipe folds the back at the bra
|
||||
# ridge because SetPatternStrengthen is a solver constraint, not bending stiffness;
|
||||
# the crease forms during the phase-1 seam pull and survives. Tyvek resists the
|
||||
# crease itself. Back is NOT strengthened (material does the work), front keeps
|
||||
# the proven stiff-then-soft phases. Ends UNFROZEN (texture visible; don't press play).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB_SOFT = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
ZFAB_STIFF = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\V2_Non-Fabric_Tyvek_1.zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
|
||||
fab_soft = fabric_api.AddFabric(ZFAB_SOFT)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab_soft)
|
||||
fab_stiff = fabric_api.AddFabric(ZFAB_STIFF)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab_stiff)
|
||||
pattern_api.SetPatternPieceFabricIndex(f, fab_soft)
|
||||
pattern_api.SetPatternPieceFabricIndex(b, fab_stiff)
|
||||
pattern_api.SetAddlThicknessCollision(f, 2.0)
|
||||
pattern_api.SetAddlThicknessCollision(b, 8.0) # glide over the bra ridge during the wrap
|
||||
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 78, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True) # front: proven stiff-then-soft
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetAddlThicknessCollision(b, 3.0) # now settle against the skin
|
||||
utility_api.Simulate(40)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
path = os.path.join(SCRATCH, "_probe14.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
results["final"] = {"bottom_m": round(zmin * 0.001, 4), "top_m": round(zmax * 0.001, 4),
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final14_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final14_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final14_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
# UNFROZEN on purpose: Can inspects with texture; nothing simulates unless play is pressed
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab_soft,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,102 @@
|
||||
# FINAL v15: match the reference's construction truth -- a SEAMLESS RIGID LOOP.
|
||||
#
|
||||
# Reference re-read (fc-voyager-kilt-gpt-piece-top-front.png): continuous band,
|
||||
# NO visible side seams, NO gathering, level edges, standing slightly proud of the
|
||||
# body like stiff basketry. Every "connection point" artifact at the armpits came
|
||||
# from the elastic: two independent edge-drawstrings meeting at a seam corner
|
||||
# always notch and curl there.
|
||||
#
|
||||
# So: NO elastic anywhere. The cut is already body-snug (top 934 mm circ vs 917 mm
|
||||
# body), and in zero-g nothing needs holding up. Seam tension + collision form the
|
||||
# smooth proud oval. Two conform styles swept in one call:
|
||||
# A_soft everything soft, zero-g 150 f
|
||||
# B_stiff stiff 40 f (clean positioning) -> soften both, 110 f
|
||||
# Judge: underarm junction on the side turntables + spans. Ends UNFROZEN.
|
||||
#
|
||||
# (Known cosmetic issue left alone: the back panel's textured face points at the
|
||||
# skin -- no API can flip it; right-click the back panel in 3D > Flip Normal, or
|
||||
# let the Blender pass recalculate normals.)
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def build():
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0) # proud of the skin, like the ref
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 78, 50)
|
||||
return f, b
|
||||
|
||||
|
||||
def measure_and_shoot(tag):
|
||||
utility_api.Refresh3DWindow()
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe15.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v15_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
# A_soft: everything soft from frame 0, weightless
|
||||
f, b = build()
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(150)
|
||||
results["A_soft"] = measure_and_shoot("A_soft")
|
||||
|
||||
# B_stiff: stiff positioning, then both soften and conform
|
||||
f, b = build()
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
results["B_stiff"] = measure_and_shoot("B_stiff")
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
# scene ends holding B_stiff, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,83 @@
|
||||
# FINAL v16: v15's clean no-elastic seamless-loop recipe + height calibration.
|
||||
# v15 proved the reference-matching construction (no elastic, no gathering, smooth
|
||||
# proud band, clean underarm junctions) but the tube slides ~0.11 m down the torso
|
||||
# taper during the weightless conform. Calibrate arrangement height: two cells,
|
||||
# keep the closer one in scene. Ends UNFROZEN (do not press play).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def build(front_y, back_y):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, front_y, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, back_y, 50)
|
||||
return f, b
|
||||
|
||||
|
||||
def measure_and_shoot(tag):
|
||||
utility_api.Refresh3DWindow()
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe16.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v16_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
for tag, fy, by in (("H74", 74, 82),): # calibrated winner -- leave in scene
|
||||
f, b = build(fy, by)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
results[tag] = measure_and_shoot(tag)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
# scene ends holding H88, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,98 @@
|
||||
# FINAL v17: v16's elastic-free recipe + the BACK PANEL BUILT WITH REVERSED
|
||||
# 2D WINDING -- Can's diagnosis: "backside tailored backwards". MD orients a
|
||||
# draped panel's front face from its 2D winding, so the back panel (which the
|
||||
# Body_Back arrangement turns 180 degrees toward the body) ended up textured-face-in.
|
||||
# Reversing its point order flips the face outward at build time; no flip API needed.
|
||||
#
|
||||
# Seam mapping with reversed back winding (same physical edges, new indices):
|
||||
# front 1 sideR_up <-> back 4 sideR_up front 2 sideR_low <-> back 3 sideR_low
|
||||
# front 4 sideL_low <-> back 1 sideL_low front 5 sideL_up <-> back 0 sideL_up
|
||||
# Flags: front keeps its proven reversal (True); the back's natural traversal now
|
||||
# matches what (True,True) used to produce, so back flag is False -> (True, False).
|
||||
# A wrong flag shows as a twist -- judge from the snapshots.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
PTS_B = list(reversed(PTS_F))
|
||||
PTS_B = PTS_B[-1:] + PTS_B[:-1] # start at (41.5,170) like the front
|
||||
# back lines: 0 sideL_up | 1 sideL_low | 2 hem | 3 sideR_low | 4 sideR_up | 5 top
|
||||
SEAMS = [(1, 4), (2, 3), (4, 1), (5, 0)]
|
||||
|
||||
results = {"pts_back": PTS_B}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, True, False)
|
||||
|
||||
_bad = []
|
||||
results["seam_lengths"] = []
|
||||
for lf, lb in SEAMS:
|
||||
fa = pattern_api.GetLineLength(f, lf)
|
||||
fb = pattern_api.GetLineLength(b, lb)
|
||||
results["seam_lengths"].append((lf, round(fa, 3), lb, round(fb, 3)))
|
||||
if abs(fa - fb) > 0.1:
|
||||
_bad.append("f.%d=%.3f vs b.%d=%.3f" % (lf, fa, lb, fb))
|
||||
if _bad:
|
||||
raise RuntimeError("seam length mismatch: " + "; ".join(_bad))
|
||||
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 74, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
path = os.path.join(SCRATCH, "_probe17.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
results["final"] = {"bottom_m": round(zmin * 0.001, 4), "top_m": round(zmax * 0.001, 4),
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v17_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results[view] = dst
|
||||
|
||||
# UNFROZEN; do not press play
|
||||
result = results
|
||||
@@ -0,0 +1,83 @@
|
||||
# FINAL v18: reversed-winding back panel (textured face OUT -- proven by v17's
|
||||
# bright back) + seam-flag sweep. v17's (True, False) crossed the back into an X.
|
||||
# MD's reverse flags do not behave like simple traversal reversal (the tooling
|
||||
# table shows (True,True) != (False,False) on identical panels), so sweep the
|
||||
# remaining combos empirically: (False, True), (False, False), (True, True).
|
||||
# Recipe otherwise = v16 winner: no elastic, zero-g, stiff 40 + soft 110, y 74/82.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
_r = list(reversed(PTS_F))
|
||||
PTS_B = _r[-1:] + _r[:-1]
|
||||
SEAMS = [(1, 4), (2, 3), (4, 1), (5, 0)]
|
||||
|
||||
|
||||
def run_cell(tag, rev_a, rev_b):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, rev_a, rev_b)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 74, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe18.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v18_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
results["FT"] = run_cell("FT", False, True)
|
||||
results["FF"] = run_cell("FF", False, False)
|
||||
results["TT"] = run_cell("TT", True, True)
|
||||
# scene ends holding TT, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,89 @@
|
||||
# FINAL v19: v16's proven clean construction (identical winding, (True,True) seams,
|
||||
# no elastic) + SetArrangementOrientation on the BACK panel to face its textured
|
||||
# side OUTWARD. v17/v18 proved reversed winding twists with every flag combo; the
|
||||
# facing must come from the ARRANGEMENT, not the pattern. Introspect the setter's
|
||||
# doc, flip the back panel's orientation (180 -> 0), verify with a presim turntable
|
||||
# before simulating.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
results = {"orient_doc": pattern_api.SetArrangementOrientation.__doc__}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 74, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
|
||||
# flip the back panel's facing at the arrangement level (front keeps its default 180)
|
||||
try:
|
||||
pattern_api.SetArrangementOrientation(b, 0)
|
||||
results["orient_set"] = True
|
||||
except Exception as exc:
|
||||
results["orient_set"] = "failed: %r" % (exc,)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
dst = os.path.join(SCRATCH, "v19_presim_back.png")
|
||||
shutil.copyfile(_tt[2], dst)
|
||||
results["presim_back"] = dst
|
||||
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
path = os.path.join(SCRATCH, "_probe19.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
results["final"] = {"bottom_m": round(zmin * 0.001, 4), "top_m": round(zmax * 0.001, 4)}
|
||||
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v19_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results[view] = dst
|
||||
|
||||
# UNFROZEN; do not press play
|
||||
result = results
|
||||
@@ -0,0 +1,131 @@
|
||||
# FINAL v2: pure zero-g wrap, no gravity pass at all.
|
||||
#
|
||||
# md_final_zerog.py showed even 45 frames at 0.1 g slides the band 16 cm. But the
|
||||
# reference garment is stiff plaited basketry -- it should NOT have gravity folds;
|
||||
# the elastic cinch wrinkles are the right surface detail. So: wrap weightless at
|
||||
# the correct height, freeze, done. offset-y mapping measured: 55 -> mid 1.172,
|
||||
# 70 -> mid 1.269, 85 -> mid 1.326; target mid 1.225 -> y ~62.
|
||||
import os
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
TARGET_MID = (1.31 + 1.14) / 2.0
|
||||
|
||||
|
||||
def build(arr_y):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, arr_y, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, arr_y, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 430.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 380.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
return f, b
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe4.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {"cells": {}}
|
||||
best = None
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
for arr_y in (60, 62, 65):
|
||||
f, b = build(arr_y)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(80)
|
||||
# brief soften so the plait relaxes against the skin (still weightless)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(30)
|
||||
lo, hi = span()
|
||||
mid = round((lo + hi) / 2.0, 4)
|
||||
results["cells"][arr_y] = {"bottom_m": lo, "top_m": hi, "mid_m": mid}
|
||||
if best is None or abs(mid - TARGET_MID) < abs(best[1] - TARGET_MID):
|
||||
best = (arr_y, mid, f, b, lo, hi)
|
||||
if abs(mid - TARGET_MID) <= 0.015:
|
||||
break # good enough; keep this scene
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0) # restore; NEVER simulate after
|
||||
|
||||
# If the loop ended on a non-best cell, rebuild the best one (weightless again).
|
||||
arr_y, mid, f, b, lo, hi = best
|
||||
if results["cells"].get(arr_y) is None or list(results["cells"])[-1] != arr_y:
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
f, b = build(arr_y)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(80)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(30)
|
||||
lo, hi = span()
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
results["final"] = {"arr_y": arr_y, "bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final2_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
|
||||
import shutil
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final2_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final2_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,85 @@
|
||||
# FINAL v20: back panel = arrangement orientation 0 (bright face out, proven v19)
|
||||
# + horizontally MIRRORED 2D pattern to compensate the L/R swap that the vertical-
|
||||
# axis orientation spin introduces (v19: tube tilted, front panel pulled up to the
|
||||
# collarbone). Mirrored coords need REMAPPED seam indices (tooling 3.3); the table
|
||||
# says mirrored+remapped takes (False, False) -- sweep (False,False) and (True,True).
|
||||
#
|
||||
# back (mirrored) lines: 0 top | 1 sideL_up | 2 sideL_low | 3 hem | 4 sideR_low | 5 sideR_up
|
||||
# pairs: front1(sideR_up)<->back5, front2(sideR_low)<->back4,
|
||||
# front4(sideL_low)<->back2, front5(sideL_up)<->back1
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
PTS_B = [(550.2 - x, y) for (x, y) in PTS_F] # horizontal mirror, same order
|
||||
SEAMS = [(1, 5), (2, 4), (4, 2), (5, 1)]
|
||||
|
||||
|
||||
def run_cell(tag, rev):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, rev, rev)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 74, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
pattern_api.SetArrangementOrientation(b, 0) # bright face out (proven v19)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe20.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v20_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
results["FF"] = run_cell("FF", False)
|
||||
results["TT"] = run_cell("TT", True)
|
||||
# scene ends holding TT, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,80 @@
|
||||
# FINAL v21: v20-FF construction (mirrored back + orientation 0 + remapped seams,
|
||||
# (False,False)) -- back is PERFECT. Only defect: the tube tilts front-high (~8 cm,
|
||||
# front panel at the collarbone). Calibrate the FRONT arrangement y down; back stays 82.
|
||||
# Two cells, winner stays in scene UNFROZEN.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
PTS_B = [(550.2 - x, y) for (x, y) in PTS_F]
|
||||
SEAMS = [(1, 5), (2, 4), (4, 2), (5, 1)]
|
||||
|
||||
|
||||
def run_cell(tag, front_y):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, False, False)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, front_y, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
pattern_api.SetArrangementOrientation(b, 0)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe21.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v21_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
results["F70"] = run_cell("F70", 70)
|
||||
results["F72"] = run_cell("F72", 72)
|
||||
# scene ends holding F64, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,83 @@
|
||||
# FINAL v22: the front-height system is BISTABLE (bust deflects the tube over or
|
||||
# under; y=70 slips low, y=72 catches high -- no stable middle by start height).
|
||||
# Fix: start from the HIGH catch (y=72) and bias it down with a FEW PERCENT of
|
||||
# gravity at the end -- the bust ledge stops it exactly where a real bandeau sits.
|
||||
# Cells: bias -300 and -600 mm/s^2 (3% / 6% g), 50 frames each. Winner stays.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS_F = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
PTS_B = [(550.2 - x, y) for (x, y) in PTS_F]
|
||||
SEAMS = [(1, 5), (2, 4), (4, 2), (5, 1)]
|
||||
|
||||
|
||||
def run_cell(tag, bias):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS_F])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS_B])
|
||||
for lf, lb in SEAMS:
|
||||
pattern_api.AddSeamlinePairGroup(f, lf, b, lb, False, False)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 72, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
pattern_api.SetArrangementOrientation(b, 0)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(70) # conform at the high catch
|
||||
utility_api.SetSimulationGravity(bias) # gentle downward bias
|
||||
utility_api.Simulate(50)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe22.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v22_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
results["g300"] = run_cell("g300", -300.0)
|
||||
results["g600"] = run_cell("g600", -600.0)
|
||||
# scene ends holding g600, UNFROZEN (do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,81 @@
|
||||
# FINAL v23: v16-H74 recipe + SELF-MEASURING RETRY LOOP. The elastic-free tube's
|
||||
# final height is BISTABLE and lands non-deterministically run-to-run (same script
|
||||
# gave 1.08-1.32 twice, then 1.01-1.19). Rebuild until the garment top lands in
|
||||
# [1.27, 1.35] m, max 6 attempts, keep the good drape in scene UNFROZEN.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
results = {"attempts": []}
|
||||
ok = False
|
||||
for attempt in range(6):
|
||||
# CRITICAL: zero gravity BEFORE the scene is built. ResetClothArrangement
|
||||
# materializes cloth with a solver tick; under full gravity that one tick
|
||||
# biases the bistable tube into the LOW basin (the cross-session mystery).
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 3.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 74, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 82, 50)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement() # gravity already zero (see above)
|
||||
try:
|
||||
utility_api.Simulate(40)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(110)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
path = os.path.join(SCRATCH, "_probe23.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
span = (round(zmin * 0.001, 4), round(zmax * 0.001, 4))
|
||||
results["attempts"].append(span)
|
||||
if 1.27 <= span[1] <= 1.35:
|
||||
ok = True
|
||||
break
|
||||
|
||||
results["accepted"] = ok
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "v23_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results[view] = dst
|
||||
|
||||
# UNFROZEN; do not press play. Back panel face: right-click > Flip Normal (manual).
|
||||
result = results
|
||||
@@ -0,0 +1,102 @@
|
||||
# FINAL v3: stiff-only zero-g wrap.
|
||||
#
|
||||
# v2 defects and their causes:
|
||||
# - cyan/white band in renders = MD's FROZEN display tint -> snapshot BEFORE freezing
|
||||
# - crumpled top edge + back panel ballooning off the back = the 30-frame soften:
|
||||
# weightless soft cloth has nothing pressing its middle to the body. The garment
|
||||
# is stiff plaited basketry -- stay strengthened for the WHOLE wrap.
|
||||
# - 2 mm collision stand-off for a clean skin offset.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe5.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 65, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 65, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 430.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 380.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
pattern_api.SetPatternStrengthen(p, True) # stiff the WHOLE wrap
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(140) # weightless wrap + cinch
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0) # restore; never simulate after
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
# snapshots BEFORE freezing (frozen cloth renders cyan)
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final3_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final3_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final3_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,101 @@
|
||||
# FINAL v4: SOFT zero-g wrap -- the winning recipe.
|
||||
#
|
||||
# probe_1_zerog.png (soft + elastic, weightless, 60f) already read like the
|
||||
# reference: plait + rope bands + fringe all visible, band conformed to the chest.
|
||||
# The stiff wrap (v3) tents off the bust and juts at the sides; the soften-after-
|
||||
# stiff (v2) crumples. Soft-from-frame-0 is SAFE here because the bunching rule
|
||||
# exists for gravity, and there is none. 150 frames for a tighter cinch, y=68 to
|
||||
# center the band on target (measured map: 55->1.172, 65->1.218, 70->1.269).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe6.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 68, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 430.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 380.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
# NO strengthen: soft conforms; safe under zero-g (bunching needs gravity)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(150)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final4_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final4_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final4_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,104 @@
|
||||
# FINAL v5: soft zero-g wrap, elastic targets = body circumference (NOT smaller).
|
||||
# v4 taught: an over-tight ring (430 vs 459 body) cannot grip in zero-g frictionless
|
||||
# contact -- it is EXPELLED off the torso like a squeezed seed and floats as a pouch
|
||||
# in front of the chest. Snug-not-tight keeps the ring seated where it is placed.
|
||||
#
|
||||
# probe_1_zerog.png (soft + elastic, weightless, 60f) already read like the
|
||||
# reference: plait + rope bands + fringe all visible, band conformed to the chest.
|
||||
# The stiff wrap (v3) tents off the bust and juts at the sides; the soften-after-
|
||||
# stiff (v2) crumples. Soft-from-frame-0 is SAFE here because the bunching rule
|
||||
# exists for gravity, and there is none. 150 frames for a tighter cinch, y=68 to
|
||||
# center the band on target (measured map: 55->1.172, 65->1.218, 70->1.269).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe6.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 68, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 465.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 402.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
# NO strengthen: soft conforms; safe under zero-g (bunching needs gravity)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(120)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final5_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final5_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final5_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,104 @@
|
||||
# FINAL v5: soft zero-g wrap, elastic targets = body circumference (NOT smaller).
|
||||
# v4 taught: an over-tight ring (430 vs 459 body) cannot grip in zero-g frictionless
|
||||
# contact -- it is EXPELLED off the torso like a squeezed seed and floats as a pouch
|
||||
# in front of the chest. Snug-not-tight keeps the ring seated where it is placed.
|
||||
#
|
||||
# probe_1_zerog.png (soft + elastic, weightless, 60f) already read like the
|
||||
# reference: plait + rope bands + fringe all visible, band conformed to the chest.
|
||||
# The stiff wrap (v3) tents off the bust and juts at the sides; the soften-after-
|
||||
# stiff (v2) crumples. Soft-from-frame-0 is SAFE here because the bunching rule
|
||||
# exists for gravity, and there is none. 150 frames for a tighter cinch, y=68 to
|
||||
# center the band on target (measured map: 55->1.172, 65->1.218, 70->1.269).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe6.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50) # x IS azimuth: back panel at its native x=0, NOT 50
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 465.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 402.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
# NO strengthen: soft conforms; safe under zero-g (bunching needs gravity)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(120)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final6_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final6_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final6_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,102 @@
|
||||
# FINAL v7: correct azimuth (back x=0) + two-phase weightless wrap.
|
||||
# v6 made a true tube (front reads like the reference) but the back panel kept a
|
||||
# fold-over and a drooping corner from being soft during the whole wrap. Phase it:
|
||||
# 1. STIFF 60 f zero-g -- panels take position cleanly, no corner folds
|
||||
# 2. soften + 90 f zero-g -- cloth conforms to the skin (no gravity, no slide)
|
||||
# Cinch slightly tighter (450/390 @ 60): safe now that the ring encircles the body.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe7.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50) # x IS azimuth; back native x=0
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
pattern_api.SetPatternStrengthen(p, True)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60) # phase 1: stiff positioning
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(90) # phase 2: soft conform, weightless
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final7_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final7_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final7_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,101 @@
|
||||
# FINAL v7: correct azimuth (back x=0) + two-phase weightless wrap.
|
||||
# v6 made a true tube (front reads like the reference) but the back panel kept a
|
||||
# fold-over and a drooping corner from being soft during the whole wrap. Phase it:
|
||||
# 1. STIFF 60 f zero-g -- panels take position cleanly, no corner folds
|
||||
# 2. soften + 90 f zero-g -- cloth conforms to the skin (no gravity, no slide)
|
||||
# Cinch slightly tighter (450/390 @ 60): safe now that the ring encircles the body.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe7.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50) # x IS azimuth; back native x=0
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
pattern_api.SetPatternStrengthen(p, True)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60) # phase 1: stiff positioning
|
||||
pattern_api.SetPatternStrengthen(f, False) # soften ONLY the front (v7: the
|
||||
utility_api.Simulate(90) # soft back rolled its top edge)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final8_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final8_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final8_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,100 @@
|
||||
# FINAL v7: correct azimuth (back x=0) + two-phase weightless wrap.
|
||||
# v6 made a true tube (front reads like the reference) but the back panel kept a
|
||||
# fold-over and a drooping corner from being soft during the whole wrap. Phase it:
|
||||
# 1. STIFF 60 f zero-g -- panels take position cleanly, no corner folds
|
||||
# 2. soften + 90 f zero-g -- cloth conforms to the skin (no gravity, no slide)
|
||||
# Cinch slightly tighter (450/390 @ 60): safe now that the ring encircles the body.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe7.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50) # x IS azimuth; back native x=0
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
pattern_api.SetPatternStrengthen(p, True)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(150) # ALL-stiff wrap: basketry stays basketry
|
||||
# (v3 tenting was the wrong azimuth, not stiffness)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final9_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final9_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final9_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r" % (exc,)
|
||||
|
||||
TINQS_GARMENT = {"garment": "voyager_bandeau_v1", "fabric": fab,
|
||||
"patterns": {"front": f, "back": b}}
|
||||
result = results
|
||||
@@ -0,0 +1,137 @@
|
||||
# FINAL RECIPE: shaped-in-place strapless bandeau (no full-gravity exposure).
|
||||
#
|
||||
# Probe findings (md_probe_slide.py): MD cloth-skin contact is ~frictionless and
|
||||
# elastic edges stretch under load, so NO strapless band survives -9800 gravity on
|
||||
# this body -- it rides over the bust by stretching (30 frames: chest -> hips).
|
||||
# Even 0.1 g slides it. Straps are the physical fix but the reference has none, and
|
||||
# the deliverable is a STATIC export for the clothing pipeline -- so the drape is a
|
||||
# shaping tool, not a stability proof:
|
||||
#
|
||||
# 1. sweep arrangement offset-y under a zero-g wrap to land the band on target
|
||||
# (y=55 landed 1.078-1.287; target 1.14-1.31 -> need ~+4 cm)
|
||||
# 2. rebuild at the best y: stiff zero-g wrap 80f -> soften, 0.1 g for 45f (folds
|
||||
# form, slide ~2-4 cm only) -> restore full gravity WITHOUT simulating
|
||||
# 3. freeze the patterns (best effort) so a stray UI play won't drop it
|
||||
#
|
||||
# Numbers target: band top 1.31 m, hem 1.14 m, tol 0.03.
|
||||
import os
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
TARGET_MID = (1.31 + 1.14) / 2.0
|
||||
|
||||
|
||||
def build(arr_y):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, arr_y, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, arr_y, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 430.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 380.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
return f, b
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe3.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
results = {"sweep": {}}
|
||||
|
||||
# --- part 1: offset-y sweep under a pure zero-g wrap ------------------------
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
for arr_y in (55, 70, 85):
|
||||
f, b = build(arr_y)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(60)
|
||||
lo, hi = span()
|
||||
results["sweep"][arr_y] = {"bottom_m": lo, "top_m": hi,
|
||||
"mid_m": round((lo + hi) / 2.0, 4)}
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
best_y = min(results["sweep"],
|
||||
key=lambda k: abs(results["sweep"][k]["mid_m"] - TARGET_MID))
|
||||
results["best_y"] = best_y
|
||||
|
||||
# --- part 2: final shape at best_y ------------------------------------------
|
||||
f, b = build(best_y)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(80) # weightless wrap + cinch, stiff
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.SetSimulationGravity(-980.0) # 0.1 g: folds without the slide
|
||||
utility_api.Simulate(45)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0) # restore; do NOT simulate again
|
||||
|
||||
# best-effort freeze so a stray UI play won't drop the band
|
||||
try:
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternFreeze(p, True)
|
||||
results["frozen"] = True
|
||||
except Exception as exc:
|
||||
results["frozen"] = "failed: %r (doc: %s)" % (exc, pattern_api.SetPatternFreeze.__doc__)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = span()
|
||||
results["final"] = {"bottom_m": lo, "top_m": hi,
|
||||
"target": {"bottom_m": 1.14, "top_m": 1.31, "tol_m": 0.03}}
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "final_front.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_snap"] = snap
|
||||
|
||||
import shutil
|
||||
_tt = export_api.ExportTurntableImages(4) # 0 front, 1 side, 2 BACK, 3 side
|
||||
if _tt and len(_tt) > 2:
|
||||
back = os.path.join(SCRATCH, "final_back.png")
|
||||
shutil.copyfile(_tt[2], back)
|
||||
results["back_snap"] = back
|
||||
side = os.path.join(SCRATCH, "final_side.png")
|
||||
shutil.copyfile(_tt[1], side)
|
||||
results["side_snap"] = side
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,30 @@
|
||||
# 1. Backup Can's manual state (zprj) BEFORE any change.
|
||||
# 2. FlipPatternPiece on the back panel -- its reverse face points outward, which
|
||||
# MD renders dull/dark ("under a shadow"). Introspect the doc first.
|
||||
# 3. Snapshot to verify. NO sim, NO rebuild.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
BACKUP = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\work\voyager_bandeau_v1\manual_fit_backup.zprj"
|
||||
|
||||
results = {}
|
||||
export_api.ExportZPrj(BACKUP)
|
||||
results["backup"] = BACKUP
|
||||
results["flip_doc"] = pattern_api.FlipPatternPiece.__doc__
|
||||
|
||||
try:
|
||||
pattern_api.FlipPatternPiece(1) # back panel
|
||||
results["flipped"] = True
|
||||
except Exception as exc:
|
||||
results["flipped"] = "failed: %r" % (exc,)
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "flip_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results[view] = dst
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,45 @@
|
||||
# INSPECT + MINIMAL FIX after Can's MANUAL fitting pass. His drape is sacred:
|
||||
# NO NewProject, NO Simulate, NO arrangement calls, NO freeze.
|
||||
# 1. snapshot the CURRENT state (front + full turntable) before touching anything
|
||||
# 2. report patterns + their fabric indices
|
||||
# 3. fix the "shadowed back": reassign the back panel to the front's fabric
|
||||
# (v14 gave the back Tyvek, whose PBR renders darker) -- appearance only
|
||||
# 4. snapshot again for comparison
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
|
||||
results = {}
|
||||
n = pattern_api.GetPatternCount()
|
||||
results["pattern_count"] = n
|
||||
results["fabrics_before"] = [pattern_api.GetPatternPieceFabricIndex(i) for i in range(n)]
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "manual_front_before.png")
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results["front_before"] = snap
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "manual_before_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results["before_" + view] = dst
|
||||
|
||||
# ---- fix the shadowed back: give the back panel the FRONT panel's fabric ----
|
||||
# pattern 0 = front, 1 = back (created in that order by every recipe)
|
||||
if n >= 2:
|
||||
fab_front = pattern_api.GetPatternPieceFabricIndex(0)
|
||||
pattern_api.SetPatternPieceFabricIndex(1, fab_front)
|
||||
results["fabrics_after"] = [pattern_api.GetPatternPieceFabricIndex(i) for i in range(n)]
|
||||
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "manual_after_%s.png" % view)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results["after_" + view] = dst
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,66 @@
|
||||
# PROBE: where do the two panels actually START, and how do they move in zero-g?
|
||||
# Turntable (front/side/back/side) at 0 frames, then after 30 zero-g frames.
|
||||
# Suspicion: the BACK panel is not behind the body at all, so every "tube" was
|
||||
# really two panels sewing themselves into a bag in front of the chest.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 68, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 465.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 402.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Refresh3DWindow()
|
||||
results = {}
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, tag in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "arrange0_%s.png" % tag)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results["presim_" + tag] = dst
|
||||
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(30)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, tag in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "arrange30_%s.png" % tag)
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
results["f30_" + tag] = dst
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,69 @@
|
||||
# PROBE: why is the back panel in FRONT? Dump Body_* arrangement entries, then
|
||||
# sweep the back panel's arrangement (point name and offset z) with 0-frame
|
||||
# turntable side shots. No simulation -- placement only.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
results = {}
|
||||
|
||||
# one throwaway import just to read the arrangement table
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
full = pattern_api.GetArrangementList()
|
||||
results["entry_keys"] = sorted(full[0].keys()) if full else []
|
||||
results["body_entries"] = [e for e in full
|
||||
if "Body" in str(e.get("ArrangementName", ""))][:40]
|
||||
|
||||
CELLS = [
|
||||
("bp_z50", "Body_Back_Center_1", (50, 68, 50)),
|
||||
("bp_zneg", "Body_Back_Center_1", (50, 68, -50)),
|
||||
("bp_z150", "Body_Back_Center_1", (50, 68, 150)),
|
||||
]
|
||||
|
||||
for tag, point, (ox, oy, oz) in CELLS:
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
if point not in arr:
|
||||
results[tag] = "POINT %r NOT IN LIST" % point
|
||||
continue
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr[point])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, ox, oy, oz)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Refresh3DWindow()
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
cell = {}
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "bp_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
cell[view] = dst
|
||||
results[tag] = cell
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,104 @@
|
||||
# PROBE: where exactly does the bandeau escape? Three checkpoints, snapshots + spans.
|
||||
# 1. after a 60-frame zero-g wrap+cinch (is it actually snug at the chest?)
|
||||
# 2. after 30 frames of full gravity (has it moved? how far?)
|
||||
# 3. after 60 more frames (where does it end up?)
|
||||
# Also probes a LOW-gravity settle as a candidate fix in the same session.
|
||||
import os
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def build():
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 55, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 55, 50)
|
||||
return f, b
|
||||
|
||||
|
||||
def set_elastic(p, line, total, strength):
|
||||
pattern_api.SetPatternPieceElastic(p, line, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, line, total)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, line, strength)
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe2.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
def shoot(tag):
|
||||
utility_api.Refresh3DWindow()
|
||||
utility_api.SetCamViewPoint(2)
|
||||
p = os.path.join(SCRATCH, "probe_%s.png" % tag)
|
||||
export_api.ExportSnapshot3D(p)
|
||||
lo, hi = span()
|
||||
return {"bottom_m": lo, "top_m": hi, "snap": p}
|
||||
|
||||
|
||||
results = {}
|
||||
|
||||
# --- part 1: checkpointed failure ------------------------------------------
|
||||
f, b = build()
|
||||
for p in (f, b):
|
||||
set_elastic(p, 0, 430.0, 60.0)
|
||||
set_elastic(p, 3, 380.0, 60.0)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60)
|
||||
results["1_after_zerog_wrap"] = shoot("1_zerog")
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Simulate(30)
|
||||
results["2_gravity_30f"] = shoot("2_g30")
|
||||
utility_api.Simulate(60)
|
||||
results["3_gravity_90f"] = shoot("3_g90")
|
||||
|
||||
# --- part 2: candidate fix -- LOW gravity settle after the zero-g wrap ------
|
||||
f, b = build()
|
||||
for p in (f, b):
|
||||
set_elastic(p, 0, 430.0, 60.0)
|
||||
set_elastic(p, 3, 380.0, 60.0)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60)
|
||||
utility_api.SetSimulationGravity(-980.0) # 1/10 g: folds form, slide force 10x smaller
|
||||
utility_api.Simulate(120)
|
||||
results["4_lowg_settle"] = shoot("4_lowg")
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,162 @@
|
||||
# GENERATED by tools/tailor/draft_garment.py -- DO NOT EDIT.
|
||||
# garment : voyager_bandeau_v1
|
||||
# stage : all
|
||||
# config : C:\Users\CAN\tinqs-ltd\animation\tools\tailor\work\voyager_bandeau_v1\config.json
|
||||
# emitted : 2026-08-18T20:09:18
|
||||
# Edit the config's `md` block and re-emit; edits here are lost.
|
||||
#
|
||||
# Run inside an MD bridge session (a human must click Plugin > TinqsMDBridge first):
|
||||
# python tools/md_bridge.py --file <this file> --timeout 310
|
||||
#
|
||||
# HARD-WON MD FACTS (do not rediscover -- see tools/tailor/draft_garment.py):
|
||||
# - 2D pattern space: units are mm, +y is UP in the 3D mapping. Straps/neck at
|
||||
# HIGH y, hem at y=0. Panels built y-down drape upside-down over the head and
|
||||
# tangle -- it looks like a seam bug, it isn't.
|
||||
# - MD's 3D unit is mm (gravity -9800). Blender-exported FBX avatars land 10x
|
||||
# small -- import with op.scale = 10. ImportAvatar() is .avt only (False on FBX).
|
||||
# - op.bAddArrangementPoints = True generates the ~98 named arrangement points;
|
||||
# without it there is nowhere to hang cloth.
|
||||
# - CreatePatternWithPoints takes (x, y, type) triples, type 0 = corner. Returned
|
||||
# id is the pattern index; line i = edge point[i] -> point[i+1].
|
||||
# - Seams are WHOLE-EDGE only: AddSeamlinePairGroup(a, lineA, b, lineB, False,
|
||||
# False) with the SAME line index on mirrored front/back panels. Cross-pairing
|
||||
# sews the garment over the face. Neck gaps and armholes are extra points in
|
||||
# the outline, not partial seams.
|
||||
# - SetArrangement() only ASSIGNS; utility_api.ResetClothArrangement() APPLIES it
|
||||
# (ReDrape3DArrangement only materializes not-yet-draped cloth).
|
||||
# - Arrangement INDICES REGENERATE on every avatar import -- always look up by
|
||||
# NAME from GetArrangementList(). Offsets aren't stable either; verify with a
|
||||
# 0-frame snapshot (the diagnostic that unsticks everything).
|
||||
# - utility_api.NewProject() DELETES the avatar -- re-import after.
|
||||
# - AddFabric() needs a .zfab FILE PATH (a name string silently fails); fabric 0
|
||||
# is the shared default, coloring it dyes every garment. Assign with
|
||||
# SetPatternPieceFabricIndex -- AssignFabricToPattern() never worked.
|
||||
# - SetBaseTextureMapImageGivenFilePath(PATH, fabricIdx) -- path is arg 0.
|
||||
# - PNG DPI sets a texture's physical size in MD; control tiling via dpi in PIL.
|
||||
# - Strengthen through the WHOLE settle, relax only at the end; elastic (if any)
|
||||
# mid-settle, never from frame 0. One garment per scene.
|
||||
# - Simulate(n) is synchronous, ~1 min per 300 frames -- raise the client timeout.
|
||||
# - GetClothPositions() stays empty: no mesh introspection, QC is image-based.
|
||||
|
||||
import os
|
||||
|
||||
report = {"garment": 'voyager_bandeau_v1', "stage": 'all'}
|
||||
|
||||
# ---- scene ---------------------------------------------------------------
|
||||
utility_api.NewProject() # NOTE: this DELETES the avatar; re-import below
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0 # Blender-exported FBX lands 10x small
|
||||
op.bAddArrangementPoints = True # ~98 named points to hang cloth on
|
||||
op.bAutoTranslate = True
|
||||
report["avatar"] = import_api.ImportFBX(AVATAR_FBX, op) # ImportAvatar() is .avt only
|
||||
|
||||
# ---- pattern (mm; +y is UP in 3D -- hem at y=0, neck/straps at high y) ----
|
||||
# front: strapless band: W 550.2 at bust (circ 1083.4 + ease 17), top 467.2, hem 405.7, H 170
|
||||
_pts_p_front = [
|
||||
(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6),
|
||||
]
|
||||
p_front = pattern_api.CreatePatternWithPoints([(x + 0.0, y + 0.0, 0) for (x, y) in _pts_p_front])
|
||||
# back: identical panel; lines 0 top | 1 sideR-up | 2 sideR-low | 3 hem | 4 sideL-low | 5 sideL-up
|
||||
_pts_p_back = [
|
||||
(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6),
|
||||
]
|
||||
p_back = pattern_api.CreatePatternWithPoints([(x + 800.2, y + 0.0, 0) for (x, y) in _pts_p_back])
|
||||
report["ids"] = [p_front, p_back]
|
||||
|
||||
# ---- seams (WHOLE-EDGE only; same line index on mirrored panels) ---------
|
||||
pattern_api.AddSeamlinePairGroup(p_front, 1, p_back, 1, True, True)
|
||||
pattern_api.AddSeamlinePairGroup(p_front, 2, p_back, 2, True, True)
|
||||
pattern_api.AddSeamlinePairGroup(p_front, 4, p_back, 4, True, True)
|
||||
pattern_api.AddSeamlinePairGroup(p_front, 5, p_back, 5, True, True)
|
||||
|
||||
# Paired edges must be EQUAL, not close: a 0.075 mm 'rounding' difference was
|
||||
# a slanted edge that notched a waistband. Fail loudly BEFORE wasting a sim.
|
||||
_pairs = [(p_front, 1, p_back, 1), (p_front, 2, p_back, 2), (p_front, 4, p_back, 4), (p_front, 5, p_back, 5)]
|
||||
report["seam_lengths"] = []
|
||||
_bad = []
|
||||
for _pa, _la, _pb, _lb in _pairs:
|
||||
_fa = pattern_api.GetLineLength(_pa, _la)
|
||||
_fb = pattern_api.GetLineLength(_pb, _lb)
|
||||
report["seam_lengths"].append((_pa, _la, round(_fa, 3), _pb, _lb, round(_fb, 3)))
|
||||
if abs(_fa - _fb) > 0.1:
|
||||
_bad.append("%s.%s=%.3f vs %s.%s=%.3f" % (_pa, _la, _fa, _pb, _lb, _fb))
|
||||
if _bad:
|
||||
raise RuntimeError("seam length mismatch (construction bug, not rounding): "
|
||||
+ "; ".join(_bad))
|
||||
|
||||
# ---- fabric (never touch index 0: it is the scene-wide default) ---------
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
fab = fabric_api.AddFabric(ZFAB) # a name string silently fails
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab) # path is arg 0
|
||||
for _p in (p_front, p_back,):
|
||||
pattern_api.SetPatternPieceFabricIndex(_p, fab) # AssignFabricToPattern never worked
|
||||
|
||||
# ---- arrangement (BY NAME: indices regenerate on every avatar import) ----
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(p_front, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(p_back, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(p_front, 50, 55, 50)
|
||||
pattern_api.SetArrangementPosition(p_back, 50, 55, 50)
|
||||
|
||||
# Hand the pattern ids to a later --stage drape/publish in the SAME session.
|
||||
TINQS_GARMENT = {"garment": 'voyager_bandeau_v1', "fabric": fab, "patterns": {'front': p_front, 'back': p_back}}
|
||||
|
||||
# THE diagnostic: apply the arrangement and shoot with ZERO sim frames. It shows
|
||||
# where the panels actually start, before physics muddies it. Reach for this the
|
||||
# moment a drape misbehaves -- upside-down panels look exactly like seam bugs.
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetCamViewPoint(2) # SetViewPoint() does nothing; 2 = front
|
||||
presim_snap = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad\voyager_bandeau_presim.png"
|
||||
os.makedirs(os.path.dirname(presim_snap), exist_ok=True)
|
||||
export_api.ExportSnapshot3D(presim_snap)
|
||||
report['presim_snap'] = presim_snap
|
||||
|
||||
# ---- drape ---------------------------------------------------------------
|
||||
# Stiffen through the WHOLE settle: soft fabric from frame 0 rolls into a bunch.
|
||||
pattern_api.SetPatternStrengthen(p_front, True)
|
||||
pattern_api.SetPatternStrengthen(p_back, True)
|
||||
utility_api.ResetClothArrangement() # SetArrangement only assigns; THIS applies it
|
||||
report["sim1"] = utility_api.Simulate(250) # synchronous, ~1 min / 300 frames
|
||||
# Elastic MID-SETTLE, never from frame 0 -- elastic-first drapes cinch the
|
||||
# garment off one hip before the cloth has wrapped.
|
||||
pattern_api.SetPatternPieceElastic(p_front, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p_front, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p_front, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p_back, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p_back, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p_back, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p_front, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p_front, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p_front, 3, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p_back, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p_back, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p_back, 3, 60.0)
|
||||
report["sim_elastic"] = utility_api.Simulate(80)
|
||||
# Relax only at the end, so the settled shape falls into natural folds.
|
||||
pattern_api.SetPatternStrengthen(p_front, False)
|
||||
pattern_api.SetPatternStrengthen(p_back, False)
|
||||
report["sim2"] = utility_api.Simulate(50)
|
||||
utility_api.Refresh3DWindow()
|
||||
utility_api.SetCamViewPoint(2) # SetViewPoint() does nothing; 2 = front
|
||||
snap = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad\voyager_bandeau_front.png"
|
||||
os.makedirs(os.path.dirname(snap), exist_ok=True)
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
report['snap'] = snap
|
||||
# ExportSnapshot3D has NO rear view (SetCamViewPoint 0-7: none is the back).
|
||||
# Turntable ignores any path arg and reuses the same output names -- copy now.
|
||||
import shutil
|
||||
_tt = export_api.ExportTurntableImages(4) # 0 front, 1 side, 2 BACK, 3 side
|
||||
if _tt and len(_tt) > 2:
|
||||
back_snap = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad\voyager_bandeau_back.png"
|
||||
os.makedirs(os.path.dirname(back_snap), exist_ok=True)
|
||||
shutil.copyfile(_tt[2], back_snap)
|
||||
report["back_snapshot"] = back_snap
|
||||
else:
|
||||
report["back_snapshot"] = "TURNTABLE RETURNED NOTHING -- rear unverified"
|
||||
|
||||
result = report
|
||||
@@ -0,0 +1,127 @@
|
||||
# SWEEP 3: iron the diagonal fold out of the BACK panel (v8 = current best).
|
||||
# v8: back stiff whole wrap -> diagonal fold from phase-1 seam pull.
|
||||
# v7: back soft in phase 2 -> top edge rolled.
|
||||
# Variants (all inherit the v8 recipe otherwise: zero-g, y=68, back x=0,
|
||||
# elastic 450/390 @ 60, stiff 60f, soften front, 90f):
|
||||
# B_brief +20f with the back briefly soft at the very end (release the fold)
|
||||
# C_solid phase 2 with back at SolidifyStrengthen 0.5 (half-stiff conform)
|
||||
# D_delay elastic OFF during phase 1 (seams settle first), ON for phase 2
|
||||
# Judge: turntable BACK shot per variant + garment z-span.
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def build(with_elastic=True):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, 68, 50)
|
||||
if with_elastic:
|
||||
enable_elastic(f, b)
|
||||
return f, b
|
||||
|
||||
|
||||
def enable_elastic(f, b):
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
|
||||
|
||||
def span():
|
||||
path = os.path.join(SCRATCH, "_probe8.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
def shoot(tag):
|
||||
utility_api.Refresh3DWindow()
|
||||
out = {}
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "bf_%s_%s.png" % (tag, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
lo, hi = span()
|
||||
out["bottom_m"], out["top_m"] = lo, hi
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
# --- B_brief: v8 + 20f brief back-soften at the end ----------------------
|
||||
f, b = build()
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
utility_api.Simulate(90)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(20)
|
||||
results["B_brief"] = shoot("B_brief")
|
||||
|
||||
# --- C_solid: back at half stiffness during phase 2 ----------------------
|
||||
f, b = build()
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
pattern_api.SetPatternPieceSolidifyStrengthen(b, 0.5)
|
||||
utility_api.Simulate(90)
|
||||
results["C_solid"] = shoot("C_solid")
|
||||
|
||||
# --- D_delay: seams settle 60f stiff WITHOUT elastic, then elastic 90f ---
|
||||
f, b = build(with_elastic=False)
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(60)
|
||||
enable_elastic(f, b)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
utility_api.Simulate(90)
|
||||
results["D_delay"] = shoot("D_delay")
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,82 @@
|
||||
# SWEEP 4: lift the drooping BACK of the band. Arrangement is PER-PANEL, so the
|
||||
# back can start higher (y 78 / 85) while the front stays at its proven 68.
|
||||
# Recipe otherwise = v8 (zero-g, stiff 60, soften front only, 90, elastic 450/390).
|
||||
# Ends UNFROZEN so Can sees the texture in the viewport (freeze tint hides it).
|
||||
import os
|
||||
import shutil
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def run_cell(back_y):
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
pattern_api.SetAddlThicknessCollision(p, 2.0)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 68, 50)
|
||||
pattern_api.SetArrangementPosition(b, 0, back_y, 50)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceElastic(p, 0, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 0, 450.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 0, 60.0)
|
||||
pattern_api.SetPatternPieceElastic(p, 3, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, 3, 390.0)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, 3, 60.0)
|
||||
pattern_api.SetPatternStrengthen(p, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.SetSimulationGravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(60)
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
utility_api.Simulate(90)
|
||||
finally:
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
utility_api.Refresh3DWindow()
|
||||
|
||||
out = {}
|
||||
path = os.path.join(SCRATCH, "_probe12.obj")
|
||||
xop = ApiTypes.ImportExportOption()
|
||||
xop.bExportGarment = True
|
||||
xop.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, xop)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
zmin, zmax = min(zmin, yv), max(zmax, yv)
|
||||
out["bottom_m"], out["top_m"] = round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
_tt = export_api.ExportTurntableImages(4)
|
||||
for i, view in enumerate(("front", "side1", "back", "side2")):
|
||||
if _tt and len(_tt) > i:
|
||||
dst = os.path.join(SCRATCH, "bh_%d_%s.png" % (back_y, view))
|
||||
shutil.copyfile(_tt[i], dst)
|
||||
out[view] = dst
|
||||
return out
|
||||
|
||||
|
||||
results = {}
|
||||
results["y78"] = run_cell(78)
|
||||
results["y85"] = run_cell(85)
|
||||
# scene ends holding y85, UNFROZEN (texture visible; do not press play)
|
||||
result = results
|
||||
@@ -0,0 +1,110 @@
|
||||
# SWEEP: can the strapless voyager bandeau hold at the bust, and with which recipe?
|
||||
#
|
||||
# v1 (md_script.py) slid to the floor: 250 stiff settle frames gave gravity time to
|
||||
# push the rigid band off the chest before the elastic ever engaged. Axis swept here:
|
||||
# WHEN the elastic lands and whether the cloth is stiff or soft while it cinches.
|
||||
#
|
||||
# A_control v1 recipe verbatim -- must land on the floor or the harness is broken
|
||||
# B_early stiff 40 -> elastic (430/380 @ 60) -> 120 -> relax 40
|
||||
# C_soft stiff 40 -> soften + elastic (430/380 @ 60) -> 120
|
||||
# D_hard stiff 30 -> elastic (400/370 @ 100) -> 130 -> relax 40
|
||||
#
|
||||
# Pass/fail is read from GEOMETRY (tooling.md section 7): probe OBJ, garment z-span
|
||||
# in metres. Target: top ~1.31, bottom ~1.14 (tol 0.03). Floor = top < 0.3.
|
||||
# OBJ is in mm with y as height (tooling.md section 2).
|
||||
import os
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
|
||||
def build():
|
||||
utility_api.NewProject() # deletes the avatar; re-import below
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5): # identical panels -> (True, True)
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 55, 50) # Body_*_Center_1: SAME x
|
||||
pattern_api.SetArrangementPosition(b, 50, 55, 50)
|
||||
return f, b
|
||||
|
||||
|
||||
def set_elastic(p, line, total, strength):
|
||||
pattern_api.SetPatternPieceElastic(p, line, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, line, total)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, line, strength)
|
||||
|
||||
|
||||
def garment_span_m():
|
||||
path = os.path.join(SCRATCH, "_sweep_probe.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2]) # OBJ: y is height, mm
|
||||
if yv < zmin:
|
||||
zmin = yv
|
||||
if yv > zmax:
|
||||
zmax = yv
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
VARIANTS = [
|
||||
("A_control", dict(pre=250, top=450.0, hem=390.0, strength=60.0,
|
||||
elastic_frames=80, soften_at_elastic=False, relax=50)),
|
||||
("B_early", dict(pre=40, top=430.0, hem=380.0, strength=60.0,
|
||||
elastic_frames=120, soften_at_elastic=False, relax=40)),
|
||||
("C_soft", dict(pre=40, top=430.0, hem=380.0, strength=60.0,
|
||||
elastic_frames=120, soften_at_elastic=True, relax=0)),
|
||||
("D_hard", dict(pre=30, top=400.0, hem=370.0, strength=100.0,
|
||||
elastic_frames=130, soften_at_elastic=False, relax=40)),
|
||||
]
|
||||
|
||||
results = {}
|
||||
for name, v in VARIANTS:
|
||||
f, b = build()
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.ResetClothArrangement()
|
||||
utility_api.Simulate(v["pre"])
|
||||
if v["soften_at_elastic"]:
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
for p in (f, b):
|
||||
set_elastic(p, 0, v["top"], v["strength"]) # line 0 = top edge
|
||||
set_elastic(p, 3, v["hem"], v["strength"]) # line 3 = hem
|
||||
utility_api.Simulate(v["elastic_frames"])
|
||||
if v["relax"]:
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(v["relax"])
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = garment_span_m()
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "sweep_%s.png" % name)
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results[name] = {"band_bottom_m": lo, "band_top_m": hi,
|
||||
"on_body": hi > 1.0, "snap": snap}
|
||||
|
||||
result = results
|
||||
@@ -0,0 +1,133 @@
|
||||
# SWEEP 2: zero-gravity donning for the strapless voyager bandeau.
|
||||
#
|
||||
# Sweep 1 (md_sweep_hold.py) proved elastic timing is NOT the lever: all four
|
||||
# variants (incl. frame-30 elastic at strength 100) ended on the floor. The probe
|
||||
# span showed the loop passed the 1095 mm hips, which a closed 812 mm hem cannot --
|
||||
# so the panels FREE-FALL ~0.5 m during the first frames while the side seams are
|
||||
# still closing, finish sewing around the shins, and slide off. Straps fixed this
|
||||
# for the pari by catching the shoulders during the drop.
|
||||
#
|
||||
# Fix: utility_api.SetSimulationGravity(0) while the seams close and the elastic
|
||||
# cinches the band onto the chest, then restore gravity and settle. Gravity is
|
||||
# restored in try/finally -- the exec namespace persists in-session and a later
|
||||
# garment must not inherit zero-g.
|
||||
#
|
||||
# E_zerog_soft zero-g wrap 100 soft + elastic 430/380 @ 60 -> gravity, 150, snapshot
|
||||
# F_zerog_stiff zero-g wrap 100 stiff + same elastic -> gravity, stiff 100 -> relax 50
|
||||
# G_zerog_tight like E but top cinched to 410
|
||||
#
|
||||
# Pass/fail from geometry: band top ~1.31 m, bottom ~1.14 m (tol 0.03).
|
||||
import os
|
||||
|
||||
SCRATCH = r"C:\Users\CAN\AppData\Local\Temp\claude\C--Users-CAN-tinqs-ltd-docs\3744fd8e-1342-446c-9677-7aafbafc8d18\scratchpad"
|
||||
AVATAR_FBX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\avatar\Lena_QuatSkin_Avatar.fbx"
|
||||
ZFAB = r"C:\Users\Public\Documents\MarvelousDesigner\New Assets\Fabric\(Default for Simulation).zfab"
|
||||
TEX = r"C:\Users\CAN\tinqs-ltd\animation\tools\tailor\textures\voyager_bandeau.png"
|
||||
PTS = [(41.5, 170.0), (508.7, 170.0), (550.2, 123.6),
|
||||
(478.0, 0.0), (72.2, 0.0), (0.0, 123.6)]
|
||||
|
||||
GRAVITY_DOC = utility_api.SetSimulationGravity.__doc__
|
||||
|
||||
|
||||
def set_gravity(g):
|
||||
"""Signature unverified -- try scalar, fall back to a vector (MD 3D is y-up)."""
|
||||
try:
|
||||
utility_api.SetSimulationGravity(float(g))
|
||||
return "scalar"
|
||||
except TypeError:
|
||||
utility_api.SetSimulationGravity(0.0, float(g), 0.0)
|
||||
return "vector"
|
||||
|
||||
|
||||
def build():
|
||||
utility_api.NewProject()
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.scale = 10.0
|
||||
op.bAddArrangementPoints = True
|
||||
op.bAutoTranslate = True
|
||||
import_api.ImportFBX(AVATAR_FBX, op)
|
||||
f = pattern_api.CreatePatternWithPoints([(x, y, 0) for (x, y) in PTS])
|
||||
b = pattern_api.CreatePatternWithPoints([(x + 800.2, y, 0) for (x, y) in PTS])
|
||||
for ln in (1, 2, 4, 5):
|
||||
pattern_api.AddSeamlinePairGroup(f, ln, b, ln, True, True)
|
||||
fab = fabric_api.AddFabric(ZFAB)
|
||||
fabric_api.SetBaseTextureMapImageGivenFilePath(TEX, fab)
|
||||
for p in (f, b):
|
||||
pattern_api.SetPatternPieceFabricIndex(p, fab)
|
||||
arr = {a["ArrangementName"]: int(a["ArrangementIndex"])
|
||||
for a in pattern_api.GetArrangementList()}
|
||||
pattern_api.SetArrangement(f, arr['Body_Front_Center_1'])
|
||||
pattern_api.SetArrangement(b, arr['Body_Back_Center_1'])
|
||||
pattern_api.SetArrangementPosition(f, 50, 55, 50)
|
||||
pattern_api.SetArrangementPosition(b, 50, 55, 50)
|
||||
return f, b
|
||||
|
||||
|
||||
def set_elastic(p, line, total, strength):
|
||||
pattern_api.SetPatternPieceElastic(p, line, True)
|
||||
pattern_api.SetPatternPieceElasticTotalLength(p, line, total)
|
||||
pattern_api.SetPatternPieceElasticStrength(p, line, strength)
|
||||
|
||||
|
||||
def garment_span_m():
|
||||
path = os.path.join(SCRATCH, "_sweep_probe.obj")
|
||||
op = ApiTypes.ImportExportOption()
|
||||
op.bExportGarment = True
|
||||
op.bExportAvatar = False
|
||||
export_api.ExportOBJ(path, op)
|
||||
zmin, zmax = 1e9, -1e9
|
||||
with open(path) as fh:
|
||||
for ln in fh:
|
||||
if ln.startswith("v "):
|
||||
yv = float(ln.split()[2])
|
||||
if yv < zmin:
|
||||
zmin = yv
|
||||
if yv > zmax:
|
||||
zmax = yv
|
||||
return round(zmin * 0.001, 4), round(zmax * 0.001, 4)
|
||||
|
||||
|
||||
VARIANTS = [
|
||||
("E_zerog_soft", dict(stiff_wrap=False, top=430.0, hem=380.0, strength=60.0,
|
||||
wrap_frames=100, settle_stiff=False, settle=150, relax=0)),
|
||||
("F_zerog_stiff", dict(stiff_wrap=True, top=430.0, hem=380.0, strength=60.0,
|
||||
wrap_frames=100, settle_stiff=True, settle=100, relax=50)),
|
||||
("G_zerog_tight", dict(stiff_wrap=False, top=410.0, hem=380.0, strength=60.0,
|
||||
wrap_frames=100, settle_stiff=False, settle=150, relax=0)),
|
||||
]
|
||||
|
||||
results = {"gravity_doc": GRAVITY_DOC}
|
||||
for name, v in VARIANTS:
|
||||
f, b = build()
|
||||
if v["stiff_wrap"]:
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
for p in (f, b):
|
||||
set_elastic(p, 0, v["top"], v["strength"])
|
||||
set_elastic(p, 3, v["hem"], v["strength"])
|
||||
utility_api.ResetClothArrangement()
|
||||
mode = set_gravity(0.0)
|
||||
try:
|
||||
utility_api.Simulate(v["wrap_frames"]) # weightless wrap + cinch
|
||||
finally:
|
||||
if mode == "scalar":
|
||||
utility_api.SetSimulationGravity(-9800.0)
|
||||
else:
|
||||
utility_api.SetSimulationGravity(0.0, -9800.0, 0.0)
|
||||
if v["settle_stiff"] and not v["stiff_wrap"]:
|
||||
pattern_api.SetPatternStrengthen(f, True)
|
||||
pattern_api.SetPatternStrengthen(b, True)
|
||||
utility_api.Simulate(v["settle"]) # now fight gravity
|
||||
if v["relax"]:
|
||||
pattern_api.SetPatternStrengthen(f, False)
|
||||
pattern_api.SetPatternStrengthen(b, False)
|
||||
utility_api.Simulate(v["relax"])
|
||||
utility_api.Refresh3DWindow()
|
||||
lo, hi = garment_span_m()
|
||||
utility_api.SetCamViewPoint(2)
|
||||
snap = os.path.join(SCRATCH, "sweep_%s.png" % name)
|
||||
export_api.ExportSnapshot3D(snap)
|
||||
results[name] = {"band_bottom_m": lo, "band_top_m": hi,
|
||||
"gravity_mode": mode, "snap": snap}
|
||||
|
||||
result = results
|
||||
Reference in New Issue
Block a user