Here’s a little example. Suppose you slerp q0
and q1
with a value of t = 0.2
and a value of t = 0.4
. This gives you a quaternion s(0.2)
and a quaternion s(0.4)
. Quaternion multiplication also gives us the following:
s(0.2) = q0 * inverse(q0) * s(0.2)
'——————— K ————————'
So we have a value K
which, when right-multiplied with q0
, gives us s(0.2)
. Now intuitively we can guess that multiplying twice will give us s(0.4)
:
s(0.4) = q0 * inverse(q0) * s(0.2) * inverse(q0) * s(0.2)
'——————— K ————————' '——————— K ————————'
Simplifying:
s(0.4) = s(0.2) * inverse(q0) * s(0.2)
We can use this technique to slerp with values greater than 1
by just dividing by two. Which brings us to the following pseudocode:
quat slerp_generic(quat q0, quat q1, float t)
{
// If t is too large, divide it by two recursively
if (t > 1.0)
{
quat tmp = slerp_generic(q0, q1, t / 2);
return tmp * inverse(q0) * tmp;
}
// It’s easier to handle negative t this way
if (t < 0.0)
return slerp_generic(q1, q0, 1.0 - t);
return slerp(q0, q1, t);
}
Edit: the above code works great for slerp
; for lerp
however you’re going to get discontinuities in the derivative which you may not want. This code uses a similar technique and will work better for lerp
:
quat lerp_generic(quat q0, quat q1, float t)
{
// If t is too large, subtract 1.0 from it recursively
if (t > 1.0)
{
quat tmp = lerp_generic(q0, q1, t - 1.0);
return tmp * inverse(q0) * q1;
}
// It’s easier to handle negative t this way
if (t < 0.0)
return lerp_generic(q1, q0, 1.0 - t);
return lerp(q0, q1, t);
}