Chapter 2 · Examples
2.6Outfit Builder
Select the garment meshes in dressing order, innermost first (shirt, then jacket, then coat), and build them into one Solver group: every garment is rebuilt into even cloth, and all of them share one Solver, one Self Collision with layer ordering, one Gravity and one collider list. A second button prints a report of every cloth in the scene.
rollout OutfitBuilder "TenPix Cloth - Outfit Builder" (
local body = undefined
spinner spnEdge "Cloth density" range:[0.2,10,2.0] fieldwidth:50
spinner spnThick "Self thickness" range:[0.05,5,0.15] fieldwidth:50
dropdownlist ddQ "Quality" items:#("Draft (1/1)", "Normal (4/2)", "High (8/4)") selection:2
checkbox chkWind "Add wind rig" checked:false
pickbutton pbBody "Pick Body (collider)" width:190
button btnBuild "Build Outfit From Selection" width:190
button btnReport "Scene Cloth Report" width:190
on pbBody picked obj do ( body = obj; pbBody.text = "Body: " + obj.name )
on btnBuild pressed do (
local order = selection as array
if order.count == 0 then ( messageBox "Select the garments first (innermost first)."; return() )
-- substeps, iterations, contact passes, stretch quality
local q = #( #(1,1,1,1), #(4,2,1,2), #(8,4,4,4) )[ddQ.selection]
for o in order do ( -- the rebuild is per garment
addModifier o (Tnpix_Garment())
o.modifiers[#Tnpix_Garment].edgeLength = spnEdge.value
)
-- ONE Solver group: the same Self Collision, Gravity, Collision, Forces and Solver on every garment
local sc = Tnpix_Self_Collision()
sc.tnEnabled = true
sc.layerOrdering = true
sc.layerHoldStrength = 4.0
sc.thickness = spnThick.value
local grav = Tnpix_Gravity()
local col = Tnpix_Collision()
local fr = undefined
if chkWind.checked do (
local w = Wind pos:[0,-250,120] strength:0.5 decay:0.0 turbulence:0.4 frequency:2.0
w.rotation = eulerAngles 90 0 0 -- blow across the outfit, not straight up
fr = Tnpix_Forces()
append fr.forceNodes w
append fr.forceMuted 0
)
local s = Tnpix_Solver()
s.substeps = q[1]
s.iterations = q[2]
s.contactPasses = q[3]
s.stretchQuality = q[4]
for i = 1 to order.count do (
local o = order[i]
addModifier o sc
addModifier o grav
addModifier o col
if fr != undefined do addModifier o fr
addModifier o s -- last on = on top
-- the garment list behind the Self Collision panel: garment i sits on layer i - 1
append sc.memberHandles (o.inode.handle)
append sc.memberLayers (i - 1)
append sc.memberFrictions -1.0 -- -1 = inherit
append sc.memberThicknesses -1.0
format "layer %: % ready\n" (i - 1) o.name
)
if body != undefined then (
TnpixTool.colAdd order[1] body
format "OUTFIT BUILT - % layers in one Solver group, body added as collider. Play.\n" order.count
) else (
format "OUTFIT BUILT - % layers in one Solver group. Pick the body on the Tnpix Collision panel, then play.\n" order.count
)
)
on btnReport pressed do (
format "\n===== SCENE CLOTH REPORT =====\n"
for o in objects where o.modifiers[#Tnpix_Solver] != undefined do (
local s = o.modifiers[#Tnpix_Solver]
format "% | substeps % iter % contact % | heatmap %\n" o.name s.substeps s.iterations s.contactPasses s.stressHeatmap
local sc = o.modifiers[#Tnpix_Self_Collision]
if sc != undefined do format " self: on % thickness % friction % layers % hold %\n" sc.tnEnabled sc.thickness sc.friction sc.layerOrdering sc.layerHoldStrength
local f = o.modifiers[#Tnpix_Forces]
if f != undefined do for n in f.forceNodes do format " force: %\n" n.name
if o.modifiers[#Tnpix_Collision] != undefined do format " colliders: %\n" (TnpixTool.colCount o)
)
format "==============================\n"
)
)
createDialog OutfitBuilder 210 220
What you should see: select your garments in order, optionally pick the body, and click Build Outfit From
Selection. The script names each layer as it goes. Open the Self Collision panel on any garment: the garment list
shows every layer, innermost first. Play: the layers settle on the body and on each other instead of passing through.
A new Self Collision starts switched on; the explicit sc.tnEnabled = true keeps the script's intent plain
and does not depend on the default.