990 lines
43 KiB
Python
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() |