如何在Python for Maya中分解矩阵?

2024-06-28 20:08:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试编写一个脚本,它可以在不依赖于父约束的情况下,将平移和旋转从子对象传递到父对象,反之亦然。过去几天我一直在使用矩阵信息研究这个问题,但我是Python和矩阵的初学者

到目前为止,我已经能够找到我想要的矩阵并对其应用正确的计算,但我无法将这些矩阵转换回常规Maya值。本质上,我试图复制Maya中“decomposeMatrix”节点所做的任何事情

经过大量的研究和测试,我非常确定OpenMaya的mtTransformationMatrix函数是我所需要的,但我无法让它工作,我不知道如何编写/使用它,它使用了什么参数,等等

如果我在正确的轨道上,我需要什么来完成这项工作?如果我正在处理一些更大的需要更多编码的事情,我也有兴趣了解更多

代码如下:

import maya.cmds as mc

import maya.OpenMaya as OpenMaya

def myM():

    tlm = MMatrix(cmds.getAttr('TRAJ.matrix'))

    pwm = MMatrix(cmds.getAttr('TRAJ.worldMatrix'))

    pim = MMatrix(cmds.getAttr('TRAJ.parentInverseMatrix'))
    
    prod = tlm * pwm * pim

    return prod
    
    tMat = OpenMaya.MTransformationMatrix(prod)
    print tMat
    
    
myM()

编辑

我在上面的代码中误用了return。今天重新测试代码(以及实现Klaudikus的建议时),我得到以下错误:

Error: TypeError: file /home/Maya_2020_DI/build/RelWithDebInfo/runTime/lib/python2.7/site-packages/maya/OpenMaya.py line 7945: in method 'new_MMatrix', argument 1 of type 'float const [4][4]' #


Tags: 对象代码importas矩阵prod事情cmds
2条回答

多亏了克劳迪库斯和我的坚忍不拔,我终于成功了。它可能看起来有点不像话,但对我来说已经足够好了!当然,它确实需要用户友好的优化(这是我的下一步),但核心思想是可行的。它可能使在子对象和父对象之间交换对象位置比捕捉或父约束更快

import maya.cmds as cmds
from maya.api.OpenMaya import MMatrix
import pymel.core as pm

def myM():
    tlmList = cmds.getAttr('TRAJ.matrix')
    tlm = MMatrix(tlmList)

    pwmList = cmds.getAttr('PARENT1.worldMatrix')
    pwm = MMatrix(pwmList)

    pimList = cmds.getAttr('PARENT0.worldInverseMatrix')
    pim = MMatrix(pimList)



    prod = tlm * pwm * pim



    pm.xform('PARENT1', m=([prod[0],prod[1],prod[2],prod[3],prod[4],prod[5],prod[6],prod[7],prod[8],prod[9],prod[10],prod[11],prod[12],prod[13],prod[14],prod[15]]))



myM()

我假设您理解脚本所做的工作,但为了以防万一,我将重述:

  • 获取TRAJ的局部矩阵值,并根据这些值创建新的MMatrix对象
  • 获取TRAJ的世界矩阵值,并根据这些值创建新的MMatrix对象
  • 获取TRAJ的父逆矩阵,并根据这些值创建新的MMatrix对象
  • 将上述三个矩阵相乘,并将得到的MMatrix存储在prod中
  • 回程针

正如halfer所说,函数的其余部分将被忽略,因为return将退出函数。这里有一些应该有用的东西

# here you typed:
# import maya.cmds as mc
# but further below used the cmds.getAttr...
# I decided to change the import statement instead
import maya.cmds as cmds

# MMatrix is a class within OpenMaya
# when using it, you must reference the module first then the class/object as so:
#     my_matrix = OpenMaya.MMatrix()
import maya.OpenMaya as OpenMaya


def myM():
    tlm = OpenMaya.MMatrix(cmds.getAttr('TRAJ.matrix'))
    pwm = OpenMaya.MMatrix(cmds.getAttr('TRAJ.worldMatrix'))
    pim = OpenMaya.MMatrix(cmds.getAttr('TRAJ.parentInverseMatrix'))
    prod = tlm * pwm * pim

    # check the documentation at:
    # https://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=__py_ref_class_open_maya_1_1_m_transformation_matrix_html
    # here I'm "creating" an MTransformationMatrix with the MMatrix stored in prod
    tMat = OpenMaya.MTransformationMatrix(prod)

    # this is how you get the data from this object
    # translation is an MVector object
    translation = tMat.translation(OpenMaya.MSpace.kObject)
    
    # eulerRotation is a MEulerRotation object
    eulerRotation = tMat.rotation(asQuaternion=False)
    

    # typically you'll return these values
    return translation, eulerRotation

TRAJ_trans, TRAJ_rot = myM()

但这并不是真的有用。首先,函数myM应该真正采用参数,这样您就可以重用它,并从场景中的任何对象(而不仅仅是TRANJ)获得平移和旋转。第二,你做的数学对我来说没有意义。我不是数学家,但这里你要用局部矩阵乘以世界矩阵,再乘以父矩阵的逆局部矩阵。老实说,我无法告诉你这是怎么回事,但据我所知,这很可能是无用的。我不会详细讨论矩阵,因为它是一个野兽般的主题,而且你似乎已经走上了这条道路,但简而言之:

obj_local_matrix = obj_world_matrix * inverse_parent_world_matrix
obj_world_matrix = obj_local_matrix * parent_world_matrix

另一种书写方式是:

obj_relative_to_other_matrix = obj_world_matrix * inverse_other_world_matrix
obj_world_matrix = obj_relative_to_other_matrix * other_world_matrix

这本质上是决定父节点之间关系的数学。但是,只要有一个节点的世界矩阵,就可以获得该节点相对于任何其他节点的变换值,而不考虑其父节点。注意顺序在这里很重要,因为矩阵乘法不是可交换的A*B!=B*A

我从你的问题中得到的是,你试图得到一个物体的相对变换,到场景中另一个物体的相对变换。以下函数返回一个对象相对于另一个对象的位置、旋转和缩放

def relative_trs(obj_name, other_obj_name):
    """
    Returns the position, rotation and scale of one object relative to another.

    :param obj_name:
    :param other_obj_name:
    :return:
    """
    obj_world_matrix = OpenMaya.MMatrix(cmds.getAttr('{}.worldMatrix'.format(obj_name)))
    other_obj_world_matrix = OpenMaya.MMatrix(cmds.getAttr('{}.worldMatrix'.format(other_obj_name)))
    
    # multiplying the world matrix of one object by the inverse of the world matrix of another, gives you it's relative matrix of the object to the other
    matrix_product = obj_world_matrix * other_obj_world_matrix.inverse()
    trans_matrix = OpenMaya.MTransformationMatrix(matrix_product)
    translation = trans_matrix.translation(OpenMaya.MSpace.kObject)
    euler_rotation = trans_matrix.rotation(asQuaternion=False)
    scale = trans_matrix.scale(OpenMaya.MSpace.kObject)
    return list(translation), list(euler_rotation), list(scale)

您可以通过创建两个层次结构来测试该函数,并在一个层次结构的叶节点和另一个层次结构中的任何节点之间运行该函数。存储结果。然后将叶节点对象重新设置为其他层次中的叶节点对象的父对象,并检查其局部坐标。它们应该与存储的结果相匹配。这本质上就是父约束的工作方式

相关问题 更多 >