## Find Euler rotation values of Maya matrix

Sparse posting lately: New home + new job = very busy

From over on my Mel Wiki, I’ve finally figure out (thanks to this post) how to extract Euler rotation values from a Maya matrix via the OpenMaya Python API. Not sure why I’ve wanted to know how to do this, but I’m glad I now can.

Note: Below is all updated bloggin’ goodness (as of 2011-02-18) from the original post, since I’ve learned some new tricks:

—-

After learning more from the API, I realized the differences between the MMatrix class and the MTransformationMatrix class: `MMatrix`

purely holds matrix data, not unlike a `MVector`

storing vector data and nothing else. the `MTransformationMatrix`

does everything a `MMatrix`

does, but it has knowledge of how Maya wants it, so provides many convenience methods for accessing the data and interaction with a Maya transform node..

The big takeaway I found is this: `MTransformationMatrix`

objects will keep track of rotations past 360 degrees & rotation order of the node, while `MMatrix`

objects will not. It makes sense: A matrix itself stores orientations as vectors, which have no concept how how far they’ve been ‘rotated’, so the `MMatrix`

object doesn’t track this data. But behind the scenes, the `MTransformationMatrix`

*does* track this info, which the below examples illustrate.

One more very important piece of data: When extracting a `MTransformationMatrix`

from a node via a `MFnTransform`

function, what you’re actually getting is the *local transformation matrix* of that node (since the `MTransformationMatrix`

appears to track transformations *specific to that node*, relative to its parent). So if you were expecting the world-space matrix, prepare to be disappointed. You can build a `MTransformationMatrix `

out of a worldspace-acquired `MMatrix`

, but at that point ‘rotations past 360’ would be lost.

# Python code import math import maya.cmds as mc import maya.OpenMaya as om # Define a node to pull a matrix from. node = 'pCube1' # Set some rotation values for comparison later: mc.setAttr('%s.rotate'%node, 15, -45, 1000) mc.setAttr('%s.scale'%node, 3, 3, 3) # Change the rot order, to make sure returned euler values are correct: mc.setAttr('%s.rotateOrder'%node, 3)

**Method A: Using MTransformationMatrix**

This, in my opinion, is the best solution. Via the API, you get an `MDagPath`

object for your node, wrapper it in a `MFnTransform `

object, and then directly extract a `MTransformationMatrix`

object from it. This object tracks the rotation order (so you don’t have to), and rotation values past 360.

#------------------------------------------- # Part 1: Get a MTransformationMatrix from an object for the sake of the example. # You can use your own MTransformationMatrix if it already exists of course. # get a MDagPath for our node: selList = om.MSelectionList() # make a sel list # MSelectionList selList.add(node) # add our node by name mDagPath = om.MDagPath() # create an empty dag path # MDagPath selList.getDagPath(0, mDagPath) # fill the dag path with our node # Create a MFnTransform object for our MDagPath, # and extract a MTransformationMatrix from it: transformFunc = om.MFnTransform(mDagPath) # MFnTransform mTransformMtx = transformFunc.transformation() # MTransformationMatrix #------------------------------------------- # Part 2, get the euler values # Get an MEulerRotation object eulerRot = mTransformMtx.eulerRotation() # MEulerRotation # note, we *don't* have to set the rot order here... # Convert from radians to degrees: angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)] print angles, "MTransformationMatrix"

**Method B: Using MMatrix**

While this method works well, it doesn’t track rotation values past 360: We create a `MMatrix`

object directly from the `worldMatrix`

attr queried on our node. We then convert that to a `MTransformationMatrix`

object so we can extract the `MEulerRotation `

object. However, the `MMatrix`

doesn’t pass along the rotation order of the node, and has no knowledge of rotations past 360, so the resultant `MTransformationMatrix`

won’t know that stuff either. To get accurate rotation values, we have to save the rotation order value ahead of time, and then apply it back before retrieving values from our `MEulreRotation`

object.

#------------------------------------------- # Part 1: Get a MMatrix from an object for the sake of the example. # You can use your own MMatrix if it already exists of course. # Get the node's rotate order value: rotOrder = mc.getAttr('%s.rotateOrder'%node) # Get the world matrix as a list matrixList = mc.getAttr('%s.worldMatrix'%node) # len(matrixList) = 16 # Create an empty MMatrix: mMatrix = om.MMatrix() # MMatrix # And populate the MMatrix object with the matrix list data: om.MScriptUtil.createMatrixFromList(matrixList, mMatrix) #------------------------------------------- # Part 2, get the euler values # Convert to MTransformationMatrix to extract rotations: mTransformMtx = om.MTransformationMatrix(mMatrix) # Get an MEulerRotation object eulerRot = mTransformMtx.eulerRotation() # MEulerRotation # Update rotate order to match original object, since the orig MMatrix has # no knoweldge of it: eulerRot.reorderIt(rotOrder) # Convert from radians to degrees: angles = [math.degrees(angle) for angle in (eulerRot.x, eulerRot.y, eulerRot.z)] print angles, "MMatrix"

Running the above code prints (and I reformatted the float precision issues, just so it’s easier to compare to the above values):

[15, -45, 1000] MTransformationMatrix [15, -45, -80] MMatrix

As you can see, the `MTransformationMatrix`

stores the rotation values past 360 deg, while the `MMatrix`

doesn’t.