| 1 | // Copyright 2009-2021 Intel Corporation |
| 2 | // SPDX-License-Identifier: Apache-2.0 |
| 3 | |
| 4 | #pragma once |
| 5 | |
| 6 | #include "vec3.h" |
| 7 | #include "vec4.h" |
| 8 | |
| 9 | #include "transcendental.h" |
| 10 | |
| 11 | namespace embree |
| 12 | { |
| 13 | //////////////////////////////////////////////////////////////// |
| 14 | // Quaternion Struct |
| 15 | //////////////////////////////////////////////////////////////// |
| 16 | |
| 17 | template<typename T> |
| 18 | struct QuaternionT |
| 19 | { |
| 20 | typedef Vec3<T> Vector; |
| 21 | |
| 22 | //////////////////////////////////////////////////////////////////////////////// |
| 23 | /// Construction |
| 24 | //////////////////////////////////////////////////////////////////////////////// |
| 25 | |
| 26 | __forceinline QuaternionT () { } |
| 27 | __forceinline QuaternionT ( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; } |
| 28 | __forceinline QuaternionT& operator=( const QuaternionT& other ) { r = other.r; i = other.i; j = other.j; k = other.k; return *this; } |
| 29 | |
| 30 | __forceinline QuaternionT( const T& r ) : r(r), i(zero), j(zero), k(zero) {} |
| 31 | __forceinline explicit QuaternionT( const Vec3<T>& v ) : r(zero), i(v.x), j(v.y), k(v.z) {} |
| 32 | __forceinline explicit QuaternionT( const Vec4<T>& v ) : r(v.x), i(v.y), j(v.z), k(v.w) {} |
| 33 | __forceinline QuaternionT( const T& r, const T& i, const T& j, const T& k ) : r(r), i(i), j(j), k(k) {} |
| 34 | __forceinline QuaternionT( const T& r, const Vec3<T>& v ) : r(r), i(v.x), j(v.y), k(v.z) {} |
| 35 | |
| 36 | __inline QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz ); |
| 37 | __inline QuaternionT( const T& yaw, const T& pitch, const T& roll ); |
| 38 | |
| 39 | //////////////////////////////////////////////////////////////////////////////// |
| 40 | /// Constants |
| 41 | //////////////////////////////////////////////////////////////////////////////// |
| 42 | |
| 43 | __forceinline QuaternionT( ZeroTy ) : r(zero), i(zero), j(zero), k(zero) {} |
| 44 | __forceinline QuaternionT( OneTy ) : r( one), i(zero), j(zero), k(zero) {} |
| 45 | |
| 46 | /*! return quaternion for rotation around arbitrary axis */ |
| 47 | static __forceinline QuaternionT rotate(const Vec3<T>& u, const T& r) { |
| 48 | return QuaternionT<T>(cos(T(0.5)*r),sin(T(0.5)*r)*normalize(u)); |
| 49 | } |
| 50 | |
| 51 | /*! returns the rotation axis of the quaternion as a vector */ |
| 52 | __forceinline Vec3<T> v( ) const { return Vec3<T>(i, j, k); } |
| 53 | |
| 54 | public: |
| 55 | T r, i, j, k; |
| 56 | }; |
| 57 | |
| 58 | template<typename T> __forceinline QuaternionT<T> operator *( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a * b.r, a * b.i, a * b.j, a * b.k); } |
| 59 | template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r * b, a.i * b, a.j * b, a.k * b); } |
| 60 | |
| 61 | //////////////////////////////////////////////////////////////// |
| 62 | // Unary Operators |
| 63 | //////////////////////////////////////////////////////////////// |
| 64 | |
| 65 | template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a ) { return QuaternionT<T>(+a.r, +a.i, +a.j, +a.k); } |
| 66 | template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a ) { return QuaternionT<T>(-a.r, -a.i, -a.j, -a.k); } |
| 67 | template<typename T> __forceinline QuaternionT<T> conj ( const QuaternionT<T>& a ) { return QuaternionT<T>(a.r, -a.i, -a.j, -a.k); } |
| 68 | template<typename T> __forceinline T abs ( const QuaternionT<T>& a ) { return sqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } |
| 69 | template<typename T> __forceinline QuaternionT<T> rcp ( const QuaternionT<T>& a ) { return conj(a)*rcp(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } |
| 70 | template<typename T> __forceinline QuaternionT<T> normalize ( const QuaternionT<T>& a ) { return a*rsqrt(a.r*a.r + a.i*a.i + a.j*a.j + a.k*a.k); } |
| 71 | |
| 72 | // evaluates a*q-r |
| 73 | template<typename T> __forceinline QuaternionT<T> |
| 74 | msub(const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p) |
| 75 | { |
| 76 | return QuaternionT<T>(msub(a, q.r, p.r), |
| 77 | msub(a, q.i, p.i), |
| 78 | msub(a, q.j, p.j), |
| 79 | msub(a, q.k, p.k)); |
| 80 | } |
| 81 | // evaluates a*q-r |
| 82 | template<typename T> __forceinline QuaternionT<T> |
| 83 | madd (const T& a, const QuaternionT<T>& q, const QuaternionT<T>& p) |
| 84 | { |
| 85 | return QuaternionT<T>(madd(a, q.r, p.r), |
| 86 | madd(a, q.i, p.i), |
| 87 | madd(a, q.j, p.j), |
| 88 | madd(a, q.k, p.k)); |
| 89 | } |
| 90 | |
| 91 | //////////////////////////////////////////////////////////////// |
| 92 | // Binary Operators |
| 93 | //////////////////////////////////////////////////////////////// |
| 94 | |
| 95 | template<typename T> __forceinline QuaternionT<T> operator +( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a + b.r, b.i, b.j, b.k); } |
| 96 | template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r + b, a.i, a.j, a.k); } |
| 97 | template<typename T> __forceinline QuaternionT<T> operator +( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r + b.r, a.i + b.i, a.j + b.j, a.k + b.k); } |
| 98 | template<typename T> __forceinline QuaternionT<T> operator -( const T & a, const QuaternionT<T>& b ) { return QuaternionT<T>(a - b.r, -b.i, -b.j, -b.k); } |
| 99 | template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const T & b ) { return QuaternionT<T>(a.r - b, a.i, a.j, a.k); } |
| 100 | template<typename T> __forceinline QuaternionT<T> operator -( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return QuaternionT<T>(a.r - b.r, a.i - b.i, a.j - b.j, a.k - b.k); } |
| 101 | |
| 102 | template<typename T> __forceinline Vec3<T> operator *( const QuaternionT<T>& a, const Vec3<T> & b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); } |
| 103 | template<typename T> __forceinline QuaternionT<T> operator *( const QuaternionT<T>& a, const QuaternionT<T>& b ) { |
| 104 | return QuaternionT<T>(a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k, |
| 105 | a.r*b.i + a.i*b.r + a.j*b.k - a.k*b.j, |
| 106 | a.r*b.j - a.i*b.k + a.j*b.r + a.k*b.i, |
| 107 | a.r*b.k + a.i*b.j - a.j*b.i + a.k*b.r); |
| 108 | } |
| 109 | template<typename T> __forceinline QuaternionT<T> operator /( const T & a, const QuaternionT<T>& b ) { return a*rcp(b); } |
| 110 | template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const T & b ) { return a*rcp(b); } |
| 111 | template<typename T> __forceinline QuaternionT<T> operator /( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a*rcp(b); } |
| 112 | |
| 113 | template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const T & b ) { return a = a+b; } |
| 114 | template<typename T> __forceinline QuaternionT<T>& operator +=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a+b; } |
| 115 | template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const T & b ) { return a = a-b; } |
| 116 | template<typename T> __forceinline QuaternionT<T>& operator -=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a-b; } |
| 117 | template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const T & b ) { return a = a*b; } |
| 118 | template<typename T> __forceinline QuaternionT<T>& operator *=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*b; } |
| 119 | template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const T & b ) { return a = a*rcp(b); } |
| 120 | template<typename T> __forceinline QuaternionT<T>& operator /=( QuaternionT<T>& a, const QuaternionT<T>& b ) { return a = a*rcp(b); } |
| 121 | |
| 122 | template<typename T, typename M> __forceinline QuaternionT<T> |
| 123 | select(const M& m, const QuaternionT<T>& q, const QuaternionT<T>& p) |
| 124 | { |
| 125 | return QuaternionT<T>(select(m, q.r, p.r), |
| 126 | select(m, q.i, p.i), |
| 127 | select(m, q.j, p.j), |
| 128 | select(m, q.k, p.k)); |
| 129 | } |
| 130 | |
| 131 | |
| 132 | template<typename T> __forceinline Vec3<T> xfmPoint ( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); } |
| 133 | template<typename T> __forceinline Vec3<T> xfmVector( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); } |
| 134 | template<typename T> __forceinline Vec3<T> xfmNormal( const QuaternionT<T>& a, const Vec3<T>& b ) { return (a*QuaternionT<T>(b)*conj(a)).v(); } |
| 135 | |
| 136 | template<typename T> __forceinline T dot(const QuaternionT<T>& a, const QuaternionT<T>& b) { return a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k; } |
| 137 | |
| 138 | //////////////////////////////////////////////////////////////////////////////// |
| 139 | /// Comparison Operators |
| 140 | //////////////////////////////////////////////////////////////////////////////// |
| 141 | |
| 142 | template<typename T> __forceinline bool operator ==( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r == b.r && a.i == b.i && a.j == b.j && a.k == b.k; } |
| 143 | template<typename T> __forceinline bool operator !=( const QuaternionT<T>& a, const QuaternionT<T>& b ) { return a.r != b.r || a.i != b.i || a.j != b.j || a.k != b.k; } |
| 144 | |
| 145 | |
| 146 | //////////////////////////////////////////////////////////////////////////////// |
| 147 | /// Orientation Functions |
| 148 | //////////////////////////////////////////////////////////////////////////////// |
| 149 | |
| 150 | template<typename T> QuaternionT<T>::QuaternionT( const Vec3<T>& vx, const Vec3<T>& vy, const Vec3<T>& vz ) |
| 151 | { |
| 152 | if ( vx.x + vy.y + vz.z >= T(zero) ) |
| 153 | { |
| 154 | const T t = T(one) + (vx.x + vy.y + vz.z); |
| 155 | const T s = rsqrt(t)*T(0.5f); |
| 156 | r = t*s; |
| 157 | i = (vy.z - vz.y)*s; |
| 158 | j = (vz.x - vx.z)*s; |
| 159 | k = (vx.y - vy.x)*s; |
| 160 | } |
| 161 | else if ( vx.x >= max(vy.y, vz.z) ) |
| 162 | { |
| 163 | const T t = (T(one) + vx.x) - (vy.y + vz.z); |
| 164 | const T s = rsqrt(t)*T(0.5f); |
| 165 | r = (vy.z - vz.y)*s; |
| 166 | i = t*s; |
| 167 | j = (vx.y + vy.x)*s; |
| 168 | k = (vz.x + vx.z)*s; |
| 169 | } |
| 170 | else if ( vy.y >= vz.z ) // if ( vy.y >= max(vz.z, vx.x) ) |
| 171 | { |
| 172 | const T t = (T(one) + vy.y) - (vz.z + vx.x); |
| 173 | const T s = rsqrt(t)*T(0.5f); |
| 174 | r = (vz.x - vx.z)*s; |
| 175 | i = (vx.y + vy.x)*s; |
| 176 | j = t*s; |
| 177 | k = (vy.z + vz.y)*s; |
| 178 | } |
| 179 | else //if ( vz.z >= max(vy.y, vx.x) ) |
| 180 | { |
| 181 | const T t = (T(one) + vz.z) - (vx.x + vy.y); |
| 182 | const T s = rsqrt(t)*T(0.5f); |
| 183 | r = (vx.y - vy.x)*s; |
| 184 | i = (vz.x + vx.z)*s; |
| 185 | j = (vy.z + vz.y)*s; |
| 186 | k = t*s; |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | template<typename T> QuaternionT<T>::QuaternionT( const T& yaw, const T& pitch, const T& roll ) |
| 191 | { |
| 192 | const T cya = cos(yaw *T(0.5f)); |
| 193 | const T cpi = cos(pitch*T(0.5f)); |
| 194 | const T cro = cos(roll *T(0.5f)); |
| 195 | const T sya = sin(yaw *T(0.5f)); |
| 196 | const T spi = sin(pitch*T(0.5f)); |
| 197 | const T sro = sin(roll *T(0.5f)); |
| 198 | r = cro*cya*cpi + sro*sya*spi; |
| 199 | i = cro*cya*spi + sro*sya*cpi; |
| 200 | j = cro*sya*cpi - sro*cya*spi; |
| 201 | k = sro*cya*cpi - cro*sya*spi; |
| 202 | } |
| 203 | |
| 204 | ////////////////////////////////////////////////////////////////////////////// |
| 205 | /// Output Operators |
| 206 | ////////////////////////////////////////////////////////////////////////////// |
| 207 | |
| 208 | template<typename T> static embree_ostream operator<<(embree_ostream cout, const QuaternionT<T>& q) { |
| 209 | return cout << "{ r = " << q.r << ", i = " << q.i << ", j = " << q.j << ", k = " << q.k << " }" ; |
| 210 | } |
| 211 | |
| 212 | /*! default template instantiations */ |
| 213 | typedef QuaternionT<float> Quaternion3f; |
| 214 | typedef QuaternionT<double> Quaternion3d; |
| 215 | |
| 216 | template<int N> using Quaternion3vf = QuaternionT<vfloat<N>>; |
| 217 | typedef QuaternionT<vfloat<4>> Quaternion3vf4; |
| 218 | typedef QuaternionT<vfloat<8>> Quaternion3vf8; |
| 219 | typedef QuaternionT<vfloat<16>> Quaternion3vf16; |
| 220 | |
| 221 | ////////////////////////////////////////////////////////////////////////////// |
| 222 | /// Interpolation |
| 223 | ////////////////////////////////////////////////////////////////////////////// |
| 224 | template<typename T> |
| 225 | __forceinline QuaternionT<T>lerp(const QuaternionT<T>& q0, |
| 226 | const QuaternionT<T>& q1, |
| 227 | const T& factor) |
| 228 | { |
| 229 | QuaternionT<T> q; |
| 230 | q.r = lerp(q0.r, q1.r, factor); |
| 231 | q.i = lerp(q0.i, q1.i, factor); |
| 232 | q.j = lerp(q0.j, q1.j, factor); |
| 233 | q.k = lerp(q0.k, q1.k, factor); |
| 234 | return q; |
| 235 | } |
| 236 | |
| 237 | template<typename T> |
| 238 | __forceinline QuaternionT<T> slerp(const QuaternionT<T>& q0, |
| 239 | const QuaternionT<T>& q1_, |
| 240 | const T& t) |
| 241 | { |
| 242 | T cosTheta = dot(q0, q1_); |
| 243 | QuaternionT<T> q1 = select(cosTheta < 0.f, -q1_, q1_); |
| 244 | cosTheta = select(cosTheta < 0.f, -cosTheta, cosTheta); |
| 245 | |
| 246 | // spherical linear interpolation |
| 247 | const T phi = t * fastapprox::acos(cosTheta); |
| 248 | T sinPhi, cosPhi; |
| 249 | fastapprox::sincos(phi, sinPhi, cosPhi); |
| 250 | QuaternionT<T> qperp = sinPhi * normalize(msub(cosTheta, q0, q1)); |
| 251 | QuaternionT<T> qslerp = msub(cosPhi, q0, qperp); |
| 252 | |
| 253 | // regular linear interpolation as fallback |
| 254 | QuaternionT<T> qlerp = normalize(lerp(q0, q1, t)); |
| 255 | |
| 256 | return select(cosTheta > 0.9995f, qlerp, qslerp); |
| 257 | } |
| 258 | } |
| 259 | |