123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Quaternion.h>
- // The spherical linear interpolation (slerp) of unit-length quaternions
- // q0 and q1 for t in [0,1] and theta in (0,pi) is
- // slerp(t,q0,q1) = [sin((1-t)*theta)*q0 + sin(theta)*q1]/sin(theta)
- // where theta is the angle between q0 and q1 [cos(theta) = Dot(q0,q1)].
- // This function is a parameterization of the great spherical arc between
- // q0 and q1 on the unit hypersphere. Moreover, the parameterization is
- // one of normalized arclength--a particle traveling along the arc through
- // time t does so with constant speed.
- //
- // Read the comments in GteChebyshevRatio.h regarding estimates for the
- // ratio sin(t*theta)/sin(theta).
- //
- // When using slerp in animations involving sequences of quaternions, it is
- // typical that the quaternions are preprocessed so that consecutive ones
- // form an acute angle A in [0,pi/2]. Other preprocessing can help with
- // performance. See the function comments in the SLERP class.
- namespace WwiseGTE
- {
- template <typename Real>
- class SLERP
- {
- public:
- // The angle between q0 and q1 is in [0,pi). There are no angle
- // restrictions and nothing is precomputed.
- template <int N>
- inline static Quaternion<Real> Estimate(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1)
- {
- static_assert(1 <= N && N <= 16, "Invalid degree.");
- Real cs = Dot(q0, q1);
- Real sign;
- if (cs >= (Real)0)
- {
- sign = (Real)1;
- }
- else
- {
- cs = -cs;
- sign = (Real)-1;
- }
- Real f0, f1;
- ChebyshevRatio<Real>::template GetEstimate<N>(t, (Real)1 - cs, f0, f1);
- return q0 * f0 + q1 * (sign * f1);
- }
- // The angle between q0 and q1 must be in [0,pi/2]. The suffix R is
- // for 'Restricted'. The preprocessing code is
- // Quaternion<Real> q[n]; // assuming initialized
- // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
- // {
- // cosA = Dot(q[i0], q[i1]);
- // if (cosA < 0)
- // {
- // q[i1] = -q[i1]; // now Dot(q[i0], q[i]1) >= 0
- // }
- // }
- template <int N>
- inline static Quaternion<Real> EstimateR(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1)
- {
- static_assert(1 <= N && N <= 16, "Invalid degree.");
- Real f0, f1;
- ChebyshevRatio<Real>::template GetEstimate<N>(t, (Real)1 - Dot(q0, q1), f0, f1);
- return q0 * f0 + q1 * f1;
- }
- // The angle between q0 and q1 must be in [0,pi/2]. The suffix R is
- // for 'Restricted' and the suffix P is for 'Preprocessed'. The
- // preprocessing code is
- // Quaternion<Real> q[n]; // assuming initialized
- // Real cosA[n-1], omcosA[n-1]; // to be precomputed
- // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
- // {
- // cs = Dot(q[i0], q[i1]);
- // if (cosA[i0] < 0)
- // {
- // q[i1] = -q[i1];
- // cs = -cs;
- // }
- //
- // // for Quaterion<T>::SlerpRP
- // cosA[i0] = cs;
- //
- // // for SLERP<T>::EstimateRP
- // omcosA[i0] = 1 - cs;
- // }
- template <int N>
- inline static Quaternion<Real> EstimateRP(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1,
- Real omcosA)
- {
- static_assert(1 <= N && N <= 16, "Invalid degree.");
- Real f0, f1;
- ChebyshevRatio<Real>::template GetEstimate<N>(t, omcosA, f0, f1);
- return q0 * f0 + q1 * f1;
- }
- // The angle between q0 and q1 is A and must be in [0,pi/2].
- // Quaternion qh is slerp(1/2,q0,q1) = (q0+q1)/|q0+q1|, so the angle
- // between q0 and qh is A/2 and the angle between qh and q1 is A/2.
- // The preprocessing code is
- // Quaternion<Real> q[n]; // assuming initialized
- // Quaternion<Real> qh[n-1]; // to be precomputed
- // Real omcosAH[n-1]; // to be precomputed
- // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
- // {
- // cosA = Dot(q[i0], q[i1]);
- // if (cosA < 0)
- // {
- // q[i1] = -q[i1];
- // cosA = -cosA;
- // }
- // cosAH = sqrt((1 + cosA)/2);
- // qh[i0] = (q0 + q1) / (2 * cosAH[i0]);
- // omcosAH[i0] = 1 - cosAH;
- // }
- template <int N>
- inline static Quaternion<Real> EstimateRPH(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1,
- Quaternion<Real> const& qh, Real omcosAH)
- {
- static_assert(1 <= N && N <= 16, "Invalid degree.");
- Real f0, f1;
- Real twoT = t * (Real)2;
- if (twoT <= (Real)1)
- {
- ChebyshevRatio<Real>::template GetEstimate<N>(twoT, omcosAH, f0, f1);
- return q0 * f0 + qh * f1;
- }
- else
- {
- ChebyshevRatio<Real>::template GetEstimate<N>(twoT - (Real)1, omcosAH, f0, f1);
- return qh * f0 + q1 * f1;
- }
- }
- };
- }
|