Quat.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Copyright (C) 2009-2021, 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. {
  10. /// @addtogroup math
  11. /// @{
  12. /// Quaternion. Used in rotations
  13. template<typename T>
  14. class alignas(16) TQuat : public TVec<T, 4>
  15. {
  16. public:
  17. using Base = TVec<T, 4>;
  18. using Base::x;
  19. using Base::y;
  20. using Base::z;
  21. using Base::w;
  22. using Base::normalize; // Shortcut
  23. using Base::getLengthSquared; // Shortcut
  24. using Base::operator-;
  25. using Base::operator=;
  26. /// @name Constructors
  27. /// @{
  28. TQuat()
  29. : Base()
  30. {
  31. }
  32. TQuat(const TQuat& b)
  33. : Base(b)
  34. {
  35. }
  36. TQuat(const T x_, const T y_, const T z_, const T w_)
  37. : Base(x_, y_, z_, w_)
  38. {
  39. }
  40. explicit TQuat(const T f)
  41. : Base(f)
  42. {
  43. }
  44. explicit TQuat(const T arr[])
  45. : Base(arr)
  46. {
  47. }
  48. explicit TQuat(const typename Base::Simd& simd)
  49. : Base(simd)
  50. {
  51. }
  52. TQuat(const TVec<T, 2>& v, const T z_, const T w_)
  53. : Base(v, z_, w_)
  54. {
  55. }
  56. TQuat(const TVec<T, 3>& v, const T w_)
  57. : Base(v, w_)
  58. {
  59. }
  60. TQuat(const Base& v)
  61. : Base(v.x(), v.y(), v.z(), v.w())
  62. {
  63. }
  64. explicit TQuat(const TMat<T, 3, 3>& m3)
  65. {
  66. const T trace = m3(0, 0) + m3(1, 1) + m3(2, 2) + T(1.0);
  67. if(trace > EPSILON)
  68. {
  69. T s = T(0.5) / sqrt<T>(trace);
  70. w() = T(0.25) / s;
  71. x() = (m3(2, 1) - m3(1, 2)) * s;
  72. y() = (m3(0, 2) - m3(2, 0)) * s;
  73. z() = (m3(1, 0) - m3(0, 1)) * s;
  74. }
  75. else
  76. {
  77. if(m3(0, 0) > m3(1, 1) && m3(0, 0) > m3(2, 2))
  78. {
  79. T s = T(0.5) / sqrt<T>(T(1.0) + m3(0, 0) - m3(1, 1) - m3(2, 2));
  80. w() = (m3(1, 2) - m3(2, 1)) * s;
  81. x() = T(0.25) / s;
  82. y() = (m3(0, 1) + m3(1, 0)) * s;
  83. z() = (m3(0, 2) + m3(2, 0)) * s;
  84. }
  85. else if(m3(1, 1) > m3(2, 2))
  86. {
  87. T s = T(0.5) / sqrt<T>(T(1.0) + m3(1, 1) - m3(0, 0) - m3(2, 2));
  88. w() = (m3(0, 2) - m3(2, 0)) * s;
  89. x() = (m3(0, 1) + m3(1, 0)) * s;
  90. y() = T(0.25) / s;
  91. z() = (m3(1, 2) + m3(2, 1)) * s;
  92. }
  93. else
  94. {
  95. T s = T(0.5) / sqrt<T>(T(1.0) + m3(2, 2) - m3(0, 0) - m3(1, 1));
  96. w() = (m3(0, 1) - m3(1, 0)) * s;
  97. x() = (m3(0, 2) + m3(2, 0)) * s;
  98. y() = (m3(1, 2) + m3(2, 1)) * s;
  99. z() = T(0.25) / s;
  100. }
  101. }
  102. }
  103. explicit TQuat(const TMat<T, 3, 4>& m)
  104. : TQuat(m.getRotationPart())
  105. {
  106. ANKI_ASSERT(isZero<T>(m(0, 3)) && isZero<T>(m(1, 3)) && isZero<T>(m(2, 3)));
  107. }
  108. explicit TQuat(const TEuler<T>& eu)
  109. {
  110. T cx, sx;
  111. sinCos(eu.y() * 0.5, sx, cx);
  112. T cy, sy;
  113. sinCos(eu.z() * 0.5, sy, cy);
  114. T cz, sz;
  115. sinCos(eu.x() * 0.5, sz, cz);
  116. T cxcy = cx * cy;
  117. T sxsy = sx * sy;
  118. x() = cxcy * sz + sxsy * cz;
  119. y() = sx * cy * cz + cx * sy * sz;
  120. z() = cx * sy * cz - sx * cy * sz;
  121. w() = cxcy * cz - sxsy * sz;
  122. }
  123. explicit TQuat(const TAxisang<T>& axisang)
  124. {
  125. const T lengthsq = axisang.getAxis().getLengthSquared();
  126. if(isZero<T>(lengthsq))
  127. {
  128. (*this) = getIdentity();
  129. return;
  130. }
  131. T rad = axisang.getAngle() * 0.5;
  132. T sintheta, costheta;
  133. sinCos(rad, sintheta, costheta);
  134. T scalefactor = sintheta / sqrt(lengthsq);
  135. x() = scalefactor * axisang.getAxis().x();
  136. y() = scalefactor * axisang.getAxis().y();
  137. z() = scalefactor * axisang.getAxis().z();
  138. w() = costheta;
  139. }
  140. /// @}
  141. /// @name Operators with same type
  142. /// @{
  143. TQuat& operator=(const TQuat& b)
  144. {
  145. x() = b.x();
  146. y() = b.y();
  147. z() = b.z();
  148. w() = b.w();
  149. return *this;
  150. }
  151. /// @}
  152. /// @name Other
  153. /// @{
  154. /// Calculates the rotation from TVec3 "from" to "to"
  155. void setFrom2Vec3(const TVec<T, 3>& from, const TVec<T, 3>& to)
  156. {
  157. TVec<T, 3> axis(from.cross(to));
  158. *this = TQuat(axis.x(), axis.y(), axis.z(), from.dot(to));
  159. normalize();
  160. w() += 1.0;
  161. if(w() <= EPSILON)
  162. {
  163. if(from.z() * from.z() > from.x() * from.x())
  164. {
  165. *this = TQuat(0.0, from.z(), -from.y(), 0.0);
  166. }
  167. else
  168. {
  169. *this = TQuat(from.y(), -from.x(), 0.0, 0.0);
  170. }
  171. }
  172. normalize();
  173. }
  174. TQuat getInverted() const
  175. {
  176. T norm = getLengthSquared();
  177. ANKI_ASSERT(!isZero<T>(norm)); // Norm is zero
  178. T normi = 1.0 / norm;
  179. return TQuat(-normi * x(), -normi * y(), -normi * z(), normi * w());
  180. }
  181. void invert()
  182. {
  183. (*this) = getInverted();
  184. }
  185. void conjugate()
  186. {
  187. x() = -x();
  188. y() = -y();
  189. z() = -z();
  190. }
  191. TQuat getConjugated() const
  192. {
  193. return TQuat(-x(), -y(), -z(), w());
  194. }
  195. /// Returns slerp(this, q1, t)
  196. TQuat slerp(const TQuat& q1_, const T t) const
  197. {
  198. TQuat q1 = q1_;
  199. const TQuat& q0 = *this;
  200. T cosHalfTheta = q0.dot(q1);
  201. if(cosHalfTheta < 0.0)
  202. {
  203. q1 = -q1; // quat changes
  204. cosHalfTheta = -cosHalfTheta;
  205. }
  206. if(absolute<T>(cosHalfTheta) >= 1.0)
  207. {
  208. return TQuat(q0);
  209. }
  210. const T halfTheta = acos<T>(cosHalfTheta);
  211. const T sinHalfTheta = sqrt<T>(T(1) - cosHalfTheta * cosHalfTheta);
  212. if(absolute<T>(sinHalfTheta) < 0.001)
  213. {
  214. return TQuat((q0 + q1) * 0.5);
  215. }
  216. const T ratioA = sin<T>((T(1) - t) * halfTheta) / sinHalfTheta;
  217. const T ratioB = sin<T>(t * halfTheta) / sinHalfTheta;
  218. TQuat tmp, tmp1, sum;
  219. tmp = q0 * ratioA;
  220. tmp1 = q1 * ratioB;
  221. sum = tmp + tmp1;
  222. sum.normalize();
  223. return TQuat(sum);
  224. }
  225. /// @note 16 muls, 12 adds
  226. TQuat combineRotations(const TQuat& b) const
  227. {
  228. // XXX See if this can be optimized
  229. TQuat out;
  230. out.x() = x() * b.w() + y() * b.z() - z() * b.y() + w() * b.x();
  231. out.y() = -x() * b.z() + y() * b.w() + z() * b.x() + w() * b.y();
  232. out.z() = x() * b.y() - y() * b.x() + z() * b.w() + w() * b.z();
  233. out.w() = -x() * b.x() - y() * b.y() - z() * b.z() + w() * b.w();
  234. return out;
  235. }
  236. /// Returns q * this * q.Conjucated() aka returns a rotated this. 18 muls, 12 adds
  237. TVec<T, 3> rotate(const TVec<T, 3>& v) const
  238. {
  239. ANKI_ASSERT(isZero<T>(1.0 - Base::getLength())); // Not normalized quat
  240. TVec<T, 3> qXyz(Base::xyz());
  241. return v + qXyz.cross(qXyz.cross(v) + v * Base::w()) * 2.0;
  242. }
  243. void setIdentity()
  244. {
  245. *this = getIdentity();
  246. }
  247. static TQuat getIdentity()
  248. {
  249. return TQuat(0.0, 0.0, 0.0, 1.0);
  250. }
  251. /// @}
  252. };
  253. /// F32 quaternion
  254. using Quat = TQuat<F32>;
  255. /// F64 quaternion
  256. using DQuat = TQuat<F64>;
  257. /// @}
  258. } // end namespace anki