Quat.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Math/Common.h>
  7. #include <AnKi/Math/Vec.h>
  8. namespace anki {
  9. /// @addtogroup math
  10. /// @{
  11. /// Quaternion. Used in rotations
  12. template<typename T>
  13. class alignas(16) TQuat
  14. {
  15. public:
  16. static constexpr Bool kSimdEnabled = std::is_same<T, F32>::value && ANKI_ENABLE_SIMD;
  17. static constexpr Bool kSseEnabled = kSimdEnabled && ANKI_SIMD_SSE;
  18. // Data //
  19. // Skip some warnings cause we really nead anonymous structs inside unions
  20. #if ANKI_COMPILER_MSVC
  21. # pragma warning(push)
  22. # pragma warning(disable : 4201)
  23. #elif ANKI_COMPILER_GCC_COMPATIBLE
  24. # pragma GCC diagnostic push
  25. # pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
  26. # pragma GCC diagnostic ignored "-Wnested-anon-types"
  27. #endif
  28. union
  29. {
  30. struct
  31. {
  32. T x;
  33. T y;
  34. T z;
  35. T w;
  36. };
  37. TVec<T, 4> m_vec;
  38. };
  39. #if ANKI_COMPILER_MSVC
  40. # pragma warning(pop)
  41. #elif ANKI_COMPILER_GCC_COMPATIBLE
  42. # pragma GCC diagnostic pop
  43. #endif
  44. // Constructors //
  45. TQuat()
  46. : m_vec(T(0), T(0), T(0), T(1))
  47. {
  48. }
  49. TQuat(const TQuat& b)
  50. : m_vec(b.m_vec)
  51. {
  52. }
  53. explicit TQuat(const T x_, const T y_, const T z_, const T w_)
  54. : m_vec(x_, y_, z_, w_)
  55. {
  56. }
  57. explicit TQuat(const T arr[])
  58. : m_vec(arr)
  59. {
  60. }
  61. explicit TQuat(const TVec<T, 2>& v, const T z_, const T w_)
  62. : m_vec(v, z_, w_)
  63. {
  64. }
  65. explicit TQuat(const TVec<T, 3>& v, const T w_)
  66. : m_vec(v, w_)
  67. {
  68. }
  69. explicit TQuat(const TVec<T, 4>& v)
  70. : m_vec(v)
  71. {
  72. }
  73. // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
  74. explicit TQuat(const TMat<T, 3, 3>& m)
  75. {
  76. const T tr = m(0, 0) + m(1, 1) + m(2, 2);
  77. if(tr > T(0))
  78. {
  79. const T S = sqrt<T>(tr + T(1)) * T(2); // S=4*qw
  80. w = T(0.25) * S;
  81. x = (m(2, 1) - m(1, 2)) / S;
  82. y = (m(0, 2) - m(2, 0)) / S;
  83. z = (m(1, 0) - m(0, 1)) / S;
  84. }
  85. else if(m(0, 0) > m(1, 1) && m(0, 0) > m(2, 2))
  86. {
  87. const T S = sqrt<T>(T(1) + m(0, 0) - m(1, 1) - m(2, 2)) * T(2); // S=4*qx
  88. w = (m(2, 1) - m(1, 2)) / S;
  89. x = T(0.25) * S;
  90. y = (m(0, 1) + m(1, 0)) / S;
  91. z = (m(0, 2) + m(2, 0)) / S;
  92. }
  93. else if(m(1, 1) > m(2, 2))
  94. {
  95. const T S = sqrt<T>(T(1) + m(1, 1) - m(0, 0) - m(2, 2)) * T(2); // S=4*qy
  96. w = (m(0, 2) - m(2, 0)) / S;
  97. x = (m(0, 1) + m(1, 0)) / S;
  98. y = T(0.25) * S;
  99. z = (m(1, 2) + m(2, 1)) / S;
  100. }
  101. else
  102. {
  103. const T S = sqrt<T>(T(1) + m(2, 2) - m(0, 0) - m(1, 1)) * T(2); // S=4*qz
  104. w = (m(1, 0) - m(0, 1)) / S;
  105. x = (m(0, 2) + m(2, 0)) / S;
  106. y = (m(1, 2) + m(2, 1)) / S;
  107. z = T(0.25) * S;
  108. }
  109. }
  110. explicit TQuat(const TMat<T, 3, 4>& m)
  111. : TQuat(m.getRotationPart())
  112. {
  113. ANKI_ASSERT(isZero<T>(m(0, 3)) && isZero<T>(m(1, 3)) && isZero<T>(m(2, 3)));
  114. }
  115. explicit TQuat(const TEuler<T>& eu)
  116. {
  117. T cx, sx;
  118. sinCos(eu.y * T(0.5), sx, cx);
  119. T cy, sy;
  120. sinCos(eu.z * T(0.5), sy, cy);
  121. T cz, sz;
  122. sinCos(eu.x * T(0.5), sz, cz);
  123. const T cxcy = cx * cy;
  124. const T sxsy = sx * sy;
  125. x = cxcy * sz + sxsy * cz;
  126. y = sx * cy * cz + cx * sy * sz;
  127. z = cx * sy * cz - sx * cy * sz;
  128. w = cxcy * cz - sxsy * sz;
  129. }
  130. explicit TQuat(const TAxisang<T>& axisang)
  131. {
  132. const T lengthsq = axisang.getAxis().lengthSquared();
  133. if(isZero<T>(lengthsq))
  134. {
  135. (*this) = getIdentity();
  136. return;
  137. }
  138. const T rad = axisang.getAngle() * T(0.5);
  139. T sintheta, costheta;
  140. sinCos(rad, sintheta, costheta);
  141. const T scalefactor = sintheta / sqrt(lengthsq);
  142. m_vec = TVec<T, 4>(axisang.getAxis(), costheta) * TVec<T, 4>(scalefactor, scalefactor, scalefactor, T(1));
  143. }
  144. // Operators with same type //
  145. TQuat& operator=(const TQuat& b)
  146. {
  147. m_vec = b.m_vec;
  148. return *this;
  149. }
  150. Bool operator==(const TQuat& b) const
  151. {
  152. return m_vec == b.m_vec;
  153. }
  154. Bool operator!=(const TQuat& b) const
  155. {
  156. return m_vec != b.m_vec;
  157. }
  158. // Combine rotations (SIMD version)
  159. TQuat operator*(const TQuat& b) requires(kSseEnabled)
  160. {
  161. #if ANKI_SIMD_SSE
  162. if constexpr(kSseEnabled)
  163. {
  164. // Taken from: http://momchil-velikov.blogspot.nl/2013/10/fast-sse-quternion-multiplication.html
  165. const __m128 abcd = m_vec.getSimd();
  166. const __m128 xyzw = b.m_vec.getSimd();
  167. const __m128 t0 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(3, 3, 3, 3));
  168. const __m128 t1 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(2, 3, 0, 1));
  169. const __m128 t3 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(0, 0, 0, 0));
  170. const __m128 t4 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(1, 0, 3, 2));
  171. const __m128 t5 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(1, 1, 1, 1));
  172. const __m128 t6 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(2, 0, 3, 1));
  173. // [d,d,d,d] * [z,w,x,y] = [dz,dw,dx,dy]
  174. const __m128 m0 = _mm_mul_ps(t0, t1);
  175. // [a,a,a,a] * [y,x,w,z] = [ay,ax,aw,az]
  176. const __m128 m1 = _mm_mul_ps(t3, t4);
  177. // [b,b,b,b] * [z,x,w,y] = [bz,bx,bw,by]
  178. const __m128 m2 = _mm_mul_ps(t5, t6);
  179. // [c,c,c,c] * [w,z,x,y] = [cw,cz,cx,cy]
  180. const __m128 t7 = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(2, 2, 2, 2));
  181. const __m128 t8 = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(3, 2, 0, 1));
  182. const __m128 m3 = _mm_mul_ps(t7, t8);
  183. // [dz,dw,dx,dy] + -[ay,ax,aw,az] = [dz+ay,dw-ax,dx+aw,dy-az]
  184. __m128 e = _mm_addsub_ps(m0, m1);
  185. // [dx+aw,dz+ay,dy-az,dw-ax]
  186. e = _mm_shuffle_ps(e, e, _MM_SHUFFLE(1, 3, 0, 2));
  187. // [dx+aw,dz+ay,dy-az,dw-ax] + -[bz,bx,bw,by] = [dx+aw+bz,dz+ay-bx,dy-az+bw,dw-ax-by]
  188. e = _mm_addsub_ps(e, m2);
  189. // [dz+ay-bx,dw-ax-by,dy-az+bw,dx+aw+bz]
  190. e = _mm_shuffle_ps(e, e, _MM_SHUFFLE(2, 0, 1, 3));
  191. // [dz+ay-bx,dw-ax-by,dy-az+bw,dx+aw+bz] + -[cw,cz,cx,cy] = [dz+ay-bx+cw,dw-ax-by-cz,dy-az+bw+cx,dx+aw+bz-cy]
  192. e = _mm_addsub_ps(e, m3);
  193. // [dw-ax-by-cz,dz+ay-bx+cw,dy-az+bw+cx,dx+aw+bz-cy]
  194. return TQuat(TVec<T, 4>(_mm_shuffle_ps(e, e, _MM_SHUFFLE(2, 3, 1, 0))));
  195. }
  196. else
  197. #endif
  198. {
  199. // Non-SIMD version
  200. const T lx = m_vec.x;
  201. const T ly = m_vec.y;
  202. const T lz = m_vec.z;
  203. const T lw = m_vec.w;
  204. const T rx = b.m_vec.x;
  205. const T ry = b.m_vec.y;
  206. const T rz = b.m_vec.z;
  207. const T rw = b.m_vec.w;
  208. const T x = lw * rx + lx * rw + ly * rz - lz * ry;
  209. const T y = lw * ry - lx * rz + ly * rw + lz * rx;
  210. const T z = lw * rz + lx * ry - ly * rx + lz * rw;
  211. const T w = lw * rw - lx * rx - ly * ry - lz * rz;
  212. return Quat(x, y, z, w);
  213. }
  214. }
  215. // Convert to Vec4.
  216. explicit operator TVec<T, 4>() const
  217. {
  218. return m_vec;
  219. }
  220. // Operators with other types //
  221. T operator[](const U32 i) const
  222. {
  223. return m_vec[i];
  224. }
  225. T& operator[](const U32 i)
  226. {
  227. return m_vec[i];
  228. }
  229. // Rotate a vector by this quat.
  230. TVec<T, 3> operator*(const TVec<T, 3>& inValue) const
  231. {
  232. // Rotating a vector by a quaternion is done by: p' = q * p * q^-1 (q^-1 = conjugated(q) for a unit quaternion)
  233. ANKI_ASSERT(isZero<T>(T(1) - m_vec.getLength()));
  234. return TVec<T, 3>((*this * TQuat(TVec<T, 4>(inValue, T(0))) * conjugated()).m_vec.xyz);
  235. }
  236. // Other //
  237. [[nodiscard]] T length() const
  238. {
  239. return m_vec.length();
  240. }
  241. /// Calculates the rotation from vector "from" to "to".
  242. static TQuat fromPointToPoint(const TVec<T, 3>& from, const TVec<T, 3>& to)
  243. {
  244. const TVec<T, 3> axis(from.cross(to));
  245. TVec<T, 4> quat = TVec4<T, 4>(axis.x, axis.y, axis.z, from.dot(to));
  246. quat = quat.normalize();
  247. quat.w += T(1);
  248. if(quat.w <= T(0.0001))
  249. {
  250. if(from.z * from.z > from.x * from.x)
  251. {
  252. quat = TVec<T, 4>(T(0), from.z, -from.y, T(0));
  253. }
  254. else
  255. {
  256. quat = TVec<T, 4>(from.y, -from.x, T(0), T(0));
  257. }
  258. }
  259. quat = quat.normalize();
  260. return TQuat(quat);
  261. }
  262. [[nodiscard]] TQuat invert() const
  263. {
  264. const T len = m_vec.length();
  265. ANKI_ASSERT(!isZero<T>(len));
  266. return conjugated() / len;
  267. }
  268. [[nodiscard]] TQuat conjugated() const
  269. {
  270. return TQuat(m_vec * TVec<T, 4>(T(-1), T(-1), T(-1), T(1)));
  271. }
  272. /// Returns slerp(this, q1, t)
  273. [[nodiscard]] TQuat slerp(const TQuat& destination, const T t) const
  274. {
  275. // Difference at which to LERP instead of SLERP
  276. const T delta = T(0.0001);
  277. // Calc cosine
  278. T sinScale1 = T(1);
  279. T cosComega = m_vec.dot(destination.m_vec);
  280. // Adjust signs (if necessary)
  281. if(cosComega < T(0))
  282. {
  283. cosComega = -cosComega;
  284. sinScale1 = T(-1);
  285. }
  286. // Calculate coefficients
  287. T scale0, scale1;
  288. if(T(1) - cosComega > delta)
  289. {
  290. // Standard case (slerp)
  291. const F32 omega = acos<T>(cosComega);
  292. const F32 sinOmega = sin<T>(omega);
  293. scale0 = sin<T>((T(1) - t) * omega) / sinOmega;
  294. scale1 = sinScale1 * sin<T>(t * omega) / sinOmega;
  295. }
  296. else
  297. {
  298. // Quaternions are very close so we can do a linear interpolation
  299. scale0 = T(1) - t;
  300. scale1 = sinScale1 * t;
  301. }
  302. // Interpolate between the two quaternions
  303. const TVec<T, 4> v = TVec<T, 4>(scale0) * m_vec + TVec<T, 4>(scale1) * destination.m_vec;
  304. return TQuat(v.normalize());
  305. }
  306. [[nodiscard]] TQuat rotateXAxis(const T rad) const
  307. {
  308. const TQuat r(Axisang<T>(rad, TVec<T, 3>(T(1), T(0), T(0))));
  309. return r * (*this);
  310. }
  311. [[nodiscard]] TQuat rotateYAxis(const T rad) const
  312. {
  313. const TQuat r(Axisang<T>(rad, TVec<T, 3>(T(0), T(1), T(0))));
  314. return r * (*this);
  315. }
  316. [[nodiscard]] TQuat rotateZAxis(const T rad) const
  317. {
  318. const TQuat r(Axisang<T>(rad, TVec<T, 3>(T(0), T(0), T(1))));
  319. return r * (*this);
  320. }
  321. [[nodiscard]] TQuat normalize() const
  322. {
  323. return TQuat(m_vec.normalize());
  324. }
  325. void setIdentity()
  326. {
  327. *this = getIdentity();
  328. }
  329. static TQuat getIdentity()
  330. {
  331. return TQuat();
  332. }
  333. static constexpr U32 getSize()
  334. {
  335. return 4;
  336. }
  337. String toString() const requires(std::is_floating_point<T>::value)
  338. {
  339. return m_vec.toString();
  340. }
  341. };
  342. using Quat = TQuat<F32>;
  343. using DQuat = TQuat<F64>;
  344. } // end namespace anki