Posts Tagged ‘ euler

## 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
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.