From d156a60943c60373d53216d8f1a24a845568e39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 3 Sep 2018 14:52:39 +0200 Subject: [PATCH] Math: fix sclerp() behavior with dual quaternions having the same angle. The fix done with https://github.com/mosra/magnum/pull/122 (0e05c7289e21b21596161e8f3c30cc3da6f624ec) was not tested properly (see previous commit) and thus this code path never worked. This properly lerps the translation part and recombines it with the rotation instead of interpolating just a part of it. Also I'm no longer having any "dotResult" that's done only on the vector part of the rotation, but instead using the full rotation quaternion dot product. I have no idea why it was done this way. This branch was also never properly tested -- it'll be with the introduction of "shortest path" variants in the next commit. --- doc/changelog.dox | 2 ++ src/Magnum/Math/DualQuaternion.h | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 410c51cfe..e67f6c82f 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -307,6 +307,8 @@ See also: - @ref Platform::GlfwApplication::exec() now asserts instead of crashing if the constructor fails to create a window (see [mosra/magnum#192](https://github.com/mosra/magnum/issues/192), [mosra/magnum#272](https://github.com/mosra/magnum/pull/272)) +- @ref Math::sclerp() was not properly interpolating the translation if + rotation was the same on both sides @subsection changelog-latest-docs Documentation diff --git a/src/Magnum/Math/DualQuaternion.h b/src/Magnum/Math/DualQuaternion.h index 81c4a95ae..d8f45269b 100644 --- a/src/Magnum/Math/DualQuaternion.h +++ b/src/Magnum/Math/DualQuaternion.h @@ -66,15 +66,15 @@ Expects that both dual quaternions are normalized. @f[ template inline DualQuaternion sclerp(const DualQuaternion& normalizedA, const DualQuaternion& normalizedB, const T t) { CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), "Math::sclerp(): dual quaternions must be normalized", {}); - const T dotResult = dot(normalizedA.real().vector(), normalizedB.real().vector()); + const T cosHalfAngle = dot(normalizedA.real(), normalizedB.real()); - /* Avoid division by zero */ - const T cosHalfAngle = dotResult + normalizedA.real().scalar()*normalizedB.real().scalar(); + /* Avoid division by zero: interpolate just the translation part */ + /** @todo could this be optimized somehow? */ if(std::abs(cosHalfAngle) >= T(1)) - return {normalizedA.real(), {Implementation::lerp(normalizedA.dual().vector(), normalizedB.dual().vector(), t), T(0)}}; + return DualQuaternion::translation(Implementation::lerp(normalizedA.translation(), normalizedB.translation(), t))*DualQuaternion{normalizedA.real()}; /* l + εm = q_A^**q_B, multiplying with -1 ensures shortest path when dot < 0 */ - const DualQuaternion diff = normalizedA.quaternionConjugated()*(dotResult < T(0) ? -normalizedB : normalizedB); + const DualQuaternion diff = normalizedA.quaternionConjugated()*(cosHalfAngle < T(0) ? -normalizedB : normalizedB); const Quaternion& l = diff.real(); const Quaternion& m = diff.dual();