I'm trying to reconstruct a MTransformationMatrix from maya's MFnIkJoint in maya 2015. According to the docs the construction works as such: 

The transformation matrix for a joint node is below.

  • matrix = [S] * [RO] * [R] * [JO] * [IS] * [T]

(where '*' denotes matrix multiplication).

These matrices are defined as follows:

  • [S] : scale
  • [RO] : rotateOrient (attribute name is rotateAxis)
  • [R] : rotate
  • [JO] : jointOrient
  • [IS] : parentScaleInverse
  • [T] : translate

So I've followed that and written the code below. The problem is that the constructed matrix I created does not seem to respect joint orientation.

If I get the MTransformationMatrix directly from the MFnIkJoint function it somehow seems to store the joint orientation. Does anyone know where the MTransformationMatrix is storing joint orientation? It seems to be a mystery to me as it isn't in MTransformationMatrix::rotationOrientation or MTransformationMatrix::rotation.

import time
from maya import cmds
from maya import OpenMaya, OpenMayaAnim

# Make a joint
jnt = cmds.joint(orientation=[0, 45, 0])
jnt2 = cmds.joint(p=[2, 0, -2])

# get a dagPath
mSel = OpenMaya.MSelectionList()
dagPath = OpenMaya.MDagPath()
mSel.getDagPath(0, dagPath)

# Put it in MFnIkJoint function set
startJointFn = OpenMayaAnim.MFnIkJoint(dagPath)
initMatrix = startJointFn.transformation()

# Make a scale pointer
util = OpenMaya.MScriptUtil()
util.createFromList([1.0, 1.0, 1.0], 3)
scalePtr = util.asDoublePtr()

# Get scale
S_MTMatrix = OpenMaya.MTransformationMatrix()
S_MTMatrix.setScale(scalePtr, OpenMaya.MSpace.kTransform)
S = S_MTMatrix.asMatrix()

# Get rotate orientation
RO_Quat = OpenMaya.MQuaternion()
RO_MTMatrix = OpenMaya.MTransformationMatrix()
RO_MTMatrix.rotateBy(RO_Quat, OpenMaya.MSpace.kTransform)
RO = RO_MTMatrix.asMatrix()

# Get Rotation
R_Quat = OpenMaya.MQuaternion()
R_MTMatrix = OpenMaya.MTransformationMatrix()
R_MTMatrix.rotateBy(R_Quat, OpenMaya.MSpace.kTransform)
R = R_MTMatrix.asMatrix()

# Get joint orientation
JO_Quat = OpenMaya.MQuaternion()
JO_MTMatrix = OpenMaya.MTransformationMatrix()
JO_MTMatrix.rotateBy(JO_Quat, OpenMaya.MSpace.kTransform)
JO = JO_MTMatrix.asMatrix()

# Get inverse scale of parent.
parentMObj = startJointFn.parent(0)
if not parentMObj.apiTypeStr() == "kWorld":
parentFn = OpenMaya.MFnTransform(parentMObj)

IS_MTMatrix = OpenMaya.MTransformationMatrix()
IS_MTMatrix.setScale(scalePtr, OpenMaya.MSpace.kTransform)
IS = IS_MTMatrix.asMatrixInverse()

# Get Translation
T_Vector = startJointFn.getTranslation(OpenMaya.MSpace.kTransform)
T_MTMatrix = OpenMaya.MTransformationMatrix()
T_MTMatrix.setTranslation(T_Vector, OpenMaya.MSpace.kTransform)
T = T_MTMatrix.asMatrix()

# Multiply like the docs say.
matrix = S * RO * R * JO * IS * T

# Put it into MTransformationMatrix
TMatrix = OpenMaya.MTransformationMatrix(matrix)

# If the two MTransformationMatrices are equal.
if TMatrix.isEquivalent(initMatrix):

# Set joint to calculated matrix

# Wait 1 second and set it back to the inital transformation matrix from the joint function
# This is just to see the difference between the two transformation matrices.

Appreciate any help!

