Getting rotations beyond -180 to 180 degree range from matrix

1,145 views
Skip to first unread message

derek wong

unread,
Mar 19, 2018, 5:06:09 PM3/19/18
to Python Programming for Autodesk Maya
Hi,

So to start this off, I'm a novice at anything beyond scripting with maya commands, so I don't really know what I'm talking about.

In the test I am trying to do, I have 3 cubes (cubeA, cube B, and cubeC). I want to be able to rotate cubeC to (x, y, z) rotation, calculate what half of the rotational difference between cubeA and cubeC's matrices is, and use that to set cubeB's rotations to halfway between cubeA and cubeC's rotations.

eg. If cubeA's rotation is (0,0,0) and cubeC's rotation is (100,200,300), cubeB's rotation would be (50,100,150)

As far as I've been able to achieve, in the above scenario, my actual cubeB's rotation would end up being (50,-160,-60).

I'm trying to do this with matrices because I was told matrix math computes faster.

Should I even be trying to do this with matrices? Or is it more logical to just use the actual rotation values directly?

Thanks

Angelo Sta. Catalina

unread,
Mar 19, 2018, 5:22:17 PM3/19/18
to python_in...@googlegroups.com
This subject can get quite complicated. How exactly are you interpolating rotations with matrices in Maya? From a matrix, you have to extract the rotation matrix, then either convert it to euler rotations or quaternions before doing any kind of interpolation. 

Just calculate the rotations using the euler rotations using lerp. It's the fastest way to get any kind of interpolation. If you're animating through the different rotations and you need a smooth interpolation, consider looking into quaternion slerp or quaternional nlerp.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/ee8a3775-1b14-4485-8657-262963977112%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Marcus Ottosson

unread,
Mar 19, 2018, 6:03:34 PM3/19/18
to python_in...@googlegroups.com

If cubeA’s rotation is (0,0,0) and cubeC’s rotation is (100,200,300), cubeB’s rotation would be (50,100,150)

If this is what you’re looking to achieve, then you can achieve it by averaging each rotational channel individually.

cubeA = [0, 0, 0]
cubeC = [100, 200, 300]
cubeB = [
    (cubeA[axis] + cubeC[axis]) * 0.5
    for axis in range(3)
]

Which with nodes can be achieved with addDoubleLinear for the addition and multDoubleLinear for the multiplication.

This would support an infinite range of rotational values (and likely be faster than matrix multiplication). However, the result is likely not what you’d expect.. Simply averaging those values (known as “Euler Angles“) likely won’t look the way you’d expect. You can confirm this for yourself by taking an object, rotating it 90 degrees along e.g. Y such that two axes align, and then consider how you’d get the object to rotate along the axis you now longer have access to. The answer is simply, by adjusting multiple axes at once.

To get cube B visually oriented in between A and C, you’ll need to do what Angelo mentioned which is where things get complicated; Quaternions.

You can use Matrices, but you’ll run into oddities. I mocked up an example to illustrate.

from maya import cmds

cmds.file(new=True, force=True)
cmds.loadPlugin("matrixNodes", quiet=True)

cubeA, _ = cmds.polyCube(name="cubeA")
cubeB, _ = cmds.polyCube(name="cubeB")
cubeC, _ = cmds.polyCube(name="cubeC")

cmds.setAttr(cubeA + ".translate", *(0, 0, 0), type="double3")
cmds.setAttr(cubeB + ".translate", *(2, 0, 0), type="double3")
cmds.setAttr(cubeC + ".translate", *(4, 0, 0), type="double3")
cmds.setAttr(cubeC + ".rotate", *[0, 20, 0], type="double3")

average = cmds.createNode("wtAddMatrix")
decompose = cmds.createNode("decomposeMatrix")
cmds.connectAttr(cubeA + ".matrix", average + ".wtMatrix[0].matrixIn")
cmds.connectAttr(cubeC + ".matrix", average + ".wtMatrix[1].matrixIn")
cmds.connectAttr(average + ".matrixSum", decompose + ".inputMatrix")
cmds.connectAttr(decompose + ".outputRotate", cubeB + ".rotate")
cmds.setAttr(average + ".wtMatrix[0].weightIn", 0.5)
cmds.setAttr(average + ".wtMatrix[1].weightIn", 0.5)

Try your hand at rotating this around, and notice how at some point it’ll start to flip and behave oddly. Especially at the values you provided, (100, 200, 300).

Finally, to answer the question in your title, matrices can’t give you Euler angles past 180 degrees. I’ll have to let someone who knows more about why explain the why, but I suspect it has something to do with how the angles in a matrix relate to sine and cosine?

derek wong

unread,
Mar 19, 2018, 6:52:20 PM3/19/18
to Python Programming for Autodesk Maya
I was getting the arccos of dot products between cubeA and cubeC to determine angular differences.

I just wasn't sure if I was using the entirely wrong method, or if I was ignorant about something that would make it work, but now I know it was the former.

Thanks for the help!

Michael Boon

