Browse Source

Math: Fix slerp interpolation of equal quaternions and add test.

If and only if the quaternions to interpolate are equal, the angle between
them is 0.0 and we therefore cannot safely divide by the sin of that angle.
Credits to @wivlaro for finding this one.

Fixes #117.

Signed-off-by: Squareys <Squareys@googlemail.com>
pull/120/head
Squareys 11 years ago committed by Vladimír Vondruš
parent
commit
998f63bcb2
  1. 8
      src/Magnum/Math/Quaternion.h
  2. 3
      src/Magnum/Math/Test/QuaternionTest.cpp

8
src/Magnum/Math/Quaternion.h

@ -112,7 +112,13 @@ Expects that both quaternions are normalized. @f[
template<class T> inline Quaternion<T> slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::slerp(): quaternions must be normalized", {});
const T a = Implementation::angle(normalizedA, normalizedB);
const T cosHalfAngle = dot(normalizedA, normalizedB);
if(std::abs(cosHalfAngle) >= T(1)) {
/* The angle `a` between the quaternions `A` and `B` is 0 and we cannot
divide by sin(a). This is the case for `A == B` or `A == -B`. */
return Quaternion<T>{normalizedA};
}
const T a = std::acos(cosHalfAngle);
return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a);
}

3
src/Magnum/Math/Test/QuaternionTest.cpp

@ -438,6 +438,9 @@ void QuaternionTest::slerp() {
Quaternion slerp = Math::slerp(a, b, 0.35f);
CORRADE_COMPARE(slerp, Quaternion({0.1191653f, 0.0491109f, 0.0491109f}, 0.9904423f));
CORRADE_COMPARE(Math::slerp(Quaternion(), Quaternion(), 0.25f), Quaternion());
CORRADE_COMPARE(Math::slerp(Quaternion(), -Quaternion(), 0.42f), Quaternion());
}
void QuaternionTest::transformVector() {

Loading…
Cancel
Save