diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index cb0232d05..f0c0f31c0 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -102,7 +102,8 @@ template inline Quaternion lerp(const Quaternion& normalizedA, co @param normalizedB Second quaternion @param t Interpolation phase (from range @f$ [0; 1] @f$) -Expects that both quaternions are normalized. @f[ +Expects that both quaternions are normalized. If the quaternions are the same +or one is a negation of the other, returns the first argument. @f[ q_{SLERP} = \frac{sin((1 - t) \theta) q_A + sin(t \theta) q_B}{sin \theta} ~ ~ ~ ~ ~ ~ ~ \theta = acos \left( \frac{q_A \cdot q_B}{|q_A| \cdot |q_B|} \right) = acos(q_A \cdot q_B) @@ -113,11 +114,10 @@ template inline Quaternion slerp(const Quaternion& normalizedA, c CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), "Math::slerp(): quaternions must be normalized", {}); 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{normalizedA}; - } + + /* Avoid division by zero */ + if(std::abs(cosHalfAngle) >= T(1)) return Quaternion{normalizedA}; + const T a = std::acos(cosHalfAngle); return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a); } diff --git a/src/Magnum/Math/Test/QuaternionTest.cpp b/src/Magnum/Math/Test/QuaternionTest.cpp index 33cf20b0b..5fcb6ad3b 100644 --- a/src/Magnum/Math/Test/QuaternionTest.cpp +++ b/src/Magnum/Math/Test/QuaternionTest.cpp @@ -439,8 +439,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()); + /* Avoid division by zero */ + CORRADE_COMPARE(Math::slerp(a, a, 0.25f), a); + CORRADE_COMPARE(Math::slerp(a, -a, 0.42f), a); } void QuaternionTest::transformVector() {