It seems that blender's Matrix decompose() function can exhibit some numerical "instability". What I mean is that orientation matrices that are relatively close can have significantly different elements in their quaternion matrix that makes interpolated keyframing unusable.
The following simple python script will calculate a sequence of matrices representing rotations around the Z axis in a smooth manner. It then decomposes the matrix into a quaternion, and inserts that as a keyframe. When you view the resulting fcurves in blender you can see that the Z value jumps from -1 to 1 about halfway through the animation.
import bpy
from math import *
from mathutils import *
def matrix_for_time(t):
theta = 2 * pi * t
mat = Matrix([[cos(theta), sin(theta), 0],
[-sin(theta), cos(theta), 0],
[0, 0, 1]]).to_4x4()
# for illustration we use rotation about Z axis,
# but in the arbitrary case, the orientation could be for a pine cone bouncing down a hill.
return mat
def mission(obj):
res = 36
qs = QuaternionStabilizer()
for z in range(res):
mat = matrix_for_time(z/res)
(loc,quat,scale) = mat.decompose()
obj.rotation_quaternion = qs.stabilize(quat)
for ai in range(len(quat)):
obj.keyframe_insert(frame=z*5, data_path="rotation_quaternion", index=ai)
mission(bpy.context.active_object)
" How to make a true linear quaternion rotation? " has some screenshots that imply quaternions aren't necessarily discontinuous.
Is there a technique for blender's python API to get a sequence of quaternions that can be keyframed and interpolated without discontinuity? For bonus points: link to an article that explains this mathematical oddity and why decomposition works this way.
This technique should be usable with arbitrary orientation matrices, because they are calculated from something a little more complex than this simple Z rotation (in my specific case I'm flying along a bezier curve).