Graphics Reference
In-Depth Information
To produce a smoother animation without artefacts introduced from the linear interpolation of
rotation matrices, we have decomposed our transformation matrices for the two key-frames
into its translation, rotation, and scale components. The translation is stored within
Vector3
,
the uniform scale within a
float
variable, and finally the rotation component is now stored
within a quaternion.
prevFrame.Transform.DecomposeUniformScale(out s1, out q1, out t1);
frame.Transform.DecomposeUniformScale(out s2, out q2, out t2);
A quaternion is an alternative mathematical entity used to represent rotations. The use of
quaternion has advantages over rotation matrices in numerous situations because they
require less storage, fewer arithmetic operations for concatenation, and quaternions are more
easily interpolated (which is most important for this recipe). Spherical linear interpolation is
used here as the method for interpolating the quaternions because regular linear interpolation
does not trace out the arc between
q1
and
q2
at a constant rate (
Lengyel
,
2012
,
pp. 80-87
).
Using linear interpolation between two matrices with the
SharpDX.Matrix.Lerp
method
would not necessarily result in a correct rotation matrix. It may work fine if the key-frames
are close together and there are no large movements; however, it would be necessary to use
either normalized linear interpolation or spherical linear interpolation to get correct results.
Both of these operations are more efficient when using quaternions.
We linearly interpolate (lerp) between the two scale floats (
s1
and
s2
) and the two
translation vectors (
t1
and
t2
). Then we perform spherical linear interpolation (Slerp)
between the two quaternions (
q1
and
q2
). The matrix is then reconstructed from the
interpolated scale, rotation, and translation.
// Perform interpolation and reconstruct matrix
skinMatrices.Bones[frame.BoneIndex] =
Matrix.Scaling(MathUtil.Lerp(s1, s2, amount)) *
Matrix.RotationQuaternion(
Quaternion.Slerp(q1, q2, amount)
) *
Matrix.Translation(Vector3.Lerp(t1, t2, amount));
To ensure that we end up with the correct result, multiply the matrices in the following order:
first apply scale, then rotate, and finally translate.
To exaggerate the effect of the frame smoothing, try slowing down the
animation. For example, to get
1sec
of the animation equal to
10secs
,
use the following code:
// Calculate elapsed seconds as 1sec = 10sec
var time = clock.ElapsedMilliseconds / 10000.0f;