Files
Nexus/2025/scripts/modeling_tools/instant_tie.py
2025-12-05 08:08:44 +08:00

990 lines
43 KiB
Python

##--------------------------------------------------------------------------
##
## ScriptName : Instant Tie
## Author : Joe Wu
## URL : https://www.youtube.com/@Im3dJoe
## LastUpdate : 2025/03/23
## : easy way to create tie and rope
## Version : 1.0 First version for public test
##
## Other Note : test in maya 2023.3 windows
##
## Install : copy and paste script into a python tab in maya script editor
## use ctrl + drag to adjust droop
##--------------------------------------------------------------------------
import maya.cmds as mc
import maya.OpenMaya as om
import maya.OpenMayaUI as omui
import maya.mel as mel
from maya.OpenMaya import MGlobal
import math
import maya.api.OpenMaya as oma
import types, fnmatch, sys, re, inspect, math, string, random, base64
import random
def euclidean_distance(pt1, pt2):
return math.sqrt((pt1[0]-pt2[0])**2 + (pt1[1]-pt2[1])**2 + (pt1[2]-pt2[2])**2)
def get_pivot(mesh):
mc.CenterPivot(mesh)
pivot = mc.xform(mesh, q=True, ws=True, piv=True)
return pivot[:3]
def cluster_pivots(mesh_list, k=2, iterations=10):
points = [(mesh, get_pivot(mesh)) for mesh in mesh_list]
if len(points) < k:
return {0: points}
centroids = [p[1] for p in random.sample(points, k)]
for it in range(iterations):
clusters = {i: [] for i in range(k)}
for mesh, pt in points:
distances = [euclidean_distance(pt, centroids[j]) for j in range(k)]
clusters[distances.index(min(distances))].append((mesh, pt))
new_centroids = []
for i in range(k):
pts = [pt for (mesh, pt) in clusters[i]]
if pts:
new_centroids.append([sum(c)/len(pts) for c in zip(*pts)])
else:
new_centroids.append(centroids[i])
if all(euclidean_distance(new_centroids[i], centroids[i]) < 1e-6 for i in range(k)):
break
centroids = new_centroids
return clusters
def average_position(points):
n = len(points)
return [sum(p[i] for p in points)/n for i in range(3)]
def checkFaceAngle(faceName):
shapeNode = mc.listRelatives(faceName, fullPath=True , parent=True )
transformNode = mc.listRelatives(shapeNode[0], fullPath=True , parent=True )
obj_matrix = oma.MMatrix(mc.xform(transformNode, query=True, worldSpace=True, matrix=True))
face_normals_text = mc.polyInfo(faceName, faceNormals=True)[0]
face_normals = [float(digit) for digit in re.findall(r'-?\d*\.\d*', face_normals_text)]
v = oma.MVector(face_normals) * obj_matrix
upvector = oma.MVector (0,1,0)
getHitNormal = v
quat = oma.MQuaternion(upvector, getHitNormal)
quatAsEuler = oma.MEulerRotation()
quatAsEuler = quat.asEulerRotation()
rx, ry, rz = math.degrees(quatAsEuler.x), math.degrees(quatAsEuler.y), math.degrees(quatAsEuler.z)
return rx, ry, rz
def tieFiz():
cleanList = ('unitMesh', 'tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
mc.button('ropeOnButton', e=1, en= 1)
mc.button('ropeOffButton', e=1, en= 0)
mc.floatSliderGrp('rtRopeTwist', e=1 ,en=0 , v=0)
def get_longest_bbox_length(mesh):
bbox = mc.exactWorldBoundingBox(mesh)
width = bbox[3] - bbox[0]
height = bbox[4] - bbox[1]
depth = bbox[5] - bbox[2]
return max(width, height, depth)
def jwPolyUniteMerge(newName):
mergeList = mc.ls(sl=1,fl=1, l=1, type = "transform")
parent = mc.listRelatives(mergeList[0], parent=True, fullPath=True)
transformNodeList = mc.listRelatives(mergeList[0], ad=True, f=True, type="transform") or []
joinArrays = transformNodeList + mergeList
shapeNodeList = mc.listRelatives(joinArrays, s=True, f=True) or []
polyCubeName = mc.polyCube(w=0.0001, h=0.0001, d=0.0001, sx=1, sy=1, sz=1)[0]
newNameMerge = mc.rename(newName)
nodeName = mc.createNode("polyUnite")
mc.rename(newName+ 'shapeMergeNode')
for i, shape in enumerate(shapeNodeList):
checkTransVis = mc.listRelatives(shape, p=True, f=True, type="transform")
if not checkTransVis:
continue
checkVis = mc.getAttr(checkTransVis[0] + ".visibility")
if checkVis == 1:
mc.connectAttr(shape + ".outMesh", (newName + "shapeMergeNode.inputPoly[" + str(i) + "]"), f=True)
mc.connectAttr(shape + ".worldMatrix[0]", (newName +"shapeMergeNode.inputMat[" + str(i) + "]"), f=True)
mc.connectAttr((newName + "shapeMergeNode.output"), (newName + ".inMesh"), f=True)
def jwCreateRefPlane():
view = omui.M3dView.active3dView()
cam = om.MDagPath()
view.getCamera(cam)
camPath = cam.fullPathName()
cameraTrans = mc.listRelatives(camPath,type='transform',p=True)
ratio = mc.getAttr('defaultResolution.deviceAspectRatio')
focalLengths = mc.getAttr(cameraTrans[0]+'.focalLength')
nearClipPlane = mc.getAttr(cameraTrans[0]+'.nearClipPlane')
mc.polyPlane(w = ratio, h=1 ,sx= 40, sy= 20, ax =(0,0,1), cuv= 2, ch=1)
mc.rename('tieRefPlane')
mc.parentConstraint( cameraTrans[0],('tieRefPlane'),weight =1)
mc.delete(constraints=True)
mc.parent('tieRefPlane',cameraTrans[0])
mc.setAttr("tieRefPlane.translate",0,0,0)
mc.setAttr(('tieRefPlane.translateZ'), (-1.05*nearClipPlane))
head3d = mc.pointPosition(( 'tieRefPlane.vtx[0]') )
tail3d = mc.pointPosition(( 'tieRefPlane.vtx[860]') )
head2D = worldSpaceToImageSpace(cameraTrans[0], (head3d[0],head3d[1],head3d[2]))
tail2d = worldSpaceToImageSpace(cameraTrans[0], (tail3d[0],tail3d[1],tail3d[2]))
distanceX = tail2d[0] - head2D[0]
distanceY = tail2d[1] - head2D[1]
resWidth,resHeight = screenRes()
mc.setAttr('tieRefPlane.scaleX', (resWidth/distanceX*2))
mc.setAttr('tieRefPlane.scaleY', (resHeight/distanceY*2))
mc.setAttr('tieRefPlane.visibility',0)
def getRefPlanePos(SX,SY):
if mc.objExists('tieRefPlane'):
global CurrentCam
pos = om.MPoint()
dir = om.MVector()
hitpoint = om.MFloatPoint()
omui.M3dView().active3dView().viewToWorld(int(SX), int(SY), pos, dir)
pos2 = om.MFloatPoint(pos.x, pos.y, pos.z)
cameraPosition = mc.xform(CurrentCam,q=1,ws=1,rp=1)
checkHit = 0
finalMesh = []
finalX = []
finalY = []
finalZ = []
shortDistance = 10000000000
distanceBetween = 1000000000
checkList = []
checkList.append('tieRefPlane')
mesh = checkList[0]
selectionList = om.MSelectionList()
selectionList.add(mesh)
dagPath = om.MDagPath()
selectionList.getDagPath(0, dagPath)
fnMesh = om.MFnMesh(dagPath)
hitFace = om.MScriptUtil()
hitFace.createFromInt(0)
hitFacePtr = hitFace.asIntPtr()
intersection = fnMesh.closestIntersection(
om.MFloatPoint(pos2),
om.MFloatVector(dir),
None,
None,
False,
oma.MSpace.kWorld,
99999,
False,
None,
hitpoint,
None,
hitFacePtr,
None,
None,
None)
if intersection:
x = hitpoint.x
y = hitpoint.y
z = hitpoint.z
distanceBetween = math.sqrt( ((float(cameraPosition[0]) - x)**2) + ((float(cameraPosition[1]) - y)**2) + ((float(cameraPosition[2]) - z)**2))
if distanceBetween < shortDistance:
shortDistance = distanceBetween
finalMesh = mesh
finalX = x
finalY = y
finalZ = z
hitFace = om.MScriptUtil(hitFacePtr).asInt()
return finalX, finalY, finalZ ,finalMesh ,hitFace
mc.refresh(cv=True,f=True)
def screenRes():
global lastPanelActive
lastPanelActive =[]
windowUnder = mc.getPanel(withFocus=True)
if 'modelPanel' not in windowUnder:
windowUnder = lastPanelActive
if 'modelPanel' not in windowUnder:
windowUnder = 'modelPanel4'
viewNow = omui.M3dView()
omui.M3dView.getM3dViewFromModelEditor(windowUnder, viewNow)
screenW = omui.M3dView.portWidth(viewNow)
screenH = omui.M3dView.portHeight(viewNow)
return screenW,screenH
def worldSpaceToImageSpace(cameraName, worldPoint):
resWidth,resHeight = screenRes()
selList = om.MSelectionList()
selList.add(cameraName)
dagPath = om.MDagPath()
selList.getDagPath(0,dagPath)
dagPath.extendToShape()
camInvMtx = dagPath.inclusiveMatrix().inverse()
fnCam = om.MFnCamera(dagPath)
mFloatMtx = fnCam.projectionMatrix()
projMtx = om.MMatrix(mFloatMtx.matrix)
mPoint = om.MPoint(worldPoint[0],worldPoint[1],worldPoint[2]) * camInvMtx * projMtx;
x = (mPoint[0] / mPoint[3] / 2 + .5) * resWidth
y = (mPoint[1] / mPoint[3] / 2 + .5) * resHeight
return [x,y]
def create_shrink_wrap(mesh, target, projMethod, **kwargs):
parameters = [
("projection", projMethod),
("closestIfNoIntersection", 1),
("reverse", 0),
("bidirectional", 1),
("boundingBoxCenter", 1),
("axisReference", 1),
("alongX", 0),
("alongY", 0),
("alongZ", 1),
("offset", 0),
("targetInflation", 0),
("targetSmoothLevel", 0),
("falloff", 0),
("falloffIterations", 1),
("shapePreservationEnable", 0),
("shapePreservationSteps", 1)
]
target_shapes = mc.listRelatives(target, f=True, shapes=True, type="mesh", ni=True)
if not target_shapes:
raise ValueError("The target supplied is not a mesh")
target_shape = target_shapes[0]
shrink_wrap = mc.deformer(mesh, type="shrinkWrap")[0]
for parameter, default in parameters:
mc.setAttr(
shrink_wrap + "." + parameter,
kwargs.get(parameter, default))
connections = [
("worldMesh", "targetGeom"),
("continuity", "continuity"),
("smoothUVs", "smoothUVs"),
("keepBorder", "keepBorder"),
("boundaryRule", "boundaryRule"),
("keepHardEdge", "keepHardEdge"),
("propagateEdgeHardness", "propagateEdgeHardness"),
("keepMapBorders", "keepMapBorders")
]
for out_plug, in_plug in connections:
mc.connectAttr(
target_shape + "." + out_plug,
shrink_wrap + "." + in_plug)
return shrink_wrap
def get_closest_point_from_camera(mesh):
global CurrentCam
cam_position = mc.xform(CurrentCam, query=True, worldSpace=True, translation=True)
vertices = mc.ls(f"{mesh}.vtx[*]", flatten=True)
closest_point = None
min_distance = float('inf')
for vertex in vertices:
vertex_position = mc.xform(vertex, query=True, worldSpace=True, translation=True)
dist_sq = ((cam_position[0] - vertex_position[0]) ** 2 +
(cam_position[1] - vertex_position[1]) ** 2 +
(cam_position[2] - vertex_position[2]) ** 2)
distance = math.sqrt(dist_sq)
if distance < min_distance:
min_distance = distance
closest_point = vertex_position
return closest_point, min_distance
def get_farest_point_from_camera(mesh):
global CurrentCam
cam_pos = mc.xform(CurrentCam, query=True, worldSpace=True, translation=True)
vertices = mc.ls(f"{mesh}.vtx[*]", flatten=True)
farthest_point = None
max_distance = float('-inf')
for v in vertices:
v_pos = mc.xform(v, query=True, worldSpace=True, translation=True)
dist = math.sqrt((cam_pos[0] - v_pos[0])**2 +
(cam_pos[1] - v_pos[1])**2 +
(cam_pos[2] - v_pos[2])**2)
if dist > max_distance:
max_distance = dist
farthest_point = v_pos
return farthest_point, max_distance
def get_curve_pivot_distance(curve):
global CurrentCam
cam_position = mc.xform(CurrentCam, query=True, worldSpace=True, translation=True)
pivot = mc.xform(curve, query=True, worldSpace=True, rp=True)
distance = math.sqrt((cam_position[0] - pivot[0])**2 +
(cam_position[1] - pivot[1])**2 +
(cam_position[2] - pivot[2])**2)
return pivot, distance
def connectSweepNodeToUI():
global sweepNode
global cableSize
mc.floatSliderGrp('rtSize', e=1, v = cableSize, min = (0.1*cableSize), max = (5*cableSize))
mc.connectControl('rtSize', (sweepNode[0] + ".scaleProfileX"))
mc.connectControl('rtPrecision', (sweepNode[0] + ".interpolationPrecision"))
mc.connectControl('rtRopeTwist', (sweepNode[0] + ".twist"))
mc.floatSliderGrp('rtRopeTwist', e=1 ,en=0 , v=0)
def ropeModeOff():
global sweepNode
mc.setAttr(sweepNode[0]+'.patternEnable', 0)
mc.setAttr(sweepNode[0]+'.twist',0)
mc.button('ropeOnButton', e=1, en= 1)
mc.button('ropeOffButton', e=1, en= 0)
mc.floatSliderGrp('rtRopeTwist', e=1 ,en=0 , v=0)
def ropeMode():
global sweepNode
mc.setAttr(sweepNode[0]+'.patternEnable', 1)
mc.setAttr(sweepNode[0]+'.patternNumberOfElements', 4)
mc.setAttr(sweepNode[0]+'.interpolationMode', 1)
mc.setAttr(sweepNode[0]+'.interpolationSteps', 100)
mc.setAttr(sweepNode[0]+'.interpolationOptimize', 0)
mc.setAttr(sweepNode[0]+'.patternScaleElementsX', 1)
mc.setAttr(sweepNode[0]+'.twist', 10)
mc.button('ropeOnButton', e=1, en= 0)
mc.button('ropeOffButton', e=1, en= 1)
mc.floatSliderGrp('rtRopeTwist', e=1 ,en=1)
def createCable(cableSize):
createType = mc.radioButtonGrp('rtType',q=1, sl=1)
precision = mc.floatSliderGrp('rtPrecision', q=1, v = 1)
global currentCurve
curveSel = mc.ls(sl=1,fl=1)
if mc.objExists('tieMeshGr*') == 0:
mc.CreateEmptyGroup()
mc.rename('tieMeshGrp')
if mc.objExists('tieCurveGr*') == 0:
mc.CreateEmptyGroup()
mc.rename('tieCurveGrp')
mc.parent(curveSel, 'tieCurveGrp')
mc.rename('tieCurve_1')
curveSel = mc.ls(sl=1,fl=1)
currentCurve = curveSel[0]
indexNumber = curveSel[0].split('_')[-1]
global sweepNode
nextCurveName = ''
if sweepNode == '' or mc.objExists(sweepNode[0])== 0:
mc.sweepMeshFromCurve(oneNodePerCurve=0)
sweepNode = mc.ls(selection=True, flatten=True)
mc.setAttr(sweepNode[0]+'.interpolationOptimize', 1)
mc.setAttr(sweepNode[0]+'.interpolationPrecision',precision)
mc.setAttr(sweepNode[0]+'.scaleProfileX', cableSize)
mc.rename('sweep1','tieMesh_1')
nextCurveName = ('tieMesh_1')
else:
curveShapes = mc.listRelatives(curveSel[0], shapes=True, fullPath=True)
mc.connectAttr((curveShapes[0] + ".worldSpace[0]"), (sweepNode[0] + ".inCurveArray[" + str(indexNumber) + "]"), force=True)
mc.createNode("mesh", name="sweepShape" + str(indexNumber))
mc.connectAttr((sweepNode[0] + ".outMeshArray[" + str(indexNumber) + "]"),("sweepShape" + str(indexNumber) + ".inMesh"), force=True)
mc.sets(('sweep' + str(indexNumber)), edit=True, forceElement="initialShadingGroup")
mc.rename(('sweep' + str(indexNumber)),('tieMesh_' + str(indexNumber)))
curveShapes = mc.listRelatives(('|tieMesh_' + str(indexNumber)), shapes=True, fullPath=True)
nextCurveName = curveShapes[0]
if '|' in nextCurveName:
selMesh = nextCurveName.split('|')[1]
mc.parent(selMesh ,'tieMeshGrp')
else:
mc.parent(('|' + nextCurveName) ,'tieMeshGrp')
stateName = mc.ls(sl=1,fl=1)[0]
plugs = mc.listConnections('unitMeshshapeMergeNode.inputPoly', plugs=True, source=True) or []
next_index = len(plugs)
mc.connectAttr(stateName + ".outMesh", ("unitMeshshapeMergeNode.inputPoly[" + str(next_index+1) + "]"), f=True)
mc.connectAttr(stateName + ".worldMatrix[0]", ("unitMeshshapeMergeNode.inputMat[" + str(next_index+1) + "]"), f=True)
connectSweepNodeToUI()
mc.select(cl=1)
def createTie():
global currentCurveType
currentCurveType = 1
global cableSize
mc.CenterPivot()
mc.duplicate()
mc.rename('cutLineFar')
curveList, distanceO = get_curve_pivot_distance("cutLine")
global CurrentCam
source_pivot = mc.xform(CurrentCam, query=True, worldSpace=True, rotatePivot=True)
mc.xform('cutLine', worldSpace=True, pivots=source_pivot)
mc.xform('cutLineFar', worldSpace=True, pivots=source_pivot)
farest_vertex, distanceF = get_farest_point_from_camera("unitMesh")
closest_vertex, distanceC = get_closest_point_from_camera("unitMesh")
scaleVC = distanceC / distanceO*0.95
scaleVF = distanceF / distanceO*1.05
mc.setAttr("cutLine.scale", scaleVC,scaleVC,scaleVC)
mc.setAttr("cutLineFar.scale", scaleVF,scaleVF,scaleVF)
mc.nurbsToPolygonsPref(polyType=1 , format=2, uType=3, uNumber=1, vType=3, vNumber=1)
loft_surface = mc.loft('cutLineFar', 'cutLine',ch=True, u=True,c=False,ar=True,d=1,ss=1,rn=False,po=1,rsn=True)
rx, ry, rz = checkFaceAngle(loft_surface[0]+'.f[0]')
mc.rename('tempLoftPlane')
result = mc.polySmooth(mth=0, dv=1, c=1, kb=0, ksb=0, khe=0, kt=1, kmb=1, suv=1, sl=1, dpe=1, ps=0.1, ro=1)
mc.select('tempLoftPlane','unitMesh')
mel.eval('assignNewPfxToon')
getToon =mc.ls(sl=1)
gettoonTrans = mc.listRelatives(getToon,p=1)
toonShape = mc.listRelatives(gettoonTrans,c=1)
mc.setAttr((toonShape[0]+'.borderLines'), 0)
mc.setAttr((toonShape[0]+'.intersectionLines'), 1)
mc.setAttr((toonShape[0]+'.creaseLines'), 0)
mc.setAttr((toonShape[0]+'.profileLines'), 0)
mc.setAttr((toonShape[0]+'.degree'), 1)
mc.setAttr((toonShape[0]+'.selfIntersect'), 0)
mc.setAttr((toonShape[0]+'.lineWidth'), 0.001)
mc.select(gettoonTrans)
nurbsGroups = mel.eval('createPfxOutCurves("%s", 1)' % gettoonTrans[0])
shapes = mc.listRelatives(nurbsGroups[0], ad=True, typ = 'transform')
mc.nurbsToPolygonsPref(polyType=1 , format=2, uType=3, uNumber=1, vType=3, vNumber=1)
convertList = []
for u in shapes:
result = mc.nurbsToPoly(u, mnd=1,ch=0,f=2,pt=True,pc=200,chr=0.1,ft=0.01,mel=0.001,d=0.1,ut=3,un=1,vt=3,vn=1,uch=False,ucr=False,cht=0.2,es=0,ntr=0,mrt=0,uss=True)
convertList.append(result[0])
mc.select(convertList)
jwPolyUniteMerge('intersectionPlane')
mc.CenterPivot('intersectionPlane')
mc.delete('intersectionPlane', ch=1)
shrinkPlane = mc.polyPlane(width=1, height=1, subdivisionsX=10, subdivisionsY=10, axis=(0, 1, 0), createUVs=2, constructionHistory=0)
mc.rename('shrinkPlane')
mc.select('intersectionPlane', add=1)
mc.MatchTranslation()
mc.setAttr("shrinkPlane.rotate", rx, ry, rz)
mc.setAttr("shrinkPlane.scale", 100000,100000,100000)
mc.makeIdentity(apply=True, translate=1, rotate=1, scale=1, normal=0, pn=True)
mc.select('shrinkPlane')
mc.ConvertSelectionToEdgePerimeter()
mc.InvertSelection()
mc.delete()
shrink_wrap = create_shrink_wrap('shrinkPlane','intersectionPlane', 4)
mc.delete('shrinkPlane',ch=1)
mc.polyMergeVertex('shrinkPlane', d=0.001, am=1, ch=0)
mc.ConvertSelectionToEdgePerimeter()
mc.polyToCurve(form=2, degree=1, conformToSmoothMeshPreview=1)
mc.delete(ch=1)
mc.rename('tieCurve_1')
cleanList = ('tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
createCable(cableSize)
def jwDrawLine():
cleanList = ('tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
global currentCurve
currentCurve = ''
global CurrentCam
mc.select(cl=True)
view = omui.M3dView.active3dView()
cam = om.MDagPath()
view.getCamera(cam)
camPath = cam.fullPathName()
cameraTrans = mc.listRelatives(camPath,type='transform',p=True)
CurrentCam = cameraTrans[0]
global ctx
ctx = 'Click2dTo3dCtx'
if mc.draggerContext(ctx, exists=True):
mc.deleteUI(ctx)
mc.draggerContext(ctx, pressCommand = onPressPlace, rc = offPressPlace, dragCommand = onDragPlace, name=ctx, cursor='crossHair',undoMode='step')
mc.setToolTo(ctx)
def onPressPlace():
global currentNode
global currentCurve
global yMove
global screenX,screenY
global CurrentCam
global ctx
currentNode = 0
modifiers = mc.getModifiers()
if (modifiers == 4):
currentNode = 1
else:
if mc.objExists('gravPoint_1'):
clusterNode = mc.listConnections('gravPoint_1', d =1 )
connected = mc.listConnections(clusterNode[0] + ".outputGeometry", plugs=True)
curveNode = connected[0].split('.')[0]
mc.delete(curveNode,ch=True)
if mc.objExists('tieRefPlane') == 0:
jwCreateRefPlane()
mc.curve(d= 1, p=[(0, 0, 0),(1,0,0)], k = [0,1])
mc.rename('cutLine')
shapes = mc.listRelatives('cutLine',shapes=True)
vpX, vpY, _ = mc.draggerContext(ctx, query=True, anchorPoint=True)
screenX = vpX
screenY = vpY
wx,wy,wz,hitmesh,hitFace= getRefPlanePos(screenX,screenY)
mc.move(wx,wy,wz,(shapes[0]+'.cv[0]'), ws=True, a=True)
def offPressPlace():
rtTypeGet = mc.radioButtonGrp('rtType', q=1, sl=1)
autoNode = mc.checkBox('autoNodeButton',q= 1,v=1)
global currentCurve
global currentNode
modifiers = mc.getModifiers()
if (modifiers == 4):
currentNode = 1
updateNodesEnd()
else:
if mc.objExists('gravPoint_1') == 0 :
if rtTypeGet == 1:
createTie()
if autoNode == 1:
createNodeTieMesh()
else:
createRope()
if currentNode == 0:
if autoNode == 1:
createNodeMesh()
updateNodesEnd()
mc.refresh(cv=True,f=True)
cleanList = ('tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
def onDragPlace():
global cableSize
global currentCurve
global yMove
global screenX,screenY
global currentNode
global currentCurveType
vpX, vpY, _ = mc.draggerContext(ctx, query=True, dragPoint=True)
modifiers = mc.getModifiers()
if (modifiers == 4):
if currentCurveType == 2:
currentNode = 1
if screenX > vpX:
yMove = (yMove + (cableSize * 0.5) )
else:
yMove = (yMove - (cableSize * 0.5) )
screenX = vpX
if mc.objExists(currentCurve):
position = mc.pointPosition((currentCurve + '.cv[1]'), world=True)
mc.move( position[0], yMove, position[2], (currentCurve + '.cv[1]'), absolute=True )
position = mc.pointPosition((currentCurve + '.cv[2]'), world=True)
mc.move( position[0], yMove, position[2], (currentCurve + '.cv[2]'), absolute=True )
else:
screenX = vpX
screenY = vpY
result = getRefPlanePos(screenX, screenY)
if (result is not None and hasattr(result, '__len__') and len(result) == 5):
wx, wy, wz, hitmesh, hitFace = result
shapes = mc.listRelatives('cutLine',shapes=True)
mc.move(wx,wy,wz,('cutLine.cv[1]'), ws=True, a=True)
mc.refresh(cv=True,f=True)
def compute_bezier_control_points(p0, p3, factor1=1/3.0, factor2=2/3.0):
p1 = [ p0[i] + (p3[i]-p0[i]) * factor1 for i in range(3) ]
p2 = [ p0[i] + (p3[i]-p0[i]) * factor2 for i in range(3) ]
return [p0, p1, p2, p3]
def lower_middle_points(curve_name, slider_value):
pos0 = mc.pointPosition(curve_name + ".cv[0]", world=True)
pos3 = mc.pointPosition(curve_name + ".cv[3]", world=True)
lowest_y = min(pos0[1], pos3[1])
random_offset = slider_value + random.uniform(-slider_value * 0.1, slider_value * 0.1)
random_offset = abs(random_offset)
new_y = lowest_y - random_offset
for cv_index in [1, 2]:
pos = mc.pointPosition(curve_name + ".cv[%d]" % cv_index, world=True)
new_pos = [pos[0], new_y, pos[2]]
mc.xform(curve_name + ".cv[%d]" % cv_index, ws=True, t=new_pos)
def create_line_from_clusters(clusters):
global yMove
group0 = clusters.get(0, [])
group1 = clusters.get(1, [])
if not group0 or not group1:
cleanList = ('tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
else:
pts0 = [pivot for (mesh, pivot) in group0]
pts1 = [pivot for (mesh, pivot) in group1]
avg0 = average_position(pts0)
avg1 = average_position(pts1)
pts = compute_bezier_control_points(avg0, avg1)
knots = [0, 0, 0, 1, 1, 1]
curve_name = mc.curve(p=pts, d=3, k=knots, bezier=True,name = 'ropeCurve_1')
randState = mc.floatSliderGrp('rtDropRandom', q=1, v = 1)
pos0 = mc.pointPosition(curve_name + ".cv[0]", world=True)
pos3 = mc.pointPosition(curve_name + ".cv[3]", world=True)
lowest_y = min(pos0[1], pos3[1])
random_offset = randState + random.uniform(-randState * 0.1, randState * 0.1)
random_offset = abs(random_offset)
new_y = lowest_y - random_offset
for cv_index in [1, 2]:
pos = mc.pointPosition(curve_name + ".cv[%d]" % cv_index, world=True)
if randState > 0:
new_pos = [pos[0], new_y, pos[2]]
mc.xform(curve_name + ".cv[%d]" % cv_index, ws=True, t=new_pos)
yMove = new_y
def createRope():
cleanList = ('tieRefPlan*','intersectionPlan*','cutLin*','cutLineFa*','tempLoftPlan*','shrinkPlan*','MeshGrou*','pfxToon*','meshIntersectionSurface*','nurbsToPoly*')
global cableSize
global yMove
yMove = 0
global currentCurveType
currentCurveType = 2
if mc.objExists('cutLine'):
mc.select('cutLine')
mc.CenterPivot()
mc.duplicate()
mc.rename('cutLineFar')
curveList, distanceO = get_curve_pivot_distance("cutLine")
global CurrentCam
source_pivot = mc.xform(CurrentCam, query=True, worldSpace=True, rotatePivot=True)
mc.xform('cutLine', worldSpace=True, pivots=source_pivot)
mc.xform('cutLineFar', worldSpace=True, pivots=source_pivot)
farest_vertex, distanceF = get_farest_point_from_camera("unitMesh")
closest_vertex, distanceC = get_closest_point_from_camera("unitMesh")
scaleVC = distanceC / distanceO*0.95
scaleVF = distanceF / distanceO*1.05
mc.setAttr("cutLine.scale", scaleVC,scaleVC,scaleVC)
mc.setAttr("cutLineFar.scale", scaleVF,scaleVF,scaleVF)
mc.nurbsToPolygonsPref(polyType=1 , format=2, uType=3, uNumber=1, vType=3, vNumber=1)
loft_surface = mc.loft('cutLineFar', 'cutLine',ch=True, u=True,c=False,ar=True,d=1,ss=1,rn=False,po=1,rsn=True)
rx, ry, rz = checkFaceAngle(loft_surface[0]+'.f[0]')
mc.rename('tempLoftPlane')
result = mc.polySmooth(mth=0, dv=1, c=1, kb=0, ksb=0, khe=0, kt=1, kmb=1, suv=1, sl=1, dpe=1, ps=0.1, ro=1)
mc.select('tempLoftPlane','unitMesh')
mel.eval('assignNewPfxToon')
getToon =mc.ls(sl=1)
gettoonTrans = mc.listRelatives(getToon,p=1)
toonShape = mc.listRelatives(gettoonTrans,c=1)
mc.setAttr((toonShape[0]+'.borderLines'), 0)
mc.setAttr((toonShape[0]+'.intersectionLines'), 1)
mc.setAttr((toonShape[0]+'.creaseLines'), 0)
mc.setAttr((toonShape[0]+'.profileLines'), 0)
mc.setAttr((toonShape[0]+'.degree'), 1)
mc.setAttr((toonShape[0]+'.selfIntersect'), 0)
mc.setAttr((toonShape[0]+'.lineWidth'), 0.001)
mc.select(gettoonTrans)
nurbsGroups = mel.eval('createPfxOutCurves("%s", 1)' % gettoonTrans[0])
if mc.objExists(nurbsGroups[0]):
shapes = mc.listRelatives(nurbsGroups[0], ad=True, typ = 'transform') or []
if shapes:
mc.nurbsToPolygonsPref(polyType=1 , format=2, uType=3, uNumber=1, vType=3, vNumber=1)
convertList = []
for u in shapes:
result = mc.nurbsToPoly(u, mnd=1,ch=0,f=2,pt=True,pc=200,chr=0.1,ft=0.01,mel=0.001,d=0.1,ut=3,un=1,vt=3,vn=1,uch=False,ucr=False,cht=0.2,es=0,ntr=0,mrt=0,uss=True)
convertList.append(result[0])
mc.select(convertList)
mc.CenterPivot()
clusters = cluster_pivots(convertList, k=2)
curve = create_line_from_clusters(clusters)
if mc.objExists('|ropeCurve_1'):
mc.select('|ropeCurve_1')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
createCable(cableSize)
currentNode = 1
else:
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
mc.select(cl=1)
def instantTieGo():
tieFiz()
script_jobs = mc.scriptJob(listJobs=True)
for job in script_jobs:
if 'tieFiz' in job:
job_id = int(job.split(":")[0])
mc.scriptJob(kill=job_id, force=True)
global tieSelTarget
global tieToolID
global sweepNode
global cableSize
global sweepNodeB
global currentCurveType
currentCurveType = 1
sweepNodeB = ''
cableSize = 0.1
sweepNode = ''
tieSelTarget = []
tieSelTarget = mc.ls(sl=1,fl=1)
filteredList = []
for obj in tieSelTarget:
shapes = mc.listRelatives(obj, shapes=True) or []
if not any(mc.objectType(shape) in ['nurbsCurve', 'bezierCurve'] for shape in shapes):
filteredList.append(obj)
if filteredList:
mc.select(filteredList)
jwPolyUniteMerge('unitMesh')
mc.setAttr("unitMesh.visibility",0)
mc.setAttr("unitMesh.hiddenInOutliner",1)
cableSize = get_longest_bbox_length('unitMesh') / 100
jwDrawLine()
tieToolID = mc.scriptJob(runOnce=True, event=["ToolChanged", tieFiz])
def ropeRandSwitch():
state = mc.radioButtonGrp('rtType',q=1, sl=1)
if state == 1:
mc.floatSliderGrp('rtDropRandom', e=1 , en=0)
mc.floatSliderGrp('rtPrecision', e =1, v = 50)
else:
mc.floatSliderGrp('rtDropRandom', e=1 , en=1)
mc.floatSliderGrp('rtPrecision', e =1, v = 90)
def updateNodesEnd():
global currentCurve
getAllNodeList = mc.ls('nodeCurve_*',fl=1)
if getAllNodeList:
for g in getAllNodeList:
parentCurve = mc.getAttr(g + '.sourceCurve')
if currentCurve == parentCurve:
posi = mc.getAttr(g + '.nodePosition')
pos0 = []
pos1 = []
if posi == 'head':
pos0 = mc.pointOnCurve(parentCurve, pr=0.01, p=True)
pos1 = mc.pointOnCurve(parentCurve, pr=0.02, p=True)
else:
pos0 = mc.pointOnCurve(parentCurve, pr=0.99, p=True)
pos1 = mc.pointOnCurve(parentCurve, pr=0.98, p=True)
mc.xform(g, ws=True, t=pos0)
direction = [pos1[i] - pos0[i] for i in range(3)]
rot = mc.angleBetween(euler=True, v1=[1, 0, 0], v2=direction)
mc.xform(g, ws=True, ro=rot)
rotRand = random.uniform(0, 360)
mc.setAttr(g+ '.rotateX',rotRand)
def createNodeTieMesh():
global currentCurve
global sweepNode
global sweepNodeB
global currentNode
currentNode = 1
ccc = mc.listRelatives(currentCurve, shapes=True, fullPath=True)
plugs = mc.listConnections(ccc[0]+ '.worldSpace[0]', plugs=True, source=True) or []
getSweepNode = plugs[0].split('.')[0]
cableSize = mc.getAttr(getSweepNode + '.scaleProfileX')
if mc.objExists('NodeMeshGr*') == 0:
mc.CreateEmptyGroup()
mc.rename('NodeMeshGrp')
nodeGrp= createNodesTie(currentCurve)
mc.parent(nodeGrp, 'NodeMeshGrp')
nodeGrp = mc.ls(sl=1,fl=1)
mc.addAttr(nodeGrp[0], ln="sourceCurve", dt="string")
mc.setAttr(nodeGrp[0] + ".sourceCurve", "", type="string")
mc.setAttr(nodeGrp[0] + ".sourceCurve", currentCurve, type="string")
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleX"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleY"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleZ"), force=True)
if sweepNodeB == '' or mc.objExists(sweepNodeB[0])== 0:
mc.sweepMeshFromCurve(oneNodePerCurve=0)
sweepNodeB = mc.ls(selection=True, flatten=True)
mc.setAttr(sweepNodeB[0]+'.interpolationMode', 2)
mc.setAttr(sweepNodeB[0]+'.interpolationSteps', 4)
mc.setAttr(sweepNodeB[0]+'.scaleProfileX', cableSize)
mc.rename('sweep1','nodeMesh_1')
mc.parent('|nodeMesh_1', 'NodeMeshGrp')
else:
for c in nodeGrp:
indexNumber = c.split('_')[-1]
curveShapes = mc.listRelatives(c, shapes=True, fullPath=True)
mc.connectAttr((curveShapes[0] + ".worldSpace[0]"), (sweepNodeB[0] + ".inCurveArray[" + str(indexNumber) + "]"), force=True)
mc.createNode("mesh", name="sweepShape" + str(indexNumber))
mc.connectAttr((sweepNodeB[0] + ".outMeshArray[" + str(indexNumber) + "]"),("sweepShape" + str(indexNumber) + ".inMesh"), force=True)
mc.sets(('sweep' + str(indexNumber)), edit=True, forceElement="initialShadingGroup")
mc.rename( ('sweep' + str(indexNumber)) ,('nodeMesh_' + str(indexNumber)))
mc.parent(('nodeMesh_' + str(indexNumber)) ,'NodeMeshGrp')
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(sweepNodeB[0] + ".scaleProfileX"),force=True)
mc.select(cl=1)
def createNodeMesh():
global currentCurve
global sweepNode
global sweepNodeB
global currentNode
currentNode = 1
ccc = mc.listRelatives(currentCurve, shapes=True, fullPath=True)
plugs = mc.listConnections(ccc[0]+ '.worldSpace[0]', plugs=True, source=True) or []
getSweepNode = plugs[0].split('.')[0]
cableSize = mc.getAttr(getSweepNode + '.scaleProfileX')
if mc.objExists('NodeMeshGr*') == 0:
mc.CreateEmptyGroup()
mc.rename('NodeMeshGrp')
nodeGrp= createNodesEnd(currentCurve)
mc.parent(nodeGrp, 'NodeMeshGrp')
nodeGrp = mc.ls(sl=1,fl=1)
mc.addAttr(nodeGrp[0], ln="sourceCurve", dt="string")
mc.setAttr(nodeGrp[0] + ".sourceCurve", "", type="string")
mc.setAttr(nodeGrp[0] + ".sourceCurve", currentCurve, type="string")
mc.addAttr(nodeGrp[1], ln="sourceCurve", dt="string")
mc.setAttr(nodeGrp[1] + ".sourceCurve", "", type="string")
mc.setAttr(nodeGrp[1] + ".sourceCurve", currentCurve, type="string")
mc.addAttr(nodeGrp[0], ln="nodePosition", dt="string")
mc.setAttr(nodeGrp[0] + ".nodePosition", "", type="string")
mc.setAttr(nodeGrp[0] + ".nodePosition", 'head', type="string")
mc.addAttr(nodeGrp[1], ln="nodePosition", dt="string")
mc.setAttr(nodeGrp[1] + ".nodePosition", "", type="string")
mc.setAttr(nodeGrp[1] + ".nodePosition", 'end', type="string")
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleX"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleY"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[0] + ".scaleZ"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[1] + ".scaleX"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[1] + ".scaleY"), force=True)
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(nodeGrp[1] + ".scaleZ"), force=True)
if sweepNodeB == '' or mc.objExists(sweepNodeB[0])== 0:
mc.sweepMeshFromCurve(oneNodePerCurve=0)
sweepNodeB = mc.ls(selection=True, flatten=True)
mc.setAttr(sweepNodeB[0]+'.interpolationMode', 2)
mc.setAttr(sweepNodeB[0]+'.interpolationSteps', 4)
mc.setAttr(sweepNodeB[0]+'.scaleProfileX', cableSize)
mc.rename('sweep1','nodeMesh_1')
mc.parent('|nodeMesh_1', 'NodeMeshGrp')
mc.rename('sweep2','nodeMesh_1')
mc.parent('|nodeMesh_1', 'NodeMeshGrp')
else:
for c in nodeGrp:
indexNumber = c.split('_')[-1]
curveShapes = mc.listRelatives(c, shapes=True, fullPath=True)
mc.connectAttr((curveShapes[0] + ".worldSpace[0]"), (sweepNodeB[0] + ".inCurveArray[" + str(indexNumber) + "]"), force=True)
mc.createNode("mesh", name="sweepShape" + str(indexNumber))
mc.connectAttr((sweepNodeB[0] + ".outMeshArray[" + str(indexNumber) + "]"),("sweepShape" + str(indexNumber) + ".inMesh"), force=True)
mc.sets(('sweep' + str(indexNumber)), edit=True, forceElement="initialShadingGroup")
mc.rename( ('sweep' + str(indexNumber)) ,('nodeMesh_' + str(indexNumber)))
mc.parent(('nodeMesh_' + str(indexNumber)) ,'NodeMeshGrp')
#connectSweepNode
mc.connectAttr((sweepNode[0] + ".scaleProfileX"),(sweepNodeB[0] + ".scaleProfileX"),force=True)
mc.select(cl=1)
def recreate_curve(original_curve):
shapes = mc.listRelatives('nodeCurve_1', shapes=True, noIntermediate=True)
curve_shape = shapes[0]
degree = mc.getAttr(curve_shape + ".degree")
cv_list = mc.ls('nodeCurve_1' + ".cv[*]", flatten=True)
points = [mc.pointPosition(cv, world=True) for cv in cv_list]
simplified_points = [[round(coord, 3) for coord in point] for point in points]
def createTieCurve():
simplified_points = [[1.322, -0.373, 0.494], [2.125, 0.006, 0.969], [2.211, 0.705, 1.113], [2.264, 1.24, 0.61], [2.256, 1.511, -0.076], [2.241, 1.307, -0.879], [2.475, 0.496, -1.235], [2.67, -0.385, -1.097], [2.534, -1.166, -0.638], [2.011, -1.554, 0.226], [1.523, -1.545, 0.81], [1.09, -1.255, 1.045], [0.762, -0.726, 1.017], [0.614, -0.148, 0.749], [0.713, 0.348, 0.377], [1.267, 0.62, 0.078], [2.354, 0.526, -0.017]]
new_curve = mc.curve(p=simplified_points, d=3, name="nodeCurve_1")
return new_curve
def createNodeCurve():
simplified_points =[[2.27, 2.2, -2.0], [2.67, 1.9, -1.3], [2.97, 1.1, 0.0], [2.77, 0.0, 1.6], [2.87, -1.1, 1.4], [2.77, -1.8, 0.7], [2.87, -1.7, -0.2], [3.07, -0.9, -0.8], [3.97, 0.2, -0.6], [4.27, 0.8, 0.5], [3.77, 1.2, 0.9], [3.17, 1.4, 1.1], [2.47, 1.4, 0.8], [2.07, 1.1, 0.3], [1.97, 0.9, -0.7], [1.97, 0.1, -1.3], [1.97, -0.7, -1.1], [1.77, -1.4, -0.8], [1.57, -1.8, -0.2], [1.47, -1.9, 0.6], [1.47, -1.3, 1.4], [1.47, -0.4, 1.8], [1.37, 0.7, 1.6], [1.17, 1.4, 0.9], [0.97, 1.5, 0.0], [0.77, 1.3, -0.8], [0.57, 0.6, -1.4], [0.27, -0.7, -1.6], [0.27, -1.7, -0.7], [0.17, -1.8, 0.3], [-0.13, -1.4, 0.9], [-0.23, -0.8, 1.5], [-0.23, 0.1, 1.6], [-0.33, 1.0, 1.1], [-0.53, 1.4, 0.5], [-0.63, 1.4, -0.2], [-0.53, 1.0, -0.7], [0.27, 0.4, -0.7], [2.07, -0.5, -0.7]]
new_curve = mc.curve(p=simplified_points, d=3, name="nodeCurve_1")
return new_curve
def longest_neighbor_cv_distance(curve):
cvs = mc.ls(curve + ".cv[*]", flatten=True)
if not cvs or len(cvs) < 2:
raise RuntimeError("Curve has less than 2 CVs: " + curve)
max_dist = 0.0
longest_pair = (None, None)
for i in range(len(cvs) - 1):
pos1 = mc.pointPosition(cvs[i], world=True)
pos2 = mc.pointPosition(cvs[i+1], world=True)
dx = pos2[0] - pos1[0]
dy = pos2[1] - pos1[1]
dz = pos2[2] - pos1[2]
dist = math.sqrt(dx*dx + dy*dy + dz*dz)
if dist > max_dist:
max_dist = dist
longest_pair = (i, i+1)
return longest_pair, max_dist
def createNodesTie(curveName):
newNodeNameA = createTieCurve()
pair, distance = longest_neighbor_cv_distance(curveName)
random_num = random.uniform(pair[0], pair[1])
pos0 = mc.pointOnCurve(curveName, pr= random_num, p=True)
pos1 = mc.pointOnCurve(curveName, pr= (random_num+0.1), p=True)
mc.xform(newNodeNameA, ws=True, t=pos0)
direction = [pos1[i] - pos0[i] for i in range(3)]
rot = mc.angleBetween(euler=True, v1=[1, 0, 0], v2=direction)
mc.xform(newNodeNameA, ws=True, ro=rot)
rotRand = random.uniform(0, 360)
mc.setAttr(newNodeNameA+ '.rotateX',rotRand)
return newNodeNameA
def createNodesEnd(curveName):
newNodeNameA = createNodeCurve()
pos0 = mc.pointOnCurve(curveName, pr= 0.01, p=True)
pos1 = mc.pointOnCurve(curveName, pr= 0.02, p=True)
mc.xform(newNodeNameA, ws=True, t=pos0)
direction = [pos1[i] - pos0[i] for i in range(3)]
rot = mc.angleBetween(euler=True, v1=[1, 0, 0], v2=direction)
mc.xform(newNodeNameA, ws=True, ro=rot)
rotRand = random.uniform(0, 360)
mc.setAttr(newNodeNameA+ '.rotateX',rotRand)
newNodeNameB = createNodeCurve()
pos0 = mc.pointOnCurve(curveName, pr=0.99, p=True)
pos1 = mc.pointOnCurve(curveName, pr=0.98, p=True)
mc.xform(newNodeNameB, ws=True, t=pos0)
direction = [pos1[i] - pos0[i] for i in range(3)]
rot = mc.angleBetween(euler=True, v1=[1, 0, 0], v2=direction)
mc.xform(newNodeNameB, ws=True, ro=rot)
rotRand = random.uniform(0, 360)
mc.setAttr(newNodeNameB+ '.rotateX',rotRand)
return newNodeNameA ,newNodeNameB
def InstantTie():
if mc.window("InstantTieUI", exists=True):
mc.deleteUI("InstantTieUI")
mc.window("InstantTieUI", title="Instant Tie v1.0", widthHeight=(320, 130),mxb = False, mnb = False, s = 1 )
mc.columnLayout(adjustableColumn=True)
mc.text(l=' ',h=3)
mc.columnLayout()
mc.columnLayout(adjustableColumn=True)
mc.floatSliderGrp('rtSize', v = 1, min = 0.1, max = 5, s = 0.1, cw3 = [60,30,190] , label = "Thickness: " ,field =True,h=20)
mc.floatSliderGrp('rtPrecision', v = 50, min = 0, max = 100, s = 1, cw3 = [60,30,190] , label = "Precision: " ,field =True,h=20)
mc.floatSliderGrp('rtDropRandom', v = 0, min = 0, max = 10, s = 1, cw3 = [60,30,190] , label = "Droop: " ,field =True, en=0,h=20)
mc.setParent( '..' )
mc.rowColumnLayout(nc= 4 ,cw=[(1,200),(2,50),(3,5),(4,30)])
mc.floatSliderGrp('rtRopeTwist', v = 0, min = 0, max = 20, fmx = 100, s = 0.1, cw3 = [60,30,190] , label = "Twist: " ,field =True,en=0)
mc.button('ropeOnButton', label='twist', command=lambda *args: ropeMode())
mc.text(l=' ')
mc.button('ropeOffButton',label='off', command=lambda *args: ropeModeOff(),en=0)
mc.setParent( '..' )
mc.text(l=' ')
mc.rowColumnLayout(nc= 4 ,cw=[(1,10),(2,170),(3,20),(4,85)])
mc.text(l=' ')
mc.radioButtonGrp('rtType', nrb=2, sl=1, label='Type: ', labelArray2=['Tie', 'Rope'], cw = [(1,50),(2,50)],cc = lambda *args: ropeRandSwitch())
mc.text(l=' ')
mc.checkBox('autoNodeButton', label= "Auto Node" ,v=1)
mc.setParent( '..' )
mc.rowColumnLayout(nc= 2 ,cw=[(1,70),(2,170)])
mc.text(l=' ')
mc.button(label='go', command=lambda *args: instantTieGo())
mc.text(l=' ')
mc.showWindow("InstantTieUI")
InstantTie()