赞
踩
只需单击 Maya 中的命令按钮一次,即可在移动模型时沿目标模型移动
InstantDrag allow user to simply click and drag mesh on another surface.
It can work in any situation. no mesh pre-select is required, once the tool is activated, just simply click and drag on any mesh which is on top of another surface.
hotKey for quick adjustment:
## hotKey :
## + Ctrl ----> rotate
## + Shift & Ctrl ----> scale
## + Shift ----> duplicate current mesh
## + Alt ----> snap to face center or vertex
## + Alt & Shilt ----> force center pivot and snap mesh to surface
let me know what you think, and happy to hear any suggestions to make the tool simple but more functional.
version Note
1.03 reMap hotkey so it's easier to use
1.02 add instant duplicate
1.01 fix bug when there is no mesh underneath at initial click
1.0 First version for public test
Maya运行Python:
##--------------------------------------------------------------------------
##
## ScriptName : instantDrag
## Contents : click and drag model on top of surface
## Author : Joe Wu
## URL : http://im3djoe.com
## Since : 2022/01/
## Version : 1.0 First version for public test
## : 1.01 fix bug when there is no mesh underneath at initial click
## : 1.02 add instant duplicate
## : 1.03 reMap hotkey
## Install :
## copy and paste entire code to a pyhotn script editor
## run it.
## or
## drag entire code to shelf to make a button.
##--------------------------------------------------------------------------
## hotKey :
## + Ctrl ----> rotate
## + Shift & Ctrl ----> scale
## + Shift ----> duplicate current mesh
## + Alt ----> snap to face center or vertex
## + Alt & Shilt ----> force center pivot and snap mesh to surface
##
##--------------------------------------------------------------------------
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
from pymel.core.datatypes import Vector, Matrix, Point
import pymel.core as pm
import re
def instantDrag():
cleanList = ('instPicker','instRot')
for c in cleanList:
if mc.objExists(c):
mc.delete(c)
global ctx
ctx = 'Click2dTo3dCtx'
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():
global ctx
global currentRotRecord
global screenX,screenY
global checkScreenMeshList
global storeCameraPosition
global storePos2
global storeDir
global storeMeshNode
global storeWRotX
global storeWRotY
global storeWRotZ
global parentDir
global storeMeshNode
global targetMeshName
global instDul
instDul = 0
vpX, vpY, _ = mc.draggerContext(ctx, query=True, anchorPoint=True)
screenX = vpX
screenY = vpY
pos = om.MPoint()
dir = om.MVector()
hitpoint = om.MFloatPoint()
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)
storeCameraPosition = mc.xform(cameraTrans,q=1,ws=1,rp=1)
checkHit = 0
finalMesh = []
shortDistance = 10000000000
distanceBetween = 1000000000
hitFacePtr = om.MScriptUtil().asIntPtr()
hitFace = []
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,
99999,
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
#finalMesh = mc.ls(sl=1,fl=1,l=1)
if len(finalMesh) > 0:
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]
for s in shapeNode:
if s in checkScreenMeshList:
checkScreenMeshList.remove(s)
finalX = []
finalY = []
finalZ = []
hitFace = []
snapMesh = []
shortDistance = 10000000000
distanceBetween = 1000000000
for snap in checkScreenMeshList:
selectionList = om.MSelectionList()
selectionList.add(snap)
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,
99999,
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
snapMesh = snap
finalX = x
finalY = y
finalZ = z
hitFace = om.MScriptUtil(hitFacePtr).asInt()
if hitFace:
hitFaceName = (snapMesh + '.f[' + str(hitFace) +']')
rx, ry, rz = checkFaceAngle(hitFaceName)
mc.group(empty=1,n ='instPicker')
mc.duplicate('instPicker')
mc.rename('instRot')
mc.parent('instRot','instPicker')
mc.setAttr('instPicker.translateX', finalX)
mc.setAttr('instPicker.translateY', finalY)
mc.setAttr('instPicker.translateZ', finalZ)
mc.setAttr('instPicker.rotateX', rx)
mc.setAttr('instPicker.rotateY', ry)
mc.setAttr('instPicker.rotateZ', rz)
mc.parent(storeMeshNode[0],'instRot')
else:
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.refresh(cv=True,f=True)
def instDragClean():
global parentDir
global targetMeshName
global instDul
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
def instDragMove():
global storeMeshNode
if storeMeshNode:
if mc.objExists('instPicker'):
global ctx
global screenX,screenY
global storeCameraPosition
global checkScreenMeshList
global storeWRotX
global storeWRotY
global storeWRotZ
global parentDir
global targetMeshName
global instDul
modifiers = mc.getModifiers()
if (modifiers == 4):
#press Ctrl
vpX, vpY, _ = mc.draggerContext(ctx, query=True, dragPoint=True)
distanceCheck = vpX - screenX
screenX = vpX
currentRoteY = mc.getAttr('instRot.rotateY')
if distanceCheck > 0.1:
currentRoteY = currentRoteY + 1
elif distanceCheck < 0.1:
currentRoteY = currentRoteY - 1
mc.setAttr('instRot.rotateY',currentRoteY)
elif(modifiers == 5):
#press Shift
vpX, vpY, _ = mc.draggerContext(ctx, query=True, dragPoint=True)
distanceCheck = vpX - screenX
screenX = vpX
currentScale = mc.getAttr('instRot.scaleX')
if distanceCheck > 0.1:
currentScale = currentScale + 0.01
elif distanceCheck < 0.1:
currentScale = currentScale - 0.01
mc.setAttr('instRot.scaleX',currentScale)
mc.setAttr('instRot.scaleY',currentScale)
mc.setAttr('instRot.scaleZ',currentScale)
elif(modifiers == 9):
#press Alt + Shift
#force snap to surface
targetPivot = mc.xform(('|instPicker|instRot|'+targetMeshName),q=1, rp=1, ws=1)
sourcePivot = mc.xform(('instRot'),q=1, rp=1, ws=1)
if targetPivot != sourcePivot:
mc.xform(('|instPicker|instRot|'+targetMeshName),cpc=1)
mc.matchTransform(('|instPicker|instRot|'+targetMeshName),'instRot',pos=1)
elif(modifiers == 1):
#press Alt + Ctrl
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:
instDul = 0
vpX, vpY, _ = mc.draggerContext(ctx, query=True, dragPoint=True)
pos = om.MPoint()
dir = om.MVector()
hitpoint = om.MFloatPoint()
omui.M3dView().active3dView().viewToWorld(int(vpX), int(vpY), pos, dir)
pos2 = om.MFloatPoint(pos.x, pos.y, pos.z)
checkHit = 0
finalMesh = []
finalX = 0
finalY = 0
finalZ = 0
shortDistance = 10000000000
distanceBetween = 1000000000
hitFacePtr = om.MScriptUtil().asIntPtr()
hitFace = []
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,
99999,
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
hitFace = om.MScriptUtil(hitFacePtr).asInt()
finalX = x
finalY = y
finalZ = z
hitFaceName = (finalMesh + '.f[' + str(hitFace) +']')
if (modifiers == 8):
cpX,cpY,cpZ = getPolyFaceCenter(hitFaceName)
checkFaceCenterDist = math.sqrt( ((cpX - finalX)**2) + ((cpY- finalY)**2) + ((cpZ - finalZ)**2))
cvX = 0
cvY = 0
cvZ = 0
shortDistanceCheck = 10000
checkCVDistance = 10000
cvList = (mc.polyInfo(hitFaceName , fv=True )[0]).split(':')[-1].split(' ')
cvList = [x for x in cvList if x.strip()]
mostCloseCVPoint = []
for v in cvList:
checkNumber = ''.join([n for n in v.split('|')[-1] if n.isdigit()])
if len(checkNumber) > 0:
cvPoint = (finalMesh + '.vtx[' + str(checkNumber) +']')
cvPosition = mc.pointPosition(cvPoint)
checkCVDistance = math.sqrt( ((float(cvPosition[0]) - finalX)**2) + ((float(cvPosition[1]) - finalY)**2) + ((float(cvPosition[2]) - finalZ)**2))
if checkCVDistance < shortDistanceCheck:
shortDistanceCheck = checkCVDistance
cvX = float(cvPosition[0])
cvY = float(cvPosition[1])
cvZ = float(cvPosition[2])
mostCloseCVPoint = cvPoint
if shortDistanceCheck < checkFaceCenterDist:
mc.setAttr('instPicker.translateX', cvX)
mc.setAttr('instPicker.translateY', cvY)
mc.setAttr('instPicker.translateZ', cvZ)
rx,ry,rz = avgVertexNormalAngle(mostCloseCVPoint)
mc.setAttr('instPicker.rotateX', rx)
mc.setAttr('instPicker.rotateY', ry)
mc.setAttr('instPicker.rotateZ', rz)
else:
mc.setAttr('instPicker.translateX', cpX)
mc.setAttr('instPicker.translateY', cpY)
mc.setAttr('instPicker.translateZ', cpZ)
rx, ry, rz = checkFaceAngle(hitFaceName)
mc.setAttr('instPicker.rotateX', rx)
mc.setAttr('instPicker.rotateY', ry)
mc.setAttr('instPicker.rotateZ', rz)
else:
mc.setAttr('instPicker.translateX', finalX)
mc.setAttr('instPicker.translateY', finalY)
mc.setAttr('instPicker.translateZ', finalZ)
rx, ry, rz = checkFaceAngle(hitFaceName)
mc.setAttr('instPicker.rotateX', rx)
mc.setAttr('instPicker.rotateY', ry)
mc.setAttr('instPicker.rotateZ', rz)
mc.refresh(cv=True,f=True)
def avgVertexNormalAngle(vertexName):
shapeNode = mc.listRelatives(vertexName, fullPath=True , parent=True )
transformNode = mc.listRelatives(shapeNode[0], fullPath=True , parent=True )
faceList = (mc.polyInfo(vertexName , vf=True )[0]).split(':')[-1].split(' ')
faceList = [x for x in faceList if x.strip()]
getMeAngle=[]
sumX = 0
sumY = 0
sumZ = 0
for f in faceList:
checkNumber = ''.join([n for n in f.split('|')[-1] if n.isdigit()])
if len(checkNumber) > 0:
rx, ry, rz = checkFaceAngle((transformNode[0] + '.f[' + str(checkNumber) +']'))
sumX = sumX + rx
sumY = sumY + ry
sumZ = sumZ + rz
avgX = sumX /len(faceList)
avgY = sumY /len(faceList)
avgZ = sumZ /len(faceList)
return avgX, avgY, avgZ
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
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 = Matrix(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 = Vector(face_normals) * obj_matrix
upvector = om.MVector (0,1,0)
getHitNormal = v
quat = om.MQuaternion(upvector, getHitNormal)
quatAsEuler = om.MEulerRotation()
quatAsEuler = quat.asEulerRotation()
rx, ry, rz = math.degrees(quatAsEuler.x), math.degrees(quatAsEuler.y), math.degrees(quatAsEuler.z)
return rx, ry, rz
def avgVertexNormalAngle(vertexName):
shapeNode = mc.listRelatives(vertexName, fullPath=True , parent=True )
transformNode = mc.listRelatives(shapeNode[0], fullPath=True , parent=True )
faceList = (mc.polyInfo(vertexName , vf=True )[0]).split(':')[-1].split(' ')
faceList = [x for x in faceList if x.strip()]
getMeAngle=[]
sumX = 0
sumY = 0
sumZ = 0
for f in faceList:
checkNumber = ''.join([n for n in f.split('|')[-1] if n.isdigit()])
if len(checkNumber) > 0:
rx, ry, rz = checkFaceAngle((transformNode[0] + '.f[' + str(checkNumber) +']'))
sumX = sumX + rx
sumY = sumY + ry
sumZ = sumZ + rz
avgX = sumX /len(faceList)
avgY = sumY /len(faceList)
avgZ = sumZ /len(faceList)
return avgX, avgY, avgZ
instantDrag()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。