I'm reading pbrt and trying to better understanding the return value of Dot(). The Dot() function takes two quaternions and returns their inner product. Also note, internally, when it comes to the inner product, a quaternion is treated as a 4D vector. I know when two vectors, or in this case the two quaternions, are parallel, then their inner product is equal to 1.0.
Things get little confusing for me when I read the implementation of Slerp()
Quaternion Slerp(float t, const Quaternion &q1,
const Quaternion &q2) {
float cosTheta = Dot(q1, q2);
if (cosTheta > .9995){
return Normalize((1.f - t) * q1 + t * q2);
} else {
// ...
}
}
I don't quite understand the if(cosTheta > .9995)
part. If two quaternions are parallel, then their inner product is 1.0, correct? The only reason I can think of for having a greater-than
operator is because Slerp() is meant to work with quaternions and unit quaternions. Is that right?
My ultimate goal is to replace if(cosTheta > .9995)
with something more accurate, such as:
if( approxEqual(cosTheta, 1.0) or cosTheta > 1.0 ){ ... }
approxEqual
computes whether the two arguments are approximately equal based on their relative difference.
Would my new if
statement be mathematically correct?
In the book Slerp()
is described as:
$$ slerp(q1,q2,t) = \frac{ q1 \sin((1-t) \theta) + q2 \sin(t\theta) }{ \sin \theta } $$
...given the quaternions to interpolate between, $q1$ and $q2$, denote by \theta the angle between them. Then, given a parameter value t ∈[0,1], we'd like to find the intermediate quaternion $q'$ that makes angle $\theta' = \theta t$ between it and $q1$, along the path from $q1$ to $q2$. --page 95
The implementation of the
Slerp()
function checks to see if the two quaternions are nearly parallel, in which case it uses regular linear interpolation of quaternion components in order to avoid numerical instability. Otherwise, ...
if
statement would work too? As far as I can tell mine is better than using the magic number0.9995
. $\endgroup$