maya的orientJoint功能没有反应
显示joint的轴,
将joint的Rotate属性转移到JointOrient上
joint的X轴对准子物体(调整orient,不考虑rotate)
from maya import cmds
from maya import OpenMaya as OM
import math
def CreateGUI():
windowID = "OrientJointsUI"
if cmds.window(windowID, query = True, exists = True):
cmds.deleteUI(windowID)
cmds.window(windowID)
cmds.showWindow()
entireUI = cmds.columnLayout()
# 轴可视化
cmds.setParent(entireUI)
jointVisualUI = cmds.frameLayout("Visualize Joint Axes", collapsable = True, backgroundColor = [0.0, 0.6,0.6])
cmds.setParent(jointVisualUI)
cmds.rowLayout(numberOfColumns = 3)
jointVisualUICheck1 = cmds.checkBox("VisualizeOn", label = "VisualizeOn", value = True)
jointVisualUICheck2 = cmds.checkBox("Change Child Joint",label = "Change Child Joint", value = True)
def DisplayJointsLocalAxis(*args):
dispalyOn = cmds.checkBox(jointVisualUICheck1, query = True, value = True)
cmds.checkBox(jointVisualUICheck1, edit = True, value = not dispalyOn)
affectChild = cmds.checkBox(jointVisualUICheck2, query = True, value = True)
selectedObjs = cmds.ls(selection = True)
for i in selectedObjs:
DisplayJointAxis(i, dispalyOn, affectChild)
cmds.button(label = "DisplayJointsLocalAxis", command = DisplayJointsLocalAxis)
# 将joint的 rotate属性转为jointOrient属性
cmds.setParent(entireUI)
jointRotateToOrientUI = cmds.frameLayout("Joint Rotate to Orient", collapsable = True, backgroundColor = [0.0, 0.6,0.6], annotation = "convert jointRotateAttr to jointOrientAttr")
cmds.setParent(jointRotateToOrientUI)
cmds.rowLayout(numberOfColumns = 2)
jointRotateToOrientCheck = cmds.checkBox("Orient Child Joint",label = "Change Child Joint", value = False)
def ApplyConversion(*argus):
selectedObjs = cmds.ls(selection = True)
affectChild = cmds.checkBox(jointRotateToOrientCheck, query = True, value = True)
for i in selectedObjs:
ConvertRotateToOrient(i, affectChild)
cmds.button(label = "Convert", command = ApplyConversion)
# 调整joint轴向
cmds.setParent(entireUI)
jointOrientUI = cmds.frameLayout("Orient Joints", collapsable = True, backgroundColor = [0.0, 0.6,0.6])
cmds.setParent(jointOrientUI)
cmds.rowLayout(numberOfColumns = 3)
jointOrientUICheck1 = cmds.checkBox("Average Vector", label = "Average Vector", annotation = "if false, use first child joint to calculate; if true, use the average of childOrientVectors", value = False)
jointOrientUICheck2 = cmds.checkBox("Orient Child Joint",label = "Change Child Joint", value = False)
def ApplyOrientJoints(argumentbool):
averageOn = cmds.checkBox(jointOrientUICheck1, query = True, value = True)
affectChild = cmds.checkBox(jointOrientUICheck2, query = True, value = True)
selectedObjs = cmds.ls(selection = True)
for i in selectedObjs:
OrientJoint(i, averageOn, affectChild)
cmds.button(label = "OrientJoints", command = ApplyOrientJoints)
def DisplayJointAxis(obj:str, show:bool = True,showItsChildren:bool = False):
if(cmds.objectType(obj) != "joint"):
print(obj + "is not joint")
else:
cmds.setAttr(obj + ".displayLocalAxis", show)
if(showItsChildren):
children = cmds.listRelatives(obj, children = True)
if(children):
for i in children:
DisplayJointAxis(i, show, showItsChildren)
def ConvertRotateToOrient(obj:str, affectChild):
if(cmds.objectType(obj) != "joint"):
print(obj + "is not joint")
else:
Q_rotate = GetRotate(obj + ".rotate").asQuaternion()
Q_orient = GetRotate(obj + ".jointOrient").asQuaternion()
Q_orient = Q_rotate * Q_orient
SetRotate(obj + ".rotate", OM.MEulerRotation(0.0, 0.0, 0.0))
SetRotate(obj + ".jointOrient", Q_orient.asEulerRotation())
children = cmds.listRelatives(obj, children = True)
if(affectChild and children):
for child in children:
ConvertRotateToOrient(child, affectChild)
def OrientJoint(obj: str, averageOfChildrenVectors: bool, orientChild: bool):
children = []
if(cmds.objectType(obj) != "joint"):
print(obj + "is not joint")
else:
orientAxis = OM.MVector(1.0, 0.0, 0.0)
orientDir = OM.MVector()
children = cmds.listRelatives(obj, children = True)
parents = cmds.listRelatives(obj, parent = True)
if(children): #存在子物体
if(averageOfChildrenVectors): #子物体的平均方向
for child in children:
if(cmds.objectType(child) == "joint"):
orientDir += GetTranslate(child + ".translate").normal()
else: #第一个子物体的方向
orientDir = GetTranslate(children[0] + ".translate")
if(orientAxis * orientDir.normal() == 1.0 or orientDir == OM.MVector(0.0, 0.0, 0.0)):
pass
else:
# obj 旋转变换
deltaAngle = orientDir.angle(orientAxis)
deltaRotateAxis = orientAxis^orientDir
Q_new_to_obj = OM.MQuaternion(deltaAngle, deltaRotateAxis)
Q_obj_to_new = Q_new_to_obj.inverse()
# PrintEuler( Q_new_to_obj.asEulerRotation())
# PrintEuler( Q_obj_to_new.asEulerRotation())
# 纠正obj joint的朝向
Q_obj_to_parent = GetRotate(obj + ".jointOrient").asQuaternion()
Q_new_to_parent = Q_new_to_obj * Q_obj_to_parent
SetRotate(obj + ".jointOrient", Q_new_to_parent.asEulerRotation())
# 纠正child joint的变换,保证其对parent位置不变
for child in children:
# 调整 children joint的位置
childTranslate = GetTranslate(child + ".translate")
childNewTranslate = childTranslate * (Q_obj_to_new.asMatrix())
SetTranslate(child + ".translate", childNewTranslate)
# 恢复 children joint的朝向
Q_child_to_obj = GetRotate(child + ".jointOrient").asQuaternion()
Q_child_to_new = Q_child_to_obj * Q_obj_to_new
SetRotate(child + ".jointOrient", Q_child_to_new.asEulerRotation())
elif(parents): #不存在子物体,对齐父物体
orientDir = GetTranslate(obj + ".translate")
Q_obj_to_parent = GetRotate(obj + ".jointOrient").asQuaternion()
orientDir = orientDir * (Q_obj_to_parent.inverse()).asMatrix()
deltaAngle = orientDir.angle(orientAxis)
deltaRotateAxis = orientAxis^orientDir
Q_new_to_obj = OM.MQuaternion(deltaAngle, deltaRotateAxis)
Q_obj_to_new = Q_new_to_obj.inverse()
# 纠正obj joint的朝向
Q_obj_to_parent = GetRotate(obj + ".jointOrient").asQuaternion()
Q_new_to_parent = Q_new_to_obj * Q_obj_to_parent
SetRotate(obj + ".jointOrient", Q_new_to_parent.asEulerRotation())
return
else:
return
if(orientChild):
if(children):
for i in children:
OrientJoint(i, averageOfChildrenVectors, orientChild)
def SetTranslate(objAttrName:str, translate:OM.MVector):
cmds.setAttr(objAttrName, translate[0], translate[1], translate[2])
def GetTranslate(objAttrName:str)->OM.MVector:
trans = cmds.getAttr(objAttrName)[0]
return OM.MVector(trans[0], trans[1], trans[2])
def SetRotate(objAttrName:str, rotate:OM.MEulerRotation):
rotate *= (180.0/math.pi)
cmds.setAttr(objAttrName,rotate[0], rotate[1], rotate[2])
def GetRotate(objAttrName:str)->OM.MEulerRotation:
trans = cmds.getAttr(objAttrName)[0]
return OM.MEulerRotation(trans[0], trans[1], trans[2]) * (math.pi/180.0)
def PrintEuler(euler:OM.MEulerRotation):
euler *= (180.0/math.pi)
print(euler.x, euler.y, euler.z)
def PrintVector(vector:OM.MVector):
print(vector.x, vector.y, vector.z)
CreateGUI()