Quote 0 0
transformation matrix != transform/joint node and their underlying classes.
The MFnTransformNode for example does so much more work on top of a base xform matrix.
So you won't be able to replicate this without taking into consideration everything that is happening in the other classes.
You have a lot more to reconstruct. :)
Quote 0 0
The MFnTransformationMatrices are the equivalent though. Is there just not an way to change joint orientation in the MFnTransformationMatrix unless it comes from the function set?
Quote 0 0
4x4 matrix is a simple data container.
MTransformationMatrix wraps the 4x4 matrix and in addition provides basic functionality to describe 3D transformations like translate, rotate, scale, shear, etc.
MFnTransform builds on that to provide extra things like limit translation/rotation/scale, joint orientation, pivots.
It actually does much more than that, but that's another story.

The easiest way to achieve what you are after is to use this class and directly call its *Pivot methods.
You don't need to initialize it to existing object. Create a new class instance, stick the input values to it and get the result matrix. Code will be much shorter than what you have now.

But, back to your code.
It actually does the right thing.
I modified it slightly to make things easier for myself to understand.
Download the attached Maya scene and run the code below.

import time
from maya import cmds
from maya import OpenMaya, OpenMayaAnim
# get a dagPath
mSel = OpenMaya.MSelectionList()
dagPath = OpenMaya.MDagPath()
mSel.getDagPath(0, dagPath)
# Put it in MFnIkJoint function set
startJointFn = OpenMayaAnim.MFnIkJoint(dagPath)
initMatrix = startJointFn.transformation()
# Make a scale pointer
util = OpenMaya.MScriptUtil()
util.createFromList([1.0, 1.0, 1.0], 3)
scalePtr = util.asDoublePtr()
# Get scale
S_MTMatrix = OpenMaya.MTransformationMatrix()
S_MTMatrix.setScale(scalePtr, OpenMaya.MSpace.kTransform)
S = S_MTMatrix.asMatrix()
# Get rotate orientation
RO_Quat = OpenMaya.MQuaternion()
RO_MTMatrix = OpenMaya.MTransformationMatrix()
RO_MTMatrix.rotateBy(RO_Quat, OpenMaya.MSpace.kTransform)
RO = RO_MTMatrix.asMatrix()
# Get Rotation
R_Quat = OpenMaya.MQuaternion()
R_MTMatrix = OpenMaya.MTransformationMatrix()
R_MTMatrix.rotateBy(R_Quat, OpenMaya.MSpace.kTransform)
R = R_MTMatrix.asMatrix()
# Get joint orientation
JO_Quat = OpenMaya.MQuaternion()
JO_MTMatrix = OpenMaya.MTransformationMatrix()
JO_MTMatrix.rotateBy(JO_Quat, OpenMaya.MSpace.kTransform)
JO = JO_MTMatrix.asMatrix()
IS_MTMatrix = OpenMaya.MTransformationMatrix()
IS_MTMatrix.setScale(scalePtr, OpenMaya.MSpace.kTransform)
IS = IS_MTMatrix.asMatrixInverse()
# Get Translation
T_Vector = startJointFn.getTranslation(OpenMaya.MSpace.kTransform)
T_MTMatrix = OpenMaya.MTransformationMatrix()
T_MTMatrix.setTranslation(T_Vector, OpenMaya.MSpace.kTransform)
T = T_MTMatrix.asMatrix()
# Multiply like the docs say.
matrix = S * RO * R * JO * IS * T
# Put it into MTransformationMatrix
TMatrix = OpenMaya.MTransformationMatrix(matrix)
# Set joint to calculated matrix
mSel.getDagPath(1, dagPath)
endJointFn = OpenMayaAnim.MFnIkJoint(dagPath)

Notice how joint2 snaps to joint1. They look differently oriented on screen, but the parented under them cubes match orientation. This is because you are "flattening" the transformations, basically combining rotation and pivot orientation into rotation only.
If you create a joint and rotate it - it's on-screen representation will look as if is not rotated. That is controlled by the joint orientation.

Hope this makes sense.
Quote 1 0