summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Harmer <sean.harmer@kdab.com>2019-03-11 16:46:17 +0000
committerSean Harmer <sean.harmer@kdab.com>2019-03-11 17:07:32 +0000
commit31aa763b0d1f4ec2439c6dc33b4a63b88c16369e (patch)
tree3e2203296a1937366fac5561b3ad9f9d49e22067
parent4af8fcdc05d0198a569e7c39fa934614bbe31803 (diff)
Make slerping safer
Now handles case where the two bounding keyframe quaternions are equal by returning the first as the interpolated value. Change-Id: I43d0dfb1e20afafd690817d30aeac2d510847422 Reviewed-by: Mike Krus <mike.krus@kdab.com>
-rw-r--r--src/animation/backend/animationutils.cpp19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/animation/backend/animationutils.cpp b/src/animation/backend/animationutils.cpp
index 0496ff681..c876fcb87 100644
--- a/src/animation/backend/animationutils.cpp
+++ b/src/animation/backend/animationutils.cpp
@@ -277,13 +277,12 @@ ClipResults evaluateClipAtLocalTime(AnimationClip *clip, float localTime)
channelResults[i++] = channelComponent.fcurve.evaluateAtTime(localTime, lowerKeyframeBound);
}
} else {
- // There's only one keyframe. We cant compute omega. Interoplate per component
+ // There's only one keyframe. We cant compute omega. Interpolate per component
const int lowerKeyframeBound = channel.channelComponents[0].fcurve.lowerKeyframeBound(localTime);
if (lowerKeyframeBound + 1 >= channel.channelComponents[0].fcurve.keyframeCount()) {
for (const auto &channelComponent : qAsConst(channel.channelComponents))
channelResults[i++] = channelComponent.fcurve.evaluateAtTime(localTime, lowerKeyframeBound);
} else {
-
auto quaternionFromChannel = [channel](const int keyframe) {
const float w = channel.channelComponents[0].fcurve.keyframe(keyframe).value;
const float x = channel.channelComponents[1].fcurve.keyframe(keyframe).value;
@@ -296,10 +295,18 @@ ClipResults evaluateClipAtLocalTime(AnimationClip *clip, float localTime)
const auto lowerQuat = quaternionFromChannel(lowerKeyframeBound);
const auto higherQuat = quaternionFromChannel(lowerKeyframeBound + 1);
-
- const float omega = std::acos(QQuaternion::dotProduct(lowerQuat, higherQuat));
- for (const auto &channelComponent : qAsConst(channel.channelComponents))
- channelResults[i++] = channelComponent.fcurve.evaluateAtTimeAsSlerp(localTime, lowerKeyframeBound, omega);
+ const float omega = std::acos(qBound(-1.0f, QQuaternion::dotProduct(lowerQuat, higherQuat), 1.0f));
+
+ if (qFuzzyIsNull(omega)) {
+ // If the two keyframe quaternions are equal, just return the first one as the interpolated value.
+ channelResults[0] = lowerQuat.scalar();
+ channelResults[1] = lowerQuat.x();
+ channelResults[2] = lowerQuat.y();
+ channelResults[3] = lowerQuat.z();
+ } else {
+ for (const auto &channelComponent : qAsConst(channel.channelComponents))
+ channelResults[i++] = channelComponent.fcurve.evaluateAtTimeAsSlerp(localTime, lowerKeyframeBound, omega);
+ }
}
}
} else {