Wednesday, April 10, 2013

Getting dat Matrix: Maya Python API 2.0

3 comments
So I've been delving in the Maya Python API lately and having lots of fun with matrices. I couldn't find a lot of info for using API 2.0 with matrices.

In this script example, there are two functions, one that gets a worldMatrix of an object and one that decomposes a matrix into translation, rotation, and scale. I think I've annotated it pretty well, but a big thing to note is that if you freeze translation on an object, it won't return the correct world values for the object you input.

Just change the nodeName to your object name and run the script.

import maya.cmds as cmds
import maya.api.OpenMaya as OpenMaya
import math
import sys

def getMatrix(node):
 '''
 Gets the world matrix of an object based on name.
 '''
 #Selection list object and MObject for our matrix
 selection = OpenMaya.MSelectionList()
 matrixObject = OpenMaya.MObject()
 
 #Adding object
 selection.add(node)
 
 #New api is nice since it will just return an MObject instead of taking two arguments.
 MObjectA = selection.getDependNode(0)
 
 #Dependency node so we can get the worldMatrix attribute
 fnThisNode = OpenMaya.MFnDependencyNode(MObjectA)
 
 #Get it's world matrix plug
 worldMatrixAttr = fnThisNode.attribute( "worldMatrix" )
 
 #Getting mPlug by plugging in our MObject and attribute
 matrixPlug = OpenMaya.MPlug( MObjectA, worldMatrixAttr )
 matrixPlug = matrixPlug.elementByLogicalIndex( 0 )
 
 #Get matrix plug as MObject so we can get it's data.
 matrixObject = matrixPlug.asMObject(  )
 
 #Finally get the data
 worldMatrixData = OpenMaya.MFnMatrixData( matrixObject )
 worldMatrix = worldMatrixData.matrix( )
 
 return worldMatrix

def decompMatrix(node,matrix):
 '''
 Decomposes a MMatrix in new api. Returns an list of translation,rotation,scale in world space.
 '''
 #Rotate order of object
 rotOrder = cmds.getAttr('%s.rotateOrder'%node)
 
 #Puts matrix into transformation matrix
 mTransformMtx = OpenMaya.MTransformationMatrix(matrix)
 
 #Translation Values
 trans = mTransformMtx.translation(OpenMaya.MSpace.kWorld)
 
 #Euler rotation value in radians
 eulerRot = mTransformMtx.rotation()
 
 #Reorder rotation order based on ctrl.
 eulerRot.reorderIt(rotOrder)
 
 #Find degrees
 angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)]
 
 #Find world scale of our object.
 scale = mTransformMtx.scale(OpenMaya.MSpace.kWorld)

 #Return Values
 return [trans.x,trans.y,trans.z],angles,scale

#If we're in the main namespace run our stuffs!
if __name__ == '__main__':
 #Defining object name.
 nodeName = 'yourName'
 
 #Get Matrix
 mat = getMatrix(nodeName)
 
 #Decompose matrix
 matDecomp = decompMatrix(nodeName,mat)
 
 #Print our values
 sys.stdout.write('\n---------------------------%s---------------------------\n'%nodeName)
 sys.stdout.write('\nTranslation : %s' %matDecomp[0])
 sys.stdout.write('\nRotation    : %s' %matDecomp[1])
 sys.stdout.write('\nScale       : %s\n' %matDecomp[2])

You could very easily get an MMatrix using maya.cmds by just doing:

mat = OpenMaya.MMatrix(cmds.getAttr('YourNode.worldMatrix'))

But this will only work with the new API, not the old.