instantDrag for Maya脚本 (移动模型时沿目标模型移动)

这是一个Maya脚本,名为instantDrag,允许用户在移动模型时使其沿目标模型表面移动。用户可以使用快捷键进行旋转、缩放、复制和对齐等操作。该脚本适用于各种情况,无需预先选择模型,并且提供了一些版本更新和修复记录。
摘要由CSDN通过智能技术生成

​​

只需单击 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()​​​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

首条

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值