Calculate quaternion animation curve's tangents from a euler animation curve

I am creating a custom animation editor that lets users modify the animation curves of various components. One component I am having trouble with is the rotation of an object. I allow the user to edit the rotation’s euler components (actually just the z rotation since the editor is for 2D). When generating the final animation, I convert the euler animation curve to a set of four quaternion curves.

The problem is that the tangents of the euler curve do not seem to correspond to the quaternion.

Here is the animation curve for the z component of a curve:

alt text

If I calculate my quaternion curve by adding the keys the following way, the animation jumps around erratically (this example is adding the middle keyframe):

float time = 1.7f;
float rotationZ = 90.0f;
float inTangent = -500.0f;
float outTangent = 500.0f

q = Quaternion.Euler(0, 0, rotationZ);

localRotationXKeyframes.Add(new Keyframe(time, q.x, inTangent, outTangent));
localRotationYKeyframes.Add(new Keyframe(time, q.y, inTangent, outTangent));
localRotationZKeyframes.Add(new Keyframe(time, q.z, inTangent, outTangent));
localRotationWKeyframes.Add(new Keyframe(time, q.w, inTangent, outTangent));

If I add the quaternion key without using the euler z curve’s tangents, the animation interpolates smoothly, but doesn’t follow the swings of the curve:

float time = 1.7f;
float rotationZ = 90.0f;

q = Quaternion.Euler(0, 0, rotationZ);

localRotationXKeyframes.Add(new Keyframe(time, q.x));
localRotationYKeyframes.Add(new Keyframe(time, q.y));
localRotationZKeyframes.Add(new Keyframe(time, q.z));
localRotationWKeyframes.Add(new Keyframe(time, q.w));

Obviously the tangents of the euler curve do not correspond with the tangents of the calculated quaternion curve.

My question is how do I create a quaternion animation curve based on the euler animation curve, with properly translated tangents?

The quaternion is a math representation of a single rotation of some angle around an arbitrary axis, where x, y and z are the normalized vector that defines the axis orientation multiplied by sin(angle/2) and w is cos(angle/2). Since sin(0) is zero, the axis orientation becomes critical for small angles, and the interpolation functions may produce incredibly wrong orientations at these points.

If you can use an alternative format, convert the quaternion to its angle/axis representation (see the functions Quaternion.AngleAxis and Quaternion.ToAngleAxis):

float angle = 0;
Vector3 axis = Vector3.zero;
// get the angle/axis equivalent of "rotation"
rotation.ToAngleAxis(out angle, out axis);
localRotationXKeyframes.Add(new Keyframe(time, axis.x));
localRotationYKeyframes.Add(new Keyframe(time, axis.y));
localRotationZKeyframes.Add(new Keyframe(time, axis.z));
localRotationWKeyframes.Add(new Keyframe(time, angle));

You will have to convert it back to quaternions using Quaternion.AngleAxis, of course.

In those cases where you rotate only around a fixed axis, you can store the angle alone and convert it back with Quaternion.Euler (or AngleAxis, if the axis isn’t x, y or z).

EDITED Paying a little more attention to your animation curve, I noticed that it strongly depends on the mid-point tangent. As a rule of thumb, you should add points for each curvature inflection - the top and bottom points, in this case:

alt text

This avoids problems with the tangents, since they are always zero at these points.

Anyone make success transfer euler curve to quaternion Curve?