A sequence of 90-degree rotations with Python

I am trying to do what I thought would be a simple task but turned out to be a very frustrating endeavor.

I need to program an object to undergo a long series of random 90-degree rotations around the origin of the object, which coincides with the World's origin. I am using Python to set the angles and create keyframes. Let's say I need a 90-degree rotation around the global X, then 90-degree around Y and then -90 around X again. The following code does not work properly:

obj = bpy.data.objects["Sphere"]
obj.animation_data_clear()

obj.rotation_euler = [0, 0, 0]
obj.keyframe_insert(data_path="rotation_euler", frame=1, index=0)
obj.keyframe_insert(data_path="rotation_euler", frame=1, index=1)
obj.keyframe_insert(data_path="rotation_euler", frame=1, index=2)

# rotate 90 around x
obj.rotation_euler.x += pi / 2

obj.keyframe_insert(data_path="rotation_euler", frame=20, index=0)
obj.keyframe_insert(data_path="rotation_euler", frame=20, index=1)
obj.keyframe_insert(data_path="rotation_euler", frame=20, index=2)

# rotate 90 around y

obj.rotation_euler.y += pi / 2

obj.keyframe_insert(data_path="rotation_euler", frame=40, index=0)
obj.keyframe_insert(data_path="rotation_euler", frame=40, index=1)
obj.keyframe_insert(data_path="rotation_euler", frame=40, index=2)

# rotate -90 around x
obj.rotation_euler.x -= pi / 2

obj.keyframe_insert(data_path="rotation_euler", frame=60, index=0)
obj.keyframe_insert(data_path="rotation_euler", frame=60, index=1)
obj.keyframe_insert(data_path="rotation_euler", frame=60, index=2)


Depending on the rotation mode (XYZ, ZYX, etc.) the results are different and never what I want them to be. For example, under XYZ, the first two rotations are correct, but the 3rd rotation ends up being around the Z-axis instead of Y.

So how do I make those rotations consistent, and without wobbling? Someone please point me in the righ direction. Thanks!

• That's probably because you assume that subsequent rotation changes are performed in world space, but the actually happen in local space. The first two rotations "change" the axes, so that the third is done around another than the initial Y axis. You should set Object.matrix_world directly or apply rotations on it for rotations in global space (may require some matrix math). I remember a post at BA.org about this, but couldn't find it so far. – CodeManX Aug 29 '15 at 15:58
• Using Quaternions solved the problem. – O.T.Vinta Sep 2 '15 at 13:43

To do this with matrix multiplication & globally. As for the "wobbling" do you mean the interpolation?

import bpy
from mathutils import Matrix

obj = bpy.data.objects["Sphere"]
obj.animation_data_clear()

obj.rotation_euler = [0, 0, 0]
bpy.context.scene.frame_set(1)
obj.keyframe_insert(data_path="rotation_euler", frame=1)

obj.matrix_world *= mat_rot_x
obj.rotation_euler = obj.matrix_world.to_euler()
obj.keyframe_insert(data_path="rotation_euler", frame=20)

obj.matrix_world *= mat_rot_y
obj.keyframe_insert(data_path="rotation_euler", frame=40)

obj.matrix_world *= mat_rot_mx
obj.rotation_euler = obj.matrix_world.to_euler()
obj.keyframe_insert(data_path="rotation_euler", frame=60)

• If you tried your code you would see the exact same behavior as in the original poster's code. The solution to the above problem is not to use Euler rotation but Quaternions. – O.T.Vinta Sep 2 '15 at 13:42
• Have a look at this script: blenderartists.org/forum/… it rotates the object in 45° steps, without eulers and quaternions. – CodeManX Sep 2 '15 at 13:50
• Code from OP leaves the Sphere in (0, 90, 0) whereas revised code above leaves it in (0, 0, 90). Fixed M.Rotate(90) not equivalent of - M.Rotate(-90) – batFINGER Sep 2 '15 at 16:33