From 912d1b1e81a7ecd632b0a4e8f92b0c1eeac692b5 Mon Sep 17 00:00:00 2001 From: Christophe Riccio Date: Fri, 21 Dec 2012 23:05:10 +0100 Subject: [PATCH] Added slerp, lerp and mix functions for quaternions. Added, fixed and clarified documentation. --- glm/gtc/matrix_transform.hpp | 2 +- glm/gtc/quaternion.hpp | 37 +++++++++++++++++++++++++++++++-- glm/gtc/quaternion.inl | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/glm/gtc/matrix_transform.hpp b/glm/gtc/matrix_transform.hpp index f39e9c0f..128209af 100644 --- a/glm/gtc/matrix_transform.hpp +++ b/glm/gtc/matrix_transform.hpp @@ -88,7 +88,7 @@ namespace glm /// @param m Input matrix multiplied by this rotation matrix. /// @param angle Rotation angle expressed in radians if GLM_FORCE_RADIANS is define or degrees otherwise. /// @param axis Rotation axis, recommanded to be normalized. - /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double. + /// @tparam T Value type used to build the matrix. Supported: half, float or double. /// @see gtc_matrix_transform /// @see gtx_transform /// @see - rotate(T angle, T x, T y, T z) diff --git a/glm/gtc/quaternion.hpp b/glm/gtc/quaternion.hpp index 5d900739..5d880321 100644 --- a/glm/gtc/quaternion.hpp +++ b/glm/gtc/quaternion.hpp @@ -171,15 +171,48 @@ namespace detail detail::tquat const & q1, detail::tquat const & q2); - /// Returns a SLERP interpolated quaternion of x and y according a. + /// Spherical linear interpolation of two quaternions. + /// The interpolation is oriented and the rotation is performed at constant speed. /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// @tparam T Value type used to build the quaternion. Supported: half, float or double. /// @see gtc_quaternion template detail::tquat mix( detail::tquat const & x, detail::tquat const & y, T const & a); - + + /// Linear interpolation of two quaternions. + /// The interpolation is oriented. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// @tparam T Value type used to build the quaternion. Supported: half, float or double. + /// @see gtc_quaternion + template + detail::tquat lerp( + detail::tquat const & x, + detail::tquat const & y, + T const & a); + + /// Spherical linear interpolation of two quaternions. + /// The interpolation always take the short path and the rotation is performed at constant speed. + /// + /// @param x A quaternion + /// @param y A quaternion + /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1]. + /// @tparam T Value type used to build the quaternion. Supported: half, float or double. + /// @see gtc_quaternion + template + detail::tquat slerp( + detail::tquat const & x, + detail::tquat const & y, + T const & a); + /// Returns the q conjugate. /// /// @see gtc_quaternion diff --git a/glm/gtc/quaternion.inl b/glm/gtc/quaternion.inl index 538fbb07..36385aae 100644 --- a/glm/gtc/quaternion.inl +++ b/glm/gtc/quaternion.inl @@ -443,6 +443,7 @@ namespace detail return normalize(beta * x + alpha * y); } */ + template GLM_FUNC_QUALIFIER detail::tquat mix ( @@ -450,6 +451,45 @@ namespace detail detail::tquat const & y, T const & a ) + { + T cosTheta = dot(x, y); + + // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator + if(cosTheta > T(1) - epsilon()) + { + // Linear interpolation + return detail::tquat( + mix(x.w, y.w, a), + mix(x.x, y.x, a), + mix(x.y, y.y, a), + mix(x.z, y.z, a)); + } + else + { + // Essential Mathematics, page 467 + T angle = acos(cosTheta); + return (sin((T(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); + } + } + + template + GLM_FUNC_QUALIFIER detail::tquat lerp + ( + detail::tquat const & x, + detail::tquat const & y, + T const & a + ) + { + return x * (T(1) - a) + (y * a); + } + + template + GLM_FUNC_QUALIFIER detail::tquat slerp + ( + detail::tquat const & x, + detail::tquat const & y, + T const & a + ) { detail::tquat z = y;