Cry_Quat.h 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Common quaternion class
  9. #pragma once
  10. #include <AzCore/Math/Quaternion.h>
  11. //----------------------------------------------------------------------
  12. // Quaternion
  13. //----------------------------------------------------------------------
  14. template <typename F>
  15. struct Quat_tpl
  16. {
  17. Vec3_tpl<F> v;
  18. F w;
  19. //-------------------------------
  20. //constructors
  21. #if defined(_DEBUG)
  22. ILINE Quat_tpl()
  23. {
  24. if constexpr (sizeof(F) == 4)
  25. {
  26. uint32* p = alias_cast<uint32*>(&v.x);
  27. p[0] = F32NAN;
  28. p[1] = F32NAN;
  29. p[2] = F32NAN;
  30. p[3] = F32NAN;
  31. }
  32. if constexpr (sizeof(F) == 8)
  33. {
  34. uint64* p = alias_cast<uint64*>(&v.x);
  35. p[0] = F64NAN;
  36. p[1] = F64NAN;
  37. p[2] = F64NAN;
  38. p[3] = F64NAN;
  39. }
  40. }
  41. #else
  42. ILINE Quat_tpl() {}
  43. #endif
  44. //initialize with zeros
  45. ILINE Quat_tpl(type_zero)
  46. {
  47. w = 0, v.x = 0, v.y = 0, v.z = 0;
  48. }
  49. ILINE Quat_tpl(type_identity)
  50. {
  51. w = 1, v.x = 0, v.y = 0, v.z = 0;
  52. }
  53. //ASSIGNMENT OPERATOR of identical Quat types.
  54. //The assignment operator has precedence over assignment constructor
  55. //Quat q; q=q0;
  56. ILINE Quat_tpl<F>& operator = (const Quat_tpl<F>& src)
  57. {
  58. v.x = src.v.x;
  59. v.y = src.v.y;
  60. v.z = src.v.z;
  61. w = src.w;
  62. assert(IsValid());
  63. return *this;
  64. }
  65. //CONSTRUCTOR to initialize a Quat from 4 floats
  66. //Quat q(1,0,0,0);
  67. ILINE Quat_tpl<F>(F qw, F qx, F qy, F qz)
  68. {
  69. w = qw;
  70. v.x = qx;
  71. v.y = qy;
  72. v.z = qz;
  73. assert(IsValid());
  74. }
  75. //CONSTRUCTOR to initialize a Quat with a scalar and a vector
  76. //Quat q(1,Vec3(0,0,0));
  77. ILINE Quat_tpl<F>(F scalar, const Vec3_tpl<F> &vector)
  78. {
  79. v = vector;
  80. w = scalar;
  81. assert(IsValid());
  82. };
  83. //CONSTRUCTOR for identical types
  84. //Quat q=q0;
  85. ILINE Quat_tpl<F>(const Quat_tpl<F>&q)
  86. {
  87. w = q.w;
  88. v.x = q.v.x;
  89. v.y = q.v.y;
  90. v.z = q.v.z;
  91. assert(IsValid());
  92. }
  93. //CONSTRUCTOR for AZ::Quaternion
  94. explicit ILINE Quat_tpl<F>(const AZ::Quaternion& q)
  95. {
  96. w = q.GetW();
  97. v.x = q.GetX();
  98. v.y = q.GetY();
  99. v.z = q.GetZ();
  100. assert(IsValid());
  101. }
  102. //CONSTRUCTOR for identical types which converts between double/float
  103. //Quat q32=q64;
  104. //Quatr q64=q32;
  105. template <class F1>
  106. ILINE Quat_tpl<F>(const Quat_tpl<F1>&q)
  107. {
  108. assert(q.IsValid());
  109. w = F(q.w);
  110. v.x = F(q.v.x);
  111. v.y = F(q.v.y);
  112. v.z = F(q.v.z);
  113. }
  114. //CONSTRUCTOR for different types. It converts a Euler Angle into a Quat.
  115. //Needs to be 'explicit' because we loose fp-precision in the conversion process
  116. //Quat(Ang3(1,2,3));
  117. explicit ILINE Quat_tpl<F>(const Ang3_tpl<F>&ang)
  118. {
  119. assert(ang.IsValid());
  120. SetRotationXYZ(ang);
  121. }
  122. //CONSTRUCTOR for different types. It converts a Euler Angle into a Quat and converts between double/float. .
  123. //Needs to be 'explicit' because we loose fp-precision in the conversion process
  124. //Quat(Ang3r(1,2,3));
  125. template<class F1>
  126. explicit ILINE Quat_tpl<F>(const Ang3_tpl<F1>&ang)
  127. {
  128. assert(ang.IsValid());
  129. SetRotationXYZ(Ang3_tpl<F>(F(ang.x), F(ang.y), F(ang.z)));
  130. }
  131. //CONSTRUCTOR for different types. It converts a Matrix33 into a Quat.
  132. //Needs to be 'explicit' because we loose fp-precision in the conversion process
  133. //Quat(m33);
  134. explicit ILINE Quat_tpl<F>(const Matrix33_tpl<F>&m)
  135. {
  136. assert(m.IsOrthonormalRH(0.1f));
  137. F s, p, tr = m.m00 + m.m11 + m.m22;
  138. w = 1, v.x = 0, v.y = 0, v.z = 0;
  139. if (tr > 0)
  140. {
  141. s = sqrt_tpl(tr + 1.0f), p = 0.5f / s, w = s * 0.5f, v.x = (m.m21 - m.m12) * p, v.y = (m.m02 - m.m20) * p, v.z = (m.m10 - m.m01) * p;
  142. }
  143. else if ((m.m00 >= m.m11) && (m.m00 >= m.m22))
  144. {
  145. s = sqrt_tpl(m.m00 - m.m11 - m.m22 + 1.0f), p = 0.5f / s, w = (m.m21 - m.m12) * p, v.x = s * 0.5f, v.y = (m.m10 + m.m01) * p, v.z = (m.m20 + m.m02) * p;
  146. }
  147. else if ((m.m11 >= m.m00) && (m.m11 >= m.m22))
  148. {
  149. s = sqrt_tpl(m.m11 - m.m22 - m.m00 + 1.0f), p = 0.5f / s, w = (m.m02 - m.m20) * p, v.x = (m.m01 + m.m10) * p, v.y = s * 0.5f, v.z = (m.m21 + m.m12) * p;
  150. }
  151. else if ((m.m22 >= m.m00) && (m.m22 >= m.m11))
  152. {
  153. s = sqrt_tpl(m.m22 - m.m00 - m.m11 + 1.0f), p = 0.5f / s, w = (m.m10 - m.m01) * p, v.x = (m.m02 + m.m20) * p, v.y = (m.m12 + m.m21) * p, v.z = s * 0.5f;
  154. }
  155. }
  156. //CONSTRUCTOR for different types. It converts a Matrix33 into a Quat and converts between double/float.
  157. //Needs to be 'explicit' because we loose fp-precision the conversion process
  158. //Quat(m33r);
  159. //Quatr(m33);
  160. template<class F1>
  161. explicit ILINE Quat_tpl<F>(const Matrix33_tpl<F1>&m)
  162. {
  163. assert(m.IsOrthonormalRH(0.1f));
  164. F1 s, p, tr = m.m00 + m.m11 + m.m22;
  165. w = 1, v.x = 0, v.y = 0, v.z = 0;
  166. if (tr > 0)
  167. {
  168. s = sqrt_tpl(tr + 1.0f), p = 0.5f / s, w = F(s * 0.5), v.x = F((m.m21 - m.m12) * p), v.y = F((m.m02 - m.m20) * p), v.z = F((m.m10 - m.m01) * p);
  169. }
  170. else if ((m.m00 >= m.m11) && (m.m00 >= m.m22))
  171. {
  172. s = sqrt_tpl(m.m00 - m.m11 - m.m22 + 1.0f), p = 0.5f / s, w = F((m.m21 - m.m12) * p), v.x = F(s * 0.5), v.y = F((m.m10 + m.m01) * p), v.z = F((m.m20 + m.m02) * p);
  173. }
  174. else if ((m.m11 >= m.m00) && (m.m11 >= m.m22))
  175. {
  176. s = sqrt_tpl(m.m11 - m.m22 - m.m00 + 1.0f), p = 0.5f / s, w = F((m.m02 - m.m20) * p), v.x = F((m.m01 + m.m10) * p), v.y = F(s * 0.5), v.z = F((m.m21 + m.m12) * p);
  177. }
  178. else if ((m.m22 >= m.m00) && (m.m22 >= m.m11))
  179. {
  180. s = sqrt_tpl(m.m22 - m.m00 - m.m11 + 1.0f), p = 0.5f / s, w = F((m.m10 - m.m01) * p), v.x = F((m.m02 + m.m20) * p), v.y = F((m.m12 + m.m21) * p), v.z = F(s * 0.5);
  181. }
  182. }
  183. //CONSTRUCTOR for different types. It converts a Matrix34 into a Quat.
  184. //Needs to be 'explicit' because we loose fp-precision in the conversion process
  185. //Quat(m34);
  186. explicit ILINE Quat_tpl<F>(const Matrix34_tpl<F>&m)
  187. {
  188. *this = Quat_tpl<F>(Matrix33_tpl<F>(m));
  189. }
  190. //CONSTRUCTOR for different types. It converts a Matrix34 into a Quat and converts between double/float.
  191. //Needs to be 'explicit' because we loose fp-precision the conversion process
  192. //Quat(m34r);
  193. //Quatr(m34);
  194. template<class F1>
  195. explicit ILINE Quat_tpl<F>(const Matrix34_tpl<F1>&m)
  196. {
  197. *this = Quat_tpl<F>(Matrix33_tpl<F1>(m));
  198. }
  199. /*!
  200. * invert quaternion.
  201. *
  202. * Example 1:
  203. * Quat q=Quat::CreateRotationXYZ(Ang3(1,2,3));
  204. * Quat result = !q;
  205. * Quat result = GetInverted(q);
  206. * q.Invert();
  207. */
  208. ILINE Quat_tpl<F> operator ! () const { return Quat_tpl(w, -v); }
  209. ILINE void Invert(void) { *this = !*this; }
  210. ILINE Quat_tpl<F> GetInverted() const { return !(*this); }
  211. //flip quaternion. don't confuse this with quaternion-inversion.
  212. ILINE Quat_tpl<F> operator - () const { return Quat_tpl<F>(-w, -v); };
  213. //multiplication by a scalar
  214. void operator *= (F op) { w *= op; v *= op; }
  215. // Exact compare of 2 quats.
  216. ILINE bool operator==(const Quat_tpl<F>& q) const { return (v == q.v) && (w == q.w); }
  217. ILINE bool operator!=(const Quat_tpl<F>& q) const { return !(*this == q); }
  218. //A quaternion is a compressed matrix. Thus there is no problem extracting the rows & columns.
  219. ILINE Vec3_tpl<F> GetColumn(uint32 i)
  220. {
  221. if (i == 0)
  222. {
  223. return GetColumn0();
  224. }
  225. if (i == 1)
  226. {
  227. return GetColumn1();
  228. }
  229. if (i == 2)
  230. {
  231. return GetColumn2();
  232. }
  233. assert(0); //bad index
  234. return Vec3(ZERO);
  235. }
  236. ILINE Vec3_tpl<F> GetColumn0() const {return Vec3_tpl<F>(2 * (v.x * v.x + w * w) - 1, 2 * (v.y * v.x + v.z * w), 2 * (v.z * v.x - v.y * w)); }
  237. ILINE Vec3_tpl<F> GetColumn1() const {return Vec3_tpl<F>(2 * (v.x * v.y - v.z * w), 2 * (v.y * v.y + w * w) - 1, 2 * (v.z * v.y + v.x * w)); }
  238. ILINE Vec3_tpl<F> GetColumn2() const {return Vec3_tpl<F>(2 * (v.x * v.z + v.y * w), 2 * (v.y * v.z - v.x * w), 2 * (v.z * v.z + w * w) - 1); }
  239. ILINE Vec3_tpl<F> GetRow0() const {return Vec3_tpl<F>(2 * (v.x * v.x + w * w) - 1, 2 * (v.x * v.y - v.z * w), 2 * (v.x * v.z + v.y * w)); }
  240. ILINE Vec3_tpl<F> GetRow1() const {return Vec3_tpl<F>(2 * (v.y * v.x + v.z * w), 2 * (v.y * v.y + w * w) - 1, 2 * (v.y * v.z - v.x * w)); }
  241. ILINE Vec3_tpl<F> GetRow2() const {return Vec3_tpl<F>(2 * (v.z * v.x - v.y * w), 2 * (v.z * v.y + v.x * w), 2 * (v.z * v.z + w * w) - 1); }
  242. // These are just copy & pasted components of the GetColumn1() above.
  243. ILINE F GetFwdX() const { return (2 * (v.x * v.y - v.z * w)); }
  244. ILINE F GetFwdY() const { return (2 * (v.y * v.y + w * w) - 1); }
  245. ILINE F GetFwdZ() const { return (2 * (v.z * v.y + v.x * w)); }
  246. ILINE F GetRotZ() const { return atan2_tpl(-GetFwdX(), GetFwdY()); }
  247. /*!
  248. * set identity quaternion
  249. *
  250. * Example:
  251. * Quat q=Quat::CreateIdentity();
  252. * or
  253. * q.SetIdentity();
  254. * or
  255. * Quat p=Quat(IDENTITY);
  256. */
  257. ILINE void SetIdentity(void)
  258. {
  259. w = 1;
  260. v.x = 0;
  261. v.y = 0;
  262. v.z = 0;
  263. }
  264. ILINE static Quat_tpl<F> CreateIdentity(void)
  265. {
  266. return Quat_tpl<F>(1, 0, 0, 0);
  267. }
  268. // Description:
  269. // Check if identity quaternion.
  270. ILINE bool IsIdentity() const
  271. {
  272. return w == 1 && v.x == 0 && v.y == 0 && v.z == 0;
  273. }
  274. ILINE bool IsUnit(F e = VEC_EPSILON) const
  275. {
  276. return fabs_tpl(1 - (w * w + v.x * v.x + v.y * v.y + v.z * v.z)) < e;
  277. }
  278. ILINE bool IsValid([[maybe_unused]] F e = VEC_EPSILON) const
  279. {
  280. if (!v.IsValid())
  281. {
  282. return false;
  283. }
  284. if (!NumberValid(w))
  285. {
  286. return false;
  287. }
  288. //if (!IsUnit(e)) return false;
  289. return true;
  290. }
  291. ILINE void SetRotationAA(F rad, const Vec3_tpl<F>& axis)
  292. {
  293. F s, c;
  294. sincos_tpl(rad * (F)0.5, &s, &c);
  295. SetRotationAA(c, s, axis);
  296. }
  297. ILINE static Quat_tpl<F> CreateRotationAA(F rad, const Vec3_tpl<F>& axis)
  298. {
  299. Quat_tpl<F> q;
  300. q.SetRotationAA(rad, axis);
  301. return q;
  302. }
  303. ILINE void SetRotationAA(F cosha, F sinha, const Vec3_tpl<F>& axis)
  304. {
  305. assert(axis.IsUnit(0.001f));
  306. w = cosha;
  307. v = axis * sinha;
  308. }
  309. ILINE static Quat_tpl<F> CreateRotationAA(F cosha, F sinha, const Vec3_tpl<F>& axis)
  310. {
  311. Quat_tpl<F> q;
  312. q.SetRotationAA(cosha, sinha, axis);
  313. return q;
  314. }
  315. /*!
  316. * Create rotation-quaternion that around the fixed coordinate axes.
  317. *
  318. * Example:
  319. * Quat q=Quat::CreateRotationXYZ( Ang3(1,2,3) );
  320. * or
  321. * q.SetRotationXYZ( Ang3(1,2,3) );
  322. */
  323. ILINE void SetRotationXYZ(const Ang3_tpl<F>& a)
  324. {
  325. assert(a.IsValid());
  326. F sx, cx;
  327. sincos_tpl(F(a.x * F(0.5)), &sx, &cx);
  328. F sy, cy;
  329. sincos_tpl(F(a.y * F(0.5)), &sy, &cy);
  330. F sz, cz;
  331. sincos_tpl(F(a.z * F(0.5)), &sz, &cz);
  332. w = cx * cy * cz + sx * sy * sz;
  333. v.x = cz * cy * sx - sz * sy * cx;
  334. v.y = cz * sy * cx + sz * cy * sx;
  335. v.z = sz * cy * cx - cz * sy * sx;
  336. }
  337. ILINE static Quat_tpl<F> CreateRotationXYZ(const Ang3_tpl<F>& a)
  338. {
  339. assert(a.IsValid());
  340. Quat_tpl<F> q;
  341. q.SetRotationXYZ(a);
  342. return q;
  343. }
  344. // creatr rotation quatation base on ZYX axis
  345. ILINE void SetRotationZYX(const Ang3_tpl<F>& a)
  346. {
  347. assert(a.IsValid());
  348. F sx, cx;
  349. sincos_tpl(F(a.x * F(0.5)), &sx, &cx);
  350. F sy, cy;
  351. sincos_tpl(F(a.y * F(0.5)), &sy, &cy);
  352. F sz, cz;
  353. sincos_tpl(F(a.z * F(0.5)), &sz, &cz);
  354. w = cx * cy * cz - sx * sy * sz;
  355. v.x = cx * sy * sz + sx * cy * cz;
  356. v.y = cx * sy * cz - sx * cy * sz;
  357. v.z = cx * cy * sz + sx * sy * cz;
  358. }
  359. ILINE static Quat_tpl<F> CreateRotationZYX(const Ang3_tpl<F>& a)
  360. {
  361. assert(a.IsValid());
  362. Quat_tpl<F> q;
  363. q.SetRotationZYX(a);
  364. return q;
  365. }
  366. /*!
  367. * Create rotation-quaternion that about the x-axis.
  368. *
  369. * Example:
  370. * Quat q=Quat::CreateRotationX( radiant );
  371. * or
  372. * q.SetRotationX( Ang3(1,2,3) );
  373. */
  374. ILINE void SetRotationX(f32 r)
  375. {
  376. F s, c;
  377. sincos_tpl(F(r * F(0.5)), &s, &c);
  378. w = c;
  379. v.x = s;
  380. v.y = 0;
  381. v.z = 0;
  382. }
  383. ILINE static Quat_tpl<F> CreateRotationX(f32 r)
  384. {
  385. Quat_tpl<F> q;
  386. q.SetRotationX(r);
  387. return q;
  388. }
  389. /*!
  390. * Create rotation-quaternion that about the y-axis.
  391. *
  392. * Example:
  393. * Quat q=Quat::CreateRotationY( radiant );
  394. * or
  395. * q.SetRotationY( radiant );
  396. */
  397. ILINE void SetRotationY(f32 r)
  398. {
  399. F s, c;
  400. sincos_tpl(F(r * F(0.5)), &s, &c);
  401. w = c;
  402. v.x = 0;
  403. v.y = s;
  404. v.z = 0;
  405. }
  406. ILINE static Quat_tpl<F> CreateRotationY(f32 r)
  407. {
  408. Quat_tpl<F> q;
  409. q.SetRotationY(r);
  410. return q;
  411. }
  412. /*!
  413. * Create rotation-quaternion that about the z-axis.
  414. *
  415. * Example:
  416. * Quat q=Quat::CreateRotationZ( radiant );
  417. * or
  418. * q.SetRotationZ( radiant );
  419. */
  420. ILINE void SetRotationZ(f32 r)
  421. {
  422. F s, c;
  423. sincos_tpl(F(r * F(0.5)), &s, &c);
  424. w = c;
  425. v.x = 0;
  426. v.y = 0;
  427. v.z = s;
  428. }
  429. ILINE static Quat_tpl<F> CreateRotationZ(f32 r)
  430. {
  431. Quat_tpl<F> q;
  432. q.SetRotationZ(r);
  433. return q;
  434. }
  435. /*!
  436. *
  437. * Create rotation-quaternion that rotates from one vector to another.
  438. * Both vectors are assumed to be normalized.
  439. *
  440. * Example:
  441. * Quat q=Quat::CreateRotationV0V1( v0,v1 );
  442. * q.SetRotationV0V1( v0,v1 );
  443. */
  444. ILINE void SetRotationV0V1(const Vec3_tpl<F>& v0, const Vec3_tpl<F>& v1)
  445. {
  446. assert(v0.IsUnit(0.01f));
  447. assert(v1.IsUnit(0.01f));
  448. F dot = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z + F(1.0);
  449. if (dot > F(0.0001))
  450. {
  451. F vx = v0.y * v1.z - v0.z * v1.y;
  452. F vy = v0.z * v1.x - v0.x * v1.z;
  453. F vz = v0.x * v1.y - v0.y * v1.x;
  454. F d = isqrt_tpl(dot * dot + vx * vx + vy * vy + vz * vz);
  455. w = F(dot * d);
  456. v.x = F(vx * d);
  457. v.y = F(vy * d);
  458. v.z = F(vz * d);
  459. return;
  460. }
  461. w = 0;
  462. v = v0.GetOrthogonal().GetNormalized();
  463. }
  464. ILINE static Quat_tpl<F> CreateRotationV0V1(const Vec3_tpl<F>& v0, const Vec3_tpl<F>& v1) { Quat_tpl<F> q; q.SetRotationV0V1(v0, v1); return q; }
  465. /*!
  466. *
  467. * \param vdir normalized view direction.
  468. * \param roll radiant to rotate about Y-axis.
  469. *
  470. * Given a view-direction and a radiant to rotate about Y-axis, this function builds a 3x3 look-at quaternion
  471. * using only simple vector arithmetic. This function is always using the implicit up-vector Vec3(0,0,1).
  472. * The view-direction is always stored in column(1).
  473. * IMPORTANT: The view-vector is assumed to be normalized, because all trig-values for the orientation are being
  474. * extracted directly out of the vector. This function must NOT be called with a view-direction
  475. * that is close to Vec3(0,0,1) or Vec3(0,0,-1). If one of these rules is broken, the function returns a quaternion
  476. * with an undefined rotation about the Z-axis.
  477. *
  478. * Rotation order for the look-at-quaternion is Z-X-Y. (Zaxis=YAW / Xaxis=PITCH / Yaxis=ROLL)
  479. *
  480. * COORDINATE-SYSTEM
  481. *
  482. * z-axis
  483. * ^
  484. * |
  485. * | y-axis
  486. * | /
  487. * | /
  488. * |/
  489. * +---------------> x-axis
  490. *
  491. * Example:
  492. * Quat LookAtQuat=Quat::CreateRotationVDir( Vec3(0,1,0) );
  493. * or
  494. * Quat LookAtQuat=Quat::CreateRotationVDir( Vec3(0,1,0), 0.333f );
  495. */
  496. ILINE void SetRotationVDir(const Vec3_tpl<F>& vdir)
  497. {
  498. assert(vdir.IsUnit(0.01f));
  499. //set default initialization for up-vector
  500. w = F(0.70710676908493042);
  501. v.x = F(vdir.z * 0.70710676908493042);
  502. v.y = F(0.0);
  503. v.z = F(0.0);
  504. F l = sqrt_tpl(vdir.x * vdir.x + vdir.y * vdir.y);
  505. if (l > F(0.00001))
  506. {
  507. //calculate LookAt quaternion
  508. Vec3_tpl<F> hv = Vec3_tpl<F> (vdir.x / l, vdir.y / l + 1.0f, l + 1.0f);
  509. F r = sqrt_tpl(hv.x * hv.x + hv.y * hv.y);
  510. F s = sqrt_tpl(hv.z * hv.z + vdir.z * vdir.z);
  511. //generate the half-angle sine&cosine
  512. F hacos0 = 0.0;
  513. F hasin0 = -1.0;
  514. if (r > F(0.00001))
  515. {
  516. hacos0 = hv.y / r;
  517. hasin0 = -hv.x / r;
  518. } //yaw
  519. F hacos1 = hv.z / s;
  520. F hasin1 = vdir.z / s; //pitch
  521. w = F(hacos0 * hacos1);
  522. v.x = F(hacos0 * hasin1);
  523. v.y = F(hasin0 * hasin1);
  524. v.z = F(hasin0 * hacos1);
  525. }
  526. }
  527. ILINE static Quat_tpl<F> CreateRotationVDir(const Vec3_tpl<F>& vdir) { Quat_tpl<F> q; q.SetRotationVDir(vdir); return q; }
  528. ILINE void SetRotationVDir(const Vec3_tpl<F>& vdir, F r)
  529. {
  530. SetRotationVDir(vdir);
  531. F sy, cy;
  532. sincos_tpl(r * (F)0.5, &sy, &cy);
  533. F vx = v.x, vy = v.y;
  534. v.x = F(vx * cy - v.z * sy);
  535. v.y = F(w * sy + vy * cy);
  536. v.z = F(v.z * cy + vx * sy);
  537. w = F(w * cy - vy * sy);
  538. }
  539. ILINE static Quat_tpl<F> CreateRotationVDir(const Vec3_tpl<F>& vdir, F roll) { Quat_tpl<F> q; q.SetRotationVDir(vdir, roll); return q; }
  540. /*!
  541. * normalize quaternion.
  542. *
  543. * Example 1:
  544. * Quat q; q.Normalize();
  545. *
  546. * Example 2:
  547. * Quat q=Quat(1,2,3,4);
  548. * Quat qn=q.GetNormalized();
  549. */
  550. ILINE void Normalize(void)
  551. {
  552. F d = isqrt_tpl(w * w + v.x * v.x + v.y * v.y + v.z * v.z);
  553. w *= d;
  554. v.x *= d;
  555. v.y *= d;
  556. v.z *= d;
  557. }
  558. ILINE Quat_tpl<F> GetNormalized() const
  559. {
  560. Quat_tpl<F> t = *this;
  561. t.Normalize();
  562. return t;
  563. }
  564. ILINE void NormalizeSafe(void)
  565. {
  566. F d = w * w + v.x * v.x + v.y * v.y + v.z * v.z;
  567. if (d > 1e-8f)
  568. {
  569. d = isqrt_tpl(d);
  570. w *= d;
  571. v.x *= d;
  572. v.y *= d;
  573. v.z *= d;
  574. }
  575. else
  576. {
  577. SetIdentity();
  578. }
  579. }
  580. ILINE Quat_tpl<F> GetNormalizedSafe() const
  581. {
  582. Quat_tpl<F> t = *this;
  583. t.NormalizeSafe();
  584. return t;
  585. }
  586. ILINE void NormalizeFast(void)
  587. {
  588. assert(this->IsValid());
  589. F fInvLen = isqrt_fast_tpl(v.x * v.x + v.y * v.y + v.z * v.z + w * w);
  590. v.x *= fInvLen;
  591. v.y *= fInvLen;
  592. v.z *= fInvLen;
  593. w *= fInvLen;
  594. }
  595. ILINE Quat_tpl<F> GetNormalizedFast() const
  596. {
  597. Quat_tpl<F> t = *this;
  598. t.NormalizeFast();
  599. return t;
  600. }
  601. /*!
  602. * get length of quaternion.
  603. *
  604. * Example 1:
  605. * f32 l=q.GetLength();
  606. */
  607. ILINE F GetLength() const
  608. {
  609. return sqrt_tpl(w * w + v.x * v.x + v.y * v.y + v.z * v.z);
  610. }
  611. ILINE static bool IsEquivalent(const Quat_tpl<F>& q1, const Quat_tpl<F>& q2, F qe = RAD_EPSILON)
  612. {
  613. Quat_tpl<f64> q1r = q1;
  614. Quat_tpl<f64> q2r = q2;
  615. f64 rad = acos(min(1.0, fabs_tpl(q1r.v.x * q2r.v.x + q1r.v.y * q2r.v.y + q1r.v.z * q2r.v.z + q1r.w * q2r.w)));
  616. bool qdif = rad <= qe;
  617. return qdif;
  618. }
  619. // Exponent of Quaternion.
  620. ILINE static Quat_tpl<F> exp(const Vec3_tpl<F>& v)
  621. {
  622. F lensqr = v.len2();
  623. if (lensqr > F(0))
  624. {
  625. F len = sqrt_tpl(lensqr);
  626. F s, c;
  627. sincos_tpl(len, &s, &c);
  628. s /= len;
  629. return Quat_tpl<F>(c, v.x * s, v.y * s, v.z * s);
  630. }
  631. return Quat_tpl<F> (IDENTITY);
  632. }
  633. // logarithm of a quaternion, imaginary part (the real part of the logarithm is always 0)
  634. ILINE static Vec3_tpl<F> log (const Quat_tpl<F>& q)
  635. {
  636. assert(q.IsValid());
  637. F lensqr = q.v.len2();
  638. if (lensqr > 0.0f)
  639. {
  640. F len = sqrt_tpl(lensqr);
  641. F angle = atan2_tpl(len, q.w) / len;
  642. return q.v * angle;
  643. }
  644. // logarithm of a quaternion, imaginary part (the real part of the logarithm is always 0)
  645. return Vec3_tpl<F>(0, 0, 0);
  646. }
  647. //////////////////////////////////////////////////////////////////////////
  648. //! Logarithm of Quaternion difference.
  649. ILINE static Quat_tpl<F> LnDif(const Quat_tpl<F>& q1, const Quat_tpl<F>& q2)
  650. {
  651. return Quat_tpl<F>(0, log(q2 / q1));
  652. }
  653. /*!
  654. * linear-interpolation between quaternions (lerp)
  655. *
  656. * Example:
  657. * CQuaternion result,p,q;
  658. * result=qlerp( p, q, 0.5f );
  659. */
  660. ILINE void SetNlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
  661. {
  662. Quat_tpl<F> q = tq;
  663. assert(p.IsValid());
  664. assert(q.IsValid());
  665. if ((p | q) < 0)
  666. {
  667. q = -q;
  668. }
  669. v.x = p.v.x * (1.0f - t) + q.v.x * t;
  670. v.y = p.v.y * (1.0f - t) + q.v.y * t;
  671. v.z = p.v.z * (1.0f - t) + q.v.z * t;
  672. w = p.w * (1.0f - t) + q.w * t;
  673. Normalize();
  674. }
  675. ILINE static Quat_tpl<F> CreateNlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
  676. {
  677. Quat_tpl<F> d;
  678. d.SetNlerp(p, tq, t);
  679. return d;
  680. }
  681. /*!
  682. * spherical-interpolation between quaternions (geometrical slerp)
  683. *
  684. * Example:
  685. * Quat result,p,q;
  686. * result.SetSlerp( p, q, 0.5f );
  687. */
  688. ILINE void SetSlerp(const Quat_tpl<F>& tp, const Quat_tpl<F>& tq, F t)
  689. {
  690. assert(tp.IsValid());
  691. assert(tq.IsUnit());
  692. Quat_tpl<F> p = tp, q = tq;
  693. Quat_tpl<F> q2;
  694. F cosine = (p | q);
  695. if (cosine < 0.0f)
  696. {
  697. cosine = -cosine;
  698. q = -q;
  699. } //take shortest arc
  700. if (cosine > 0.9999f)
  701. {
  702. SetNlerp(p, q, t);
  703. return;
  704. }
  705. // from now on, a division by 0 is not possible any more
  706. q2.w = q.w - p.w * cosine;
  707. q2.v.x = q.v.x - p.v.x * cosine;
  708. q2.v.y = q.v.y - p.v.y * cosine;
  709. q2.v.z = q.v.z - p.v.z * cosine;
  710. F sine = sqrt(q2 | q2);
  711. // Actually you can divide by 0 right here.
  712. assert(sine != 0.0000f);
  713. F s, c;
  714. sincos_tpl(atan2_tpl(sine, cosine) * t, &s, &c);
  715. w = F(p.w * c + q2.w * s / sine);
  716. v.x = F(p.v.x * c + q2.v.x * s / sine);
  717. v.y = F(p.v.y * c + q2.v.y * s / sine);
  718. v.z = F(p.v.z * c + q2.v.z * s / sine);
  719. }
  720. ILINE static Quat_tpl<F> CreateSlerp(const Quat_tpl<F>& p, const Quat_tpl<F>& tq, F t)
  721. {
  722. Quat_tpl<F> d;
  723. d.SetSlerp(p, tq, t);
  724. return d;
  725. }
  726. //! squad(p,a,b,q,t) = slerp( slerp(p,q,t),slerp(a,b,t), 2(1-t)t).
  727. ILINE void SetSquad(const Quat_tpl<F>& p, const Quat_tpl<F>& a, const Quat_tpl<F>& b, const Quat_tpl<F>& q, F t)
  728. {
  729. SetSlerp(CreateSlerp(p, q, t), CreateSlerp(a, b, t), 2.0f * (1.0f - t) * t);
  730. }
  731. ILINE static Quat_tpl<F> CreateSquad(const Quat_tpl<F>& p, const Quat_tpl<F>& a, const Quat_tpl<F>& b, const Quat_tpl<F>& q, F t)
  732. {
  733. Quat_tpl<F> d;
  734. d.SetSquad(p, a, b, q, t);
  735. return d;
  736. }
  737. //useless, please delete
  738. ILINE Quat_tpl<F> GetScaled(F scale) const
  739. {
  740. return CreateNlerp(IDENTITY, *this, scale);
  741. }
  742. };
  743. ///////////////////////////////////////////////////////////////////////////////
  744. // Typedefs //
  745. ///////////////////////////////////////////////////////////////////////////////
  746. typedef Quat_tpl<f32> Quat; //always 32 bit
  747. /*!
  748. *
  749. * The "inner product" or "dot product" operation.
  750. *
  751. * calculate the "inner product" between two Quaternion.
  752. * If both Quaternion are unit-quaternions, the result is the cosine: p*q=cos(angle)
  753. *
  754. * Example:
  755. * Quat p(1,0,0,0),q(1,0,0,0);
  756. * f32 cosine = ( p | q );
  757. *
  758. */
  759. template<typename F1, typename F2>
  760. ILINE F1 operator | (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  761. {
  762. assert(q.v.IsValid());
  763. assert(p.v.IsValid());
  764. return (q.v.x * p.v.x + q.v.y * p.v.y + q.v.z * p.v.z + q.w * p.w);
  765. }
  766. /*!
  767. *
  768. * Implements the multiplication operator: Qua=QuatA*QuatB
  769. *
  770. * AxB = operation B followed by operation A.
  771. * A multiplication takes 16 muls and 12 adds.
  772. *
  773. * Example 1:
  774. * Quat p(1,0,0,0),q(1,0,0,0);
  775. * Quat result=p*q;
  776. *
  777. * Example 2: (self-multiplication)
  778. * Quat p(1,0,0,0),q(1,0,0,0);
  779. * Quat p*=q;
  780. */
  781. template<class F1, class F2>
  782. Quat_tpl<F1> ILINE operator * (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  783. {
  784. assert(q.IsValid());
  785. assert(p.IsValid());
  786. return Quat_tpl<F1>
  787. (
  788. q.w * p.w - (q.v.x * p.v.x + q.v.y * p.v.y + q.v.z * p.v.z),
  789. q.v.y * p.v.z - q.v.z * p.v.y + q.w * p.v.x + q.v.x * p.w,
  790. q.v.z * p.v.x - q.v.x * p.v.z + q.w * p.v.y + q.v.y * p.w,
  791. q.v.x * p.v.y - q.v.y * p.v.x + q.w * p.v.z + q.v.z * p.w
  792. );
  793. }
  794. template<class F1, class F2>
  795. ILINE void operator *= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  796. {
  797. assert(q.IsValid());
  798. assert(p.IsValid());
  799. F1 s0 = q.w;
  800. q.w = q.w * p.w - (q.v | p.v);
  801. q.v = p.v * s0 + q.v * p.w + (q.v % p.v);
  802. }
  803. /*!
  804. * division operator
  805. *
  806. * Example 1:
  807. * Quat p(1,0,0,0),q(1,0,0,0);
  808. * Quat result=p/q;
  809. *
  810. * Example 2: (self-division)
  811. * Quat p(1,0,0,0),q(1,0,0,0);
  812. * Quat p/=q;
  813. */
  814. template<class F1, class F2>
  815. ILINE Quat_tpl<F1> operator / (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  816. {
  817. return (!p * q);
  818. }
  819. template<class F1, class F2>
  820. ILINE void operator /= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  821. {
  822. q = (!p * q);
  823. }
  824. /*!
  825. * addition operator
  826. *
  827. * Example:
  828. * Quat p(1,0,0,0),q(1,0,0,0);
  829. * Quat result=p+q;
  830. *
  831. * Example:(self-addition operator)
  832. * Quat p(1,0,0,0),q(1,0,0,0);
  833. * Quat p-=q;
  834. */
  835. template<class F1, class F2>
  836. ILINE Quat_tpl<F1> operator + (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  837. {
  838. return Quat_tpl<F1>(q.w + p.w, q.v + p.v);
  839. }
  840. template<class F1, class F2>
  841. ILINE void operator += (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  842. {
  843. q.w += p.w;
  844. q.v += p.v;
  845. }
  846. /*!
  847. * subtraction operator
  848. *
  849. * Example:
  850. * Quat p(1,0,0,0),q(1,0,0,0);
  851. * Quat result=p-q;
  852. *
  853. * Example: (self-subtraction operator)
  854. * Quat p(1,0,0,0),q(1,0,0,0);
  855. * Quat p-=q;
  856. *
  857. */
  858. template<class F1, class F2>
  859. ILINE Quat_tpl<F1> operator - (const Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  860. {
  861. return Quat_tpl<F1>(q.w - p.w, q.v - p.v);
  862. }
  863. template<class F1, class F2>
  864. ILINE void operator -= (Quat_tpl<F1>& q, const Quat_tpl<F2>& p)
  865. {
  866. q.w -= p.w;
  867. q.v -= p.v;
  868. }
  869. //! Scale quaternion free function.
  870. template <typename F>
  871. ILINE Quat_tpl<F> operator * (F t, const Quat_tpl<F>& q)
  872. {
  873. return Quat_tpl<F>(t * q.w, t * q.v);
  874. };
  875. template <typename F1, typename F2>
  876. ILINE Quat_tpl<F1> operator * (const Quat_tpl<F1>& q, F2 t)
  877. {
  878. return Quat_tpl<F1>(q.w * t, q.v * t);
  879. };
  880. template <typename F1, typename F2>
  881. ILINE Quat_tpl<F1> operator / (const Quat_tpl<F1>& q, F2 t)
  882. {
  883. return Quat_tpl<F1>(q.w / t, q.v / t);
  884. };
  885. /*!
  886. *
  887. * post-multiply of a quaternion and a Vec3 (3D rotations with quaternions)
  888. *
  889. * Example:
  890. * Quat q(1,0,0,0);
  891. * Vec3 v(33,44,55);
  892. * Vec3 result = q*v;
  893. */
  894. template<class F, class F2>
  895. ILINE Vec3_tpl<F> operator * (const Quat_tpl<F>& q, const Vec3_tpl<F2>& v)
  896. {
  897. assert(v.IsValid());
  898. assert(q.IsValid());
  899. //muls=15 / adds=15
  900. Vec3_tpl<F> out, r2;
  901. r2.x = (q.v.y * v.z - q.v.z * v.y) + q.w * v.x;
  902. r2.y = (q.v.z * v.x - q.v.x * v.z) + q.w * v.y;
  903. r2.z = (q.v.x * v.y - q.v.y * v.x) + q.w * v.z;
  904. out.x = (r2.z * q.v.y - r2.y * q.v.z);
  905. out.x += out.x + v.x;
  906. out.y = (r2.x * q.v.z - r2.z * q.v.x);
  907. out.y += out.y + v.y;
  908. out.z = (r2.y * q.v.x - r2.x * q.v.y);
  909. out.z += out.z + v.z;
  910. return out;
  911. }
  912. /*!
  913. * pre-multiply of a quaternion and a Vec3 (3D rotations with quaternions)
  914. *
  915. * Example:
  916. * Quat q(1,0,0,0);
  917. * Vec3 v(33,44,55);
  918. * Vec3 result = v*q;
  919. */
  920. template<class F, class F2>
  921. ILINE Vec3_tpl<F2> operator * (const Vec3_tpl<F>& v, const Quat_tpl<F2>& q)
  922. {
  923. assert(v.IsValid());
  924. assert(q.IsValid());
  925. //muls=15 / adds=15
  926. Vec3_tpl<F> out, r2;
  927. r2.x = (q.v.z * v.y - q.v.y * v.z) + q.w * v.x;
  928. r2.y = (q.v.x * v.z - q.v.z * v.x) + q.w * v.y;
  929. r2.z = (q.v.y * v.x - q.v.x * v.y) + q.w * v.z;
  930. out.x = (r2.y * q.v.z - r2.z * q.v.y);
  931. out.x += out.x + v.x;
  932. out.y = (r2.z * q.v.x - r2.x * q.v.z);
  933. out.y += out.y + v.y;
  934. out.z = (r2.x * q.v.y - r2.y * q.v.x);
  935. out.z += out.z + v.z;
  936. return out;
  937. }
  938. template<class F1, class F2>
  939. ILINE Quat_tpl<F1> operator % (const Quat_tpl<F1>& q, const Quat_tpl<F2>& tp)
  940. {
  941. Quat_tpl<F1> p = tp;
  942. if ((p | q) < 0)
  943. {
  944. p = -p;
  945. }
  946. return Quat_tpl<F1>(q.w + p.w, q.v + p.v);
  947. }
  948. template<class F1, class F2>
  949. ILINE void operator %= (Quat_tpl<F1>& q, const Quat_tpl<F2>& tp)
  950. {
  951. Quat_tpl<F1> p = tp;
  952. if ((p | q) < 0)
  953. {
  954. p = -p;
  955. }
  956. q = Quat_tpl<F1>(q.w + p.w, q.v + p.v);
  957. }