Quat.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. // Copyright (C) 2009-2016, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <anki/math/CommonIncludes.h>
  7. #include <anki/math/Vec4.h>
  8. namespace anki
  9. {
  10. /// @addtogroup math
  11. /// @{
  12. /// Quaternion. Used in rotations
  13. template<typename T>
  14. class alignas(16) TQuat
  15. : public TVec<T, 4, typename TVec4Simd<T>::Type, TQuat<T>>
  16. {
  17. public:
  18. using Base = TVec<T, 4, typename TVec4Simd<T>::Type, TQuat<T>>;
  19. using Base::x;
  20. using Base::y;
  21. using Base::z;
  22. using Base::w;
  23. using Base::normalize; // Shortcut
  24. using Base::getLengthSquared; // Shortcut
  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 TVec2<T>& v, const T z_, const T w_)
  52. : Base(v, z_, w_)
  53. {
  54. }
  55. TQuat(const TVec3<T>& v, const T w_)
  56. : Base(v, w_)
  57. {
  58. }
  59. explicit TQuat(const TVec4<T>& v)
  60. : Base(v.x(), v.y(), v.z(), v.w())
  61. {
  62. }
  63. explicit TQuat(const TMat3<T>& m3)
  64. {
  65. T trace = m3(0, 0) + m3(1, 1) + m3(2, 2) + 1.0;
  66. if(trace > getEpsilon<T>())
  67. {
  68. T s = 0.5 / sqrt<T>(trace);
  69. w() = 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 = 0.5 / sqrt<T>(1.0 + m3(0, 0) - m3(1, 1) - m3(2, 2));
  79. w() = (m3(1, 2) - m3(2, 1)) * s;
  80. x() = 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 = 0.5 / sqrt<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() = 0.25 / s;
  90. z() = (m3(1, 2) + m3(2, 1)) * s;
  91. }
  92. else
  93. {
  94. T s = 0.5 / sqrt<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() = 0.25 / s;
  99. }
  100. }
  101. }
  102. explicit TQuat(const TMat3x4<T>& m)
  103. : TQuat(m.getRotationPart())
  104. {
  105. ANKI_ASSERT(
  106. 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. 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 Other
  142. /// @{
  143. /// Calculates the rotation from TVec3 "from" to "to"
  144. void setFrom2Vec3(const TVec3<T>& from, const TVec3<T>& to)
  145. {
  146. TVec3<T> axis(from.cross(to));
  147. *this = TQuat(axis.x(), axis.y(), axis.z(), from.dot(to));
  148. normalize();
  149. w() += 1.0;
  150. if(w() <= getEpsilon<T>())
  151. {
  152. if(from.z() * from.z() > from.x() * from.x())
  153. {
  154. *this = TQuat(0.0, from.z(), -from.y(), 0.0);
  155. }
  156. else
  157. {
  158. *this = TQuat(from.y(), -from.x(), 0.0, 0.0);
  159. }
  160. }
  161. normalize();
  162. }
  163. TQuat getInverted() const
  164. {
  165. T norm = getLengthSquared();
  166. ANKI_ASSERT(!isZero<T>(norm)); // Norm is zero
  167. T normi = 1.0 / norm;
  168. return TQuat(-normi * x(), -normi * y(), -normi * z(), normi * w());
  169. }
  170. void invert()
  171. {
  172. (*this) = getInverted();
  173. }
  174. void conjugate()
  175. {
  176. x() = -x();
  177. y() = -y();
  178. z() = -z();
  179. }
  180. TQuat getConjugated() const
  181. {
  182. return TQuat(-x(), -y(), -z(), w());
  183. }
  184. /// Returns slerp(this, q1, t)
  185. TQuat slerp(const TQuat& q1_, const T t) const
  186. {
  187. TQuat q1 = q1_;
  188. const TQuat& q0 = *this;
  189. T cosHalfTheta = q0.dot(q1);
  190. if(cosHalfTheta < 0.0)
  191. {
  192. q1 = -q1; // quat changes
  193. cosHalfTheta = -cosHalfTheta;
  194. }
  195. if(fabs<T>(cosHalfTheta) >= 1.0)
  196. {
  197. return TQuat(q0);
  198. }
  199. T halfTheta = acos<T>(cosHalfTheta);
  200. T sinHalfTheta = sqrt<T>(1.0 - cosHalfTheta * cosHalfTheta);
  201. if(fabs<T>(sinHalfTheta) < 0.001)
  202. {
  203. return TQuat((q0 + q1) * 0.5);
  204. }
  205. T ratioA = sin<T>((1.0 - t) * halfTheta) / sinHalfTheta;
  206. T ratioB = sin<T>(t * halfTheta) / sinHalfTheta;
  207. TQuat tmp, tmp1, sum;
  208. tmp = q0 * ratioA;
  209. tmp1 = q1 * ratioB;
  210. sum = tmp + tmp1;
  211. sum.normalize();
  212. return TQuat(sum);
  213. }
  214. /// @note 16 muls, 12 adds
  215. TQuat combineRotations(const TQuat& b) const
  216. {
  217. // XXX See if this can be optimized
  218. TQuat out;
  219. out.x() = x() * b.w() + y() * b.z() - z() * b.y() + w() * b.x();
  220. out.y() = -x() * b.z() + y() * b.w() + z() * b.x() + w() * b.y();
  221. out.z() = x() * b.y() - y() * b.x() + z() * b.w() + w() * b.z();
  222. out.w() = -x() * b.x() - y() * b.y() - z() * b.z() + w() * b.w();
  223. return out;
  224. }
  225. /// Returns q * this * q.Conjucated() aka returns a rotated this.
  226. /// 18 muls, 12 adds
  227. TVec3<T> rotate(const TVec3<T>& v) const
  228. {
  229. ANKI_ASSERT(isZero<T>(1.0 - Base::getLength())); // Not normalized quat
  230. TVec3<T> qXyz(Base::xyz());
  231. return v + qXyz.cross(qXyz.cross(v) + v * Base::w()) * 2.0;
  232. }
  233. void setIdentity()
  234. {
  235. *this = getIdentity();
  236. }
  237. static TQuat getIdentity()
  238. {
  239. return TQuat(0.0, 0.0, 0.0, 1.0);
  240. }
  241. /// @}
  242. };
  243. /// F32 quaternion
  244. typedef TQuat<F32> Quat;
  245. /// @}
  246. } // end namespace anki