485 lines
18 KiB
Python
485 lines
18 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
import maya.cmds as mc
|
||
|
import maya.mel as mel
|
||
|
import maya.OpenMaya as om
|
||
|
import maya.OpenMayaUI as omui
|
||
|
from maya.OpenMaya import MGlobal
|
||
|
import math
|
||
|
import maya.api.OpenMaya as oma
|
||
|
import re
|
||
|
|
||
|
|
||
|
|
||
|
def run():
|
||
|
cleanList = ('instPicker','instRot')
|
||
|
for c in cleanList:
|
||
|
if mc.objExists(c):
|
||
|
mc.delete(c)
|
||
|
global ctx
|
||
|
ctx = 'Click2dTo3dCtx'
|
||
|
global storeHitFace
|
||
|
storeHitFace =''
|
||
|
if mc.draggerContext(ctx, exists=True):
|
||
|
mc.deleteUI(ctx)
|
||
|
mc.draggerContext(ctx, pressCommand = instDragPick, rc = instDragClean, dragCommand = instDragMove, name=ctx, cursor='crossHair',undoMode='step')
|
||
|
mc.setToolTo(ctx)
|
||
|
|
||
|
|
||
|
|
||
|
def instDragPick():
|
||
|
preSelect = mc.ls(sl=1,fl=1,l=1)
|
||
|
global ctx
|
||
|
global screenX,screenY
|
||
|
global checkScreenMeshList
|
||
|
global storeCameraPosition
|
||
|
global storeMeshNode
|
||
|
global parentDir
|
||
|
global targetMeshName
|
||
|
global instDul
|
||
|
global storeHitFace
|
||
|
global cameraFarClip
|
||
|
global storeRotCount
|
||
|
global lockCount
|
||
|
global edgeAlignRecord
|
||
|
edgeAlignRecord = 0
|
||
|
storeRotCount = 0
|
||
|
vpX, vpY, _ = mc.draggerContext(ctx, query=True, anchorPoint=True)
|
||
|
screenX = vpX
|
||
|
screenY = vpY
|
||
|
pos = om.MPoint()
|
||
|
dir = om.MVector()
|
||
|
omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir)
|
||
|
pos2 = om.MFloatPoint(pos.x, pos.y, pos.z)
|
||
|
view = omui.M3dView.active3dView()
|
||
|
cam = om.MDagPath()
|
||
|
view.getCamera(cam)
|
||
|
camPath = cam.fullPathName()
|
||
|
cameraTrans = mc.listRelatives(camPath,type='transform',p=True)
|
||
|
cameraFarClip = mc.getAttr(cameraTrans[0]+'.farClipPlane')
|
||
|
storeCameraPosition = mc.xform(cameraTrans,q=1,ws=1,rp=1)
|
||
|
##########################################################
|
||
|
storeMeshNode=[]
|
||
|
instDul = 0
|
||
|
checkHit = 0
|
||
|
finalMesh = []
|
||
|
shortDistance = cameraFarClip
|
||
|
distanceBetween = cameraFarClip
|
||
|
hitpoint = om.MFloatPoint()
|
||
|
hitFace = om.MScriptUtil()
|
||
|
hitFace.createFromInt(0)
|
||
|
hitFacePtr = hitFace.asIntPtr()
|
||
|
##########################################################
|
||
|
checkScreenMeshList = screenVisPoly()
|
||
|
for mesh in checkScreenMeshList:
|
||
|
selectionList = om.MSelectionList()
|
||
|
selectionList.add(mesh)
|
||
|
dagPath = om.MDagPath()
|
||
|
selectionList.getDagPath(0, dagPath)
|
||
|
fnMesh = om.MFnMesh(dagPath)
|
||
|
intersection = fnMesh.closestIntersection(
|
||
|
om.MFloatPoint(pos2),
|
||
|
om.MFloatVector(dir),
|
||
|
None,
|
||
|
None,
|
||
|
False,
|
||
|
om.MSpace.kWorld,
|
||
|
cameraFarClip,
|
||
|
False,
|
||
|
None,
|
||
|
hitpoint,
|
||
|
None,
|
||
|
hitFacePtr,
|
||
|
None,
|
||
|
None,
|
||
|
None)
|
||
|
if intersection:
|
||
|
x = hitpoint.x
|
||
|
y = hitpoint.y
|
||
|
z = hitpoint.z
|
||
|
distanceBetween = math.sqrt( ((float(storeCameraPosition[0]) - x)**2) + ((float(storeCameraPosition[1]) - y)**2) + ((float(storeCameraPosition[2]) - z)**2))
|
||
|
if distanceBetween < shortDistance:
|
||
|
shortDistance = distanceBetween
|
||
|
finalMesh = mesh
|
||
|
if preSelect:
|
||
|
checkShape = mc.listRelatives(preSelect, shapes=True, fullPath=True)
|
||
|
finalMesh = checkShape
|
||
|
|
||
|
if len(finalMesh) > 0:
|
||
|
#preSelect = mc.ls(sl=1,fl=1,l=1)
|
||
|
#checkShape = mc.listRelatives(preSelect, shapes=True, fullPath=True)
|
||
|
#finalMesh = checkShape
|
||
|
storeMeshNode=mc.listRelatives(finalMesh,type='transform',p=True,f=True)
|
||
|
shapeNode = mc.listRelatives(storeMeshNode[0], fullPath=True,ad=True )
|
||
|
parentDir = '|'.join(storeMeshNode[0].split('|')[0:-1])
|
||
|
targetMeshName = storeMeshNode[0].split('|')[-1]
|
||
|
#move pivot to bbox base
|
||
|
rotSave = mc.getAttr(targetMeshName + '.rotate')
|
||
|
posSave = mc.xform(targetMeshName, q=True, ws=True, piv=True)[:3]
|
||
|
mc.setAttr(targetMeshName + '.rotate',0,0,0)
|
||
|
bbox = mc.exactWorldBoundingBox(targetMeshName)
|
||
|
base_position = bbox[1]
|
||
|
mc.move(posSave[0], base_position, posSave[2] , (targetMeshName+ '.scalePivot'), (targetMeshName + '.rotatePivot'), ws=True)
|
||
|
|
||
|
##########################################################
|
||
|
mc.group(empty=1,n ='instPicker')
|
||
|
mc.duplicate('instPicker')
|
||
|
mc.rename('instRot')
|
||
|
mc.parent('instRot','instPicker')
|
||
|
mc.select('instPicker',storeMeshNode[0])
|
||
|
mc.matchTransform(pos=1,rot=1)
|
||
|
mc.parent(storeMeshNode[0],'instRot')
|
||
|
mc.select('instPicker|instRot|'+targetMeshName)
|
||
|
mc.setAttr('instPicker.rotate',rotSave[0][0],rotSave[0][1],rotSave[0][2])
|
||
|
mc.makeIdentity(apply=True, t=1, r=1, s=1, n=0)
|
||
|
mc.delete(constructionHistory=True)
|
||
|
##########################################################
|
||
|
for s in shapeNode:
|
||
|
if s in checkScreenMeshList:
|
||
|
checkScreenMeshList.remove(s)
|
||
|
currentRoteY = mc.getAttr('instRot.rotateY')
|
||
|
lockCount = int(currentRoteY / 15)*15
|
||
|
|
||
|
def instDragClean():
|
||
|
global parentDir
|
||
|
global targetMeshName
|
||
|
global instDul
|
||
|
global edgeAlignRecord
|
||
|
edgeAlignRecord = 0
|
||
|
if mc.objExists('instPicker'):
|
||
|
if len(parentDir) == 0:
|
||
|
mc.select('instPicker|instRot|'+targetMeshName)
|
||
|
mc.parent(w=1)
|
||
|
else:
|
||
|
mc.parent(('|instPicker|instRot|'+targetMeshName),(parentDir))
|
||
|
|
||
|
cleanList = ('instPicker','instRot')
|
||
|
for c in cleanList:
|
||
|
if mc.objExists(c):
|
||
|
mc.delete(c)
|
||
|
instDul = 0
|
||
|
mc.select(cl=1)
|
||
|
|
||
|
def instDragMove():
|
||
|
global screenX
|
||
|
global storeMeshNode
|
||
|
global storeHitFace
|
||
|
global cameraFarClip
|
||
|
global storeRotCount
|
||
|
global storeRotCount
|
||
|
global lockCount
|
||
|
global edgeAlignRecord
|
||
|
if storeMeshNode:
|
||
|
if mc.objExists('instPicker'):
|
||
|
global ctx
|
||
|
global screenX,screenY
|
||
|
global storeCameraPosition
|
||
|
global checkScreenMeshList
|
||
|
global parentDir
|
||
|
global targetMeshName
|
||
|
global instDul
|
||
|
|
||
|
modifiers = mc.getModifiers()
|
||
|
vpX, vpY, _ = mc.draggerContext(ctx, query=True, dragPoint=True)
|
||
|
|
||
|
if (modifiers == 4):
|
||
|
#press Ctrl ----> rotate
|
||
|
if screenX > vpX:
|
||
|
lockCount = lockCount - 2
|
||
|
else:
|
||
|
lockCount = lockCount + 2
|
||
|
screenX = vpX
|
||
|
if lockCount < -360:
|
||
|
lockCount = -360
|
||
|
elif lockCount > 360:
|
||
|
lockCount = 360
|
||
|
|
||
|
getX = int(lockCount / 15)*15
|
||
|
|
||
|
if storeRotCount != getX:
|
||
|
storeRotCount = getX
|
||
|
mc.setAttr('instRot.rotateY',storeRotCount)
|
||
|
mc.refresh(cv=True,f=True)
|
||
|
elif(modifiers == 5):
|
||
|
#press Shift + Ctrl
|
||
|
if edgeAlignRecord == 0:
|
||
|
alignEdge()
|
||
|
edgeAlignRecord = 1
|
||
|
mc.refresh(cv=True,f=True)
|
||
|
elif(modifiers == 1):
|
||
|
#press Shift -----> dulpicate current mesh
|
||
|
if instDul == 0:
|
||
|
newD = mc.duplicate(('|instPicker|instRot|'+targetMeshName),rr=1)
|
||
|
if len(parentDir) == 0:
|
||
|
mc.select('instPicker|instRot|'+targetMeshName)
|
||
|
mc.parent(w=1)
|
||
|
else:
|
||
|
mc.parent(('|instPicker|instRot|'+targetMeshName),(parentDir))
|
||
|
targetMeshName = newD[0]
|
||
|
mc.select(targetMeshName)
|
||
|
instDul = 1
|
||
|
mc.refresh(cv=True,f=True)
|
||
|
else:
|
||
|
pos = om.MPoint()
|
||
|
dir = om.MVector()
|
||
|
omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir)
|
||
|
pos2 = om.MFloatPoint(pos.x, pos.y, pos.z)
|
||
|
############################################################
|
||
|
checkHit = 0
|
||
|
finalMesh = ''
|
||
|
hitFaceName = ''
|
||
|
finalX = 0
|
||
|
finalY = 0
|
||
|
finalZ = 0
|
||
|
shortDistance = cameraFarClip
|
||
|
distanceBetween = cameraFarClip
|
||
|
hitpoint = om.MFloatPoint()
|
||
|
hitFace = om.MScriptUtil()
|
||
|
hitFace.createFromInt(0)
|
||
|
hitFacePtr = hitFace.asIntPtr()
|
||
|
############################################################
|
||
|
for mesh in checkScreenMeshList:
|
||
|
selectionList = om.MSelectionList()
|
||
|
selectionList.add(mesh)
|
||
|
dagPath = om.MDagPath()
|
||
|
selectionList.getDagPath(0, dagPath)
|
||
|
fnMesh = om.MFnMesh(dagPath)
|
||
|
intersection = fnMesh.closestIntersection(
|
||
|
om.MFloatPoint(pos2),
|
||
|
om.MFloatVector(dir),
|
||
|
None,
|
||
|
None,
|
||
|
False,
|
||
|
om.MSpace.kWorld,
|
||
|
cameraFarClip,
|
||
|
False,
|
||
|
None,
|
||
|
hitpoint,
|
||
|
None,
|
||
|
hitFacePtr,
|
||
|
None,
|
||
|
None,
|
||
|
None)
|
||
|
if intersection:
|
||
|
x = hitpoint.x
|
||
|
y = hitpoint.y
|
||
|
z = hitpoint.z
|
||
|
distanceBetween = math.sqrt( ((float(storeCameraPosition[0]) - x)**2) + ((float(storeCameraPosition[1]) - y)**2) + ((float(storeCameraPosition[2]) - z)**2))
|
||
|
if distanceBetween < shortDistance:
|
||
|
shortDistance = distanceBetween
|
||
|
finalMesh = mesh
|
||
|
|
||
|
if finalMesh:
|
||
|
selectionList = om.MSelectionList()
|
||
|
selectionList.add(finalMesh)
|
||
|
dagPath = om.MDagPath()
|
||
|
selectionList.getDagPath(0, dagPath)
|
||
|
fnMesh = om.MFnMesh(dagPath)
|
||
|
intersection = fnMesh.closestIntersection(
|
||
|
om.MFloatPoint(pos2),
|
||
|
om.MFloatVector(dir),
|
||
|
None,
|
||
|
None,
|
||
|
False,
|
||
|
om.MSpace.kWorld,
|
||
|
cameraFarClip,
|
||
|
False,
|
||
|
None,
|
||
|
hitpoint,
|
||
|
None,
|
||
|
hitFacePtr,
|
||
|
None,
|
||
|
None,
|
||
|
None)
|
||
|
finalX = hitpoint.x
|
||
|
finalY = hitpoint.y
|
||
|
finalZ = hitpoint.z
|
||
|
hitFace = om.MScriptUtil(hitFacePtr).asInt()
|
||
|
hitFaceName = (finalMesh + '.f[' + str(hitFace) +']')
|
||
|
instDul = 0
|
||
|
mc.setAttr('instPicker.translate', finalX,finalY,finalZ)
|
||
|
if storeHitFace != hitFaceName:
|
||
|
rx, ry, rz = checkFaceAngle(hitFaceName)
|
||
|
mc.setAttr('instPicker.rotate', rx,ry,rz)
|
||
|
storeHitFace = hitFaceName
|
||
|
mc.refresh(cv=True,f=True)
|
||
|
|
||
|
|
||
|
def screenVisPoly():
|
||
|
commonList= []
|
||
|
view = omui.M3dView.active3dView()
|
||
|
om.MGlobal.selectFromScreen(0, 0, view.portWidth(), view.portHeight(), om.MGlobal.kReplaceList)
|
||
|
objects = om.MSelectionList()
|
||
|
sel = om.MSelectionList()
|
||
|
om.MGlobal.getActiveSelectionList(objects)
|
||
|
om.MGlobal.setActiveSelectionList(sel, om.MGlobal.kReplaceList)
|
||
|
fromScreen = []
|
||
|
objects.getSelectionStrings(fromScreen)
|
||
|
shapesOnScreen = mc.listRelatives(fromScreen, shapes=True,f=True)
|
||
|
meshList = mc.ls(type='mesh',l=True)#only polygon
|
||
|
if len(meshList)>0 and shapesOnScreen is not None:
|
||
|
commonList = list(set(meshList) & set(shapesOnScreen))
|
||
|
return commonList
|
||
|
else:
|
||
|
commonList = []
|
||
|
return commonList
|
||
|
|
||
|
|
||
|
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 alignEdge():
|
||
|
mesh=mc.ls(sl=1,fl=1)
|
||
|
if len(mesh) == 1:
|
||
|
checkLongName = mc.ls(mesh[0],l=1)
|
||
|
parentNode = checkLongName[0].split('|')
|
||
|
if len(parentNode) > 2:
|
||
|
outParent = ''
|
||
|
outParent = '|'.join(parentNode[1:-1])
|
||
|
mc.parent(mesh[0],w=1)
|
||
|
cleanList = ('sampleCurv*','sampleMes*','rotationPlan*')
|
||
|
for c in cleanList:
|
||
|
if mc.objExists(c):
|
||
|
mc.delete(c)
|
||
|
gface, gHitp,cEdge,cEdgePos = getClosestEdge()
|
||
|
mc.select(cEdge)
|
||
|
checkCVList=mc.ls( mc.polyListComponentConversion (cEdge,fe=True,tv=True),flatten=True)
|
||
|
mx,my,mz = mc.pointPosition(checkCVList[0],w=1)
|
||
|
mc.polyPlane(w=1, h=1, sx=1, sy=1, ax=(0,1,0), cuv=2, ch=0, n='rotationPlane')
|
||
|
mc.polyCreateFacet( p=[(mx, my, mz),(cEdgePos[0], cEdgePos[1], cEdgePos[2]),(gHitp[0], gHitp[1], gHitp[2])] )
|
||
|
mc.rename('sampleMesh')
|
||
|
mc.select("rotationPlane.vtx[0:2]", "sampleMesh.vtx[0:2]")
|
||
|
CMD = 'snap3PointsTo3Points(0);'
|
||
|
mel.eval(CMD)
|
||
|
mc.parent(mesh[0],'rotationPlane')
|
||
|
axes = ["X", "Y", "Z"]
|
||
|
for a in axes:
|
||
|
val = mc.getAttr( mesh[0] + ".rotate" + a)
|
||
|
valTmp = ''
|
||
|
if val > 0:
|
||
|
valTmp = val + 45
|
||
|
else:
|
||
|
valTmp = val - 45
|
||
|
valNew = int (valTmp/90)
|
||
|
mc.setAttr(( mesh[0] + ".rotate" + a), (valNew*90))
|
||
|
|
||
|
mc.move(gHitp[0], gHitp[1], gHitp[2], mesh[0], rpr=True,wd=True)
|
||
|
mc.select(mesh[0])
|
||
|
mc.parent(w=1)
|
||
|
if len(parentNode) > 2:
|
||
|
mc.parent(mesh[0],outParent)
|
||
|
for c in cleanList:
|
||
|
if mc.objExists(c):
|
||
|
mc.delete(c)
|
||
|
|
||
|
|
||
|
|
||
|
def getClosestEdge():
|
||
|
mayaMesh = mc.ls(sl=1,fl=1)
|
||
|
gFace = ''
|
||
|
gHitP = ''
|
||
|
gFace,gHitP = getClosestMeshHit(mayaMesh[0])
|
||
|
listF2E=mc.ls( mc.polyListComponentConversion (gFace,ff=True,te=True),flatten=True)
|
||
|
cEdge = ''
|
||
|
smallestDist = 1000000
|
||
|
cEdgePos = []
|
||
|
for l in listF2E:
|
||
|
mc.select(l)
|
||
|
mc.polyToCurve(form=2, degree=1, conformToSmoothMeshPreview=1)
|
||
|
sampleCurve = mc.ls(sl=1)
|
||
|
selectionList = om.MSelectionList()
|
||
|
selectionList.add(sampleCurve[0])
|
||
|
dagPath = om.MDagPath()
|
||
|
selectionList.getDagPath(0, dagPath)
|
||
|
omCurveOut = om.MFnNurbsCurve(dagPath)
|
||
|
pointInSpace = om.MPoint(gHitP[0],gHitP[1],gHitP[2])
|
||
|
closestPoint = om.MPoint()
|
||
|
closestPoint = omCurveOut.closestPoint(pointInSpace)
|
||
|
getDist = math.sqrt( ((closestPoint[0] - gHitP[0])**2) + ((closestPoint[1]- gHitP[1])**2) + ((closestPoint[2] - gHitP[2])**2))
|
||
|
if getDist < smallestDist:
|
||
|
smallestDist = getDist
|
||
|
cEdge = l
|
||
|
cEdgePos = [closestPoint[0],closestPoint[1],closestPoint[2]]
|
||
|
mc.delete(sampleCurve)
|
||
|
mc.select(cEdge)
|
||
|
return(gFace,gHitP,cEdge,cEdgePos)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
def getClosestMeshHit(mayaMesh):
|
||
|
myShape = mc.listRelatives(mayaMesh, f=True,ad =True)
|
||
|
checkList = screenVisPoly()
|
||
|
removeList = list(set(checkList) - set(myShape))
|
||
|
checkList = removeList
|
||
|
meshPos = mc.xform(mayaMesh,q=1, ws=1, a=1, piv=1)
|
||
|
posXXX = [meshPos[0],meshPos[1],meshPos[2]]
|
||
|
shortDistanceCheck = 10000
|
||
|
resultFace = []
|
||
|
resultCV =[]
|
||
|
resultHitPoint = []
|
||
|
for c in checkList:
|
||
|
transNode = mc.listRelatives(c, p=True,f=True)
|
||
|
getFaceDist,getFace,getHitPoint = getClosestPointOnFace(transNode[0],posXXX)
|
||
|
#print(getCV, getFaceDist, getFace)
|
||
|
if getFaceDist < shortDistanceCheck:
|
||
|
shortDistanceCheck = getFaceDist
|
||
|
resultFace = getFace
|
||
|
resultHitPoint = getHitPoint
|
||
|
return (resultFace,resultHitPoint)
|
||
|
|
||
|
|
||
|
|
||
|
def getClosestPointOnFace(mayaMesh,pos=[0,0,0]):
|
||
|
mVector = oma.MVector(pos)#using MVector type to represent position
|
||
|
selectionList = oma.MSelectionList()
|
||
|
selectionList.add(mayaMesh)
|
||
|
dPath= selectionList.getDagPath(0)
|
||
|
mMesh=oma.MFnMesh(dPath)
|
||
|
ID = mMesh.getClosestPoint(oma.MPoint(mVector),space=oma.MSpace.kWorld)[1] #getting closest face ID
|
||
|
closestPoint= mMesh.getClosestPoint(oma.MPoint(mVector),space=oma.MSpace.kWorld)[0]
|
||
|
cpx = closestPoint[0]
|
||
|
cpy = closestPoint[1]
|
||
|
cpz = closestPoint[2]
|
||
|
hitPointPosition = [cpx,cpy,cpz]
|
||
|
hitFaceName = (mayaMesh+'.f['+str(ID)+']')
|
||
|
getFaceDist = math.sqrt( ((pos[0] - cpx)**2) + ((pos[1]- cpy)**2) + ((pos[2] - cpz)**2))
|
||
|
return (getFaceDist, hitFaceName,hitPointPosition)
|
||
|
|
||
|
|
||
|
def getPolyFaceCenter(faceName):
|
||
|
meshFaceName = faceName.split('.')[0]
|
||
|
findVtx = mc.polyInfo(faceName, fv=1)
|
||
|
getNumber = []
|
||
|
checkNumber = ((findVtx[0].split(':')[1]).split('\n')[0]).split(' ')
|
||
|
for c in checkNumber:
|
||
|
findNumber = ''.join([n for n in c.split('|')[-1] if n.isdigit()])
|
||
|
if findNumber:
|
||
|
getNumber.append(findNumber)
|
||
|
centerX = 0
|
||
|
centerY = 0
|
||
|
centerZ = 0
|
||
|
for g in getNumber:
|
||
|
x,y,z = mc.pointPosition((meshFaceName + '.vtx['+g + ']'),w=1)
|
||
|
centerX = centerX + x
|
||
|
centerY = centerY + y
|
||
|
centerZ = centerZ + z
|
||
|
|
||
|
centerX = centerX/len(getNumber)
|
||
|
centerY = centerY/len(getNumber)
|
||
|
centerZ = centerZ/len(getNumber)
|
||
|
return centerX,centerY,centerZ
|