unread,
Mar 20, 2018, 8:52:01 PM3/20/18
to Python Programming for Autodesk Maya
In most cases, if you're trying to average rotations, quaternions will give you much more intuitive results. Quaternions don't get gimbal lock, so they don't do weird things when the euler angles get near 90 degrees. One weird thing they do (which might suit you given the subject) is that they support angles up to +-360 degrees.

If you use the OpenMaya.MQuaternion class, it has a slerp function that will do your interpolation for you.

Generally speaking (though it will depend on your specific code) quaternions are faster than matrices or euler angles for interpolating angles too.

However off the top of my head, I can't remember how to get or set object rotation as quaternion in Maya. Someone else might know?

justin hidair

unread,
Mar 20, 2018, 10:02:21 PM3/20/18
to python_in...@googlegroups.com

You need to use MQuaternion , go take a look at MFnTransform or MFnTransformation ( I don’t know which it is)  and see the parts where it mentions MQuaternion , can’t remember it at the top of my head but you can have any angle with your quaternion in radians of course so past 180 deg like you want ( pi ) past 360 degrees ( 2 pi ) …

 

Sent from Mail for Windows 10

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/c5861edd-f7b8-476f-838a-6bfd73251aa7%40googlegroups.com.

Marcus Ottosson

unread,
Mar 21, 2018, 3:53:56 AM3/21/18
to python_in...@googlegroups.com

If getting it through nodes, there’s decomposeMatrix which has a quaternion output, along with a eulerToQuat node. Don’t know whether there’s any way to interpolate quaternions with any of the native nodes however?

Joe Weidenbach

unread,
Mar 21, 2018, 4:29:52 AM3/21/18
to python_in...@googlegroups.com
It's generally not the best idea to use something just because people say it's faster.  It's better to get correct behaviour and then optimise.

Quaternions will allow you to handle angles from -360 to 360, but there's one more piece you need if you're interpolating. You need to keep track of the delta in angle between the two sources, and note when it crosses 180 degrees, because quaternion slerp will always return the shortest rotation, so will need to be flipped if that delta has been crossed. The most reliable way to do this is to use the original euler angles and just average them before constructing your new rotation.

In the case you're describing, for the Z rotations you have a delta of 200 degrees, so quaternions could return the 160 degree rotation in the other direction instead to reach that orientation, and in that case, without the original eulers to inform the decision you'll have no information to choose to use the inverse quaternion instead.  This isn't an issue for the actual rotation, as visually it will look the same, but once you start averaging, you've now got an 80 degree rotation in one direction versus a 100 degree rotation on the other side.  Those look very different, and that's why you have that pop when you cross a 180 degree delta.

As to performance, yes, matrices and quaternions are going to be quicker than other methods that have to do more work, but you throw away data to get that speed boost, and the maya nodes with direct connections are still going to use the matrices under the hood to find your final transform.  In this case (averaging rotation), you've got three additions, and three multiplications, which is far faster than using a matrix.  You could achieve the whole thing with a single plusMinusAverage node (or if you prefer to avoid unit conversions, 3 addDoubleLinears and 3 multDoubleLinears). That's going to be way faster than the matrix operations (which have, for each of 16 elements, four multiplications and three additions).

A note that none of this will take into account offsets or parent spaces.  Those you'd have to handle as well for all but the simplest cases, and for those the matrix nodes would not go amiss once you understand the maths driving them.

Hope that helps,

Joe

Joe Weidenbach

unread,
Mar 21, 2018, 4:30:49 AM3/21/18
to python_in...@googlegroups.com
To Marcus' question on quaternion interpolation, yes, there's the quatSlerp node :)

Joe Weidenbach

unread,
Mar 21, 2018, 4:42:51 AM3/21/18
to python_in...@googlegroups.com
Also, I should note that the solution I mentioned also doesn't take into account rotation order.  That's a big area where matrices or quaternions would have strength for this.  But again, it also isn't about 'quaternions are always better.'  They're certainly better at some things, but at the end of the day, matrices, quaternions, and eulers are just tools you need to pick and choose as appropriate for your case.

Marcus Ottosson

unread,
Mar 21, 2018, 4:56:09 AM3/21/18
to python_in...@googlegroups.com

quatSlerp

Oooo that sounded too good to be true, so I had a look and found none (in Maya 2015). :O Could you be referring to this one? https://github.com/yantor3d/quatExtras


To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAM33%3Da5dr8M%3DSkOXyER2HjQ99vYh1ed3NuiQTay27dP12y0YjQ%40mail.gmail.com.

Joe Weidenbach

unread,
Mar 21, 2018, 5:20:10 AM3/21/18
to python_in...@googlegroups.com
I'm not sure; I'm in Maya 2018 though. In 2015, you could check that the quaternionNodes (not positive of the name at the moment) is enabled--it might be disabled by default, just as matrixNodes used to be.

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOD4bjsQrWOYb8AT1u%3DATdGbniiuOVFYOJCbpPdZpLq9uw%40mail.gmail.com.

Joe Weidenbach

unread,
Mar 21, 2018, 5:21:53 AM3/21/18
to python_in...@googlegroups.com
Ok, it's also possible that that node was added later based on the repo you mentioned :)
Reply all
Reply to author
Forward
0 new messages