Browse Source

Math: fix sclerp() behavior with dual quaternions having the same angle.

The fix done with https://github.com/mosra/magnum/pull/122
(0e05c7289e) 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.
pull/267/head
Vladimír Vondruš 8 years ago
parent
commit
d156a60943
  1. 2
      doc/changelog.dox
  2. 10
      src/Magnum/Math/DualQuaternion.h

2
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

10
src/Magnum/Math/DualQuaternion.h

@ -66,15 +66,15 @@ Expects that both dual quaternions are normalized. @f[
template<class T> inline DualQuaternion<T> sclerp(const DualQuaternion<T>& normalizedA, const DualQuaternion<T>& 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<T>::translation(Implementation::lerp(normalizedA.translation(), normalizedB.translation(), t))*DualQuaternion<T>{normalizedA.real()};
/* l + εm = q_A^**q_B, multiplying with -1 ensures shortest path when dot < 0 */
const DualQuaternion<T> diff = normalizedA.quaternionConjugated()*(dotResult < T(0) ? -normalizedB : normalizedB);
const DualQuaternion<T> diff = normalizedA.quaternionConjugated()*(cosHalfAngle < T(0) ? -normalizedB : normalizedB);
const Quaternion<T>& l = diff.real();
const Quaternion<T>& m = diff.dual();

Loading…
Cancel
Save