2
0

Quat.h 5.9 KB

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