Maya OrientJoint Python

 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()


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值