# How to make a true linear quaternion rotation?

It turns out to be impossible to make a 360° rotation by using quaternion only with 2 keyframes. So I used three. However, the result appears unlinear, even though the curve interpolation type are all set to Linear. demo file

I wonder if this is something unavoidable. If not, is there any way to achieve a true linear quaternion rotation?

You would need to make a sinus/cosinus graph for that animation to have linear motion with quaternions:

For the 1st cube I set Euler rotation and animated a linear rotation, with Copy rotation constraint copied that to the second cube and then baked the animation on it with Object > Animation > Bake Action (visual keying on). This resulted in (the gif is little laggy):

This could be done easily with Sinusoidal easing type. Setting correct easingIn/easingOut for keyframes yields to this nice result:

• It seems this is quite suitable for the current project. Thanks a lot. – Leon Cheung Jan 25 '15 at 4:27
• Yes. We shared similar concept on the easing type. However, If the global and local coordinates are not aligned, it's still better to use baking method. Or some better idea? – Leon Cheung Jan 25 '15 at 13:35
• If the rotation is some random angle or combination of multiple linear rotations it's truly best to bake it. – Jaroslav Jerryno Novotny Jan 25 '15 at 18:23
• Yes. Btw, for the attached case, I think another way is to simply use one keyframe with two buil-in function modifier on both curves, which is a possible option, too. :) – Leon Cheung Jan 26 '15 at 0:19

I would use drivers for this. For a simple rotation around a static axis, it's quite straightforward, and the formulae can be entered directly in the driver window. No need for elaborate Python scripts.

A rotation quaternion is composed of four trigonometric values:
W = cos(a/2) for clockwise rotation or W = -cos(a/2) for counter-clockwise rotation
X = dirX*sin(a/2)
Y = dirY*sin(a/2)
Z = dirZ*sin(a/2)
where a is the rotation angle and dirX, dirY and dirZ are the X, Y and Z values of a vector that describes the direction of the axis of rotation. This vector should have a magnitude of 1, i.e. sqrt(dirX**2+dirY**2+dirZ**2) = 1

For linear rotation where 360° takes a known number of frames,
a/2 = (frame-1)*pi/(number of frames)
(Blender normally starts at frame 1, and the rotation at the first frame should be 0, hence the subtraction of 1 from the frame number).

In your example file the rotation is around the global Z axis, whose directional vector is (0, 0, 1), and 360° takes 40 frames. This yields the following driver functions. Use the Scripted expression driver type.

W = cos((frame-1)*pi/40)
X = 0
Y = 0
Z = sin((frame-1)*pi/40)

In this image, I'm actually rotating around the Y axis in front view, but the basic idea is the same.

There are several methods to calculate the values of dirX, dirY and dirZ. I will try to explain two of them.

## Method 1

You need to know the angles between the axis of rotation and the global X, Y and Z axes. Let's call these angles aX, aY and aZ. Then it's as simple as
dirX = cos(aX)
dirY = cos(aY)
dirZ = cos(aZ)
These are the direction cosines of the axis, and if the angles are composed correctly, the vector (dirX, dirY, dirZ) will have a magnitude of 1. If it doesn't, the angles define an axis that can't exist in 3D space.

## Method 2

Find the coordinates in the object's local space where the axis of rotation intersects the surface of the object. Let's call them x, y and z. The vector (x, y, z) will have a magnitude that may be 1, but quite possibly isn't. To normalize it, simply divide it by its own magnitude. Like this (dividing a vector by a scalar is the same as dividing its individual values by that scalar):
dirX = x/sqrt(x**2+y**2+z**2)
dirY = y/sqrt(x**2+y**2+z**2)
dirZ = z/sqrt(x**2+y**2+z**2)

A more in-depth explanation of the math behind all this, is most likely off topic here, but it probably would be right at home at math.SE.

I've found the following links quite useful:
Using Quaternion to Perform 3D rotations
Quaternions and spatial rotation

• Thank you very much for such comprehensive answer. I think it may help people quite a lot. :) – Leon Cheung Jan 25 '15 at 4:25
• @LeonCheung Math is my only true love, so this is an answer I enjoyed writing quite a lot. :) – user7952 Jan 25 '15 at 4:44
• I must confess, that although math is my true love, 3D geometry has never been my highest priority, and I'm just getting the hang of quaternions. I made an error in my original answer. The error was of little consequence; I said that the direction cosines needed to be normalised to a magnitude of 1. That isn't true, because they should already have a magnitude of 1, and normalising them would make no difference. Nevertheless, I've corrected the error. – user7952 Jan 28 '15 at 2:17

Inspired by answers from SixthOfFour and Jerryno, I optimized the curve with the relatively new Robert Penner Easing Equations feature, set type to Sinusoidal, which saves quite a lot keyframes.

example file