quaternion.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. // Copyright (C) 2002-2012 Nikolaus Gebhardt
  2. // This file is part of the "Irrlicht Engine".
  3. // For conditions of distribution and use, see copyright notice in irrlicht.h
  4. #pragma once
  5. #include "irrTypes.h"
  6. #include "irrMath.h"
  7. #include "matrix4.h"
  8. #include "vector3d.h"
  9. // NOTE: You *only* need this when updating an application from Irrlicht before 1.8 to Irrlicht 1.8 or later.
  10. // Between Irrlicht 1.7 and Irrlicht 1.8 the quaternion-matrix conversions changed.
  11. // Before the fix they had mixed left- and right-handed rotations.
  12. // To test if your code was affected by the change enable IRR_TEST_BROKEN_QUATERNION_USE and try to compile your application.
  13. // This defines removes those functions so you get compile errors anywhere you use them in your code.
  14. // For every line with a compile-errors you have to change the corresponding lines like that:
  15. // - When you pass the matrix to the quaternion constructor then replace the matrix by the transposed matrix.
  16. // - For uses of getMatrix() you have to use quaternion::getMatrix_transposed instead.
  17. // #define IRR_TEST_BROKEN_QUATERNION_USE
  18. namespace irr
  19. {
  20. namespace core
  21. {
  22. //! Quaternion class for representing rotations.
  23. /** It provides cheap combinations and avoids gimbal locks.
  24. Also useful for interpolations. */
  25. class quaternion
  26. {
  27. public:
  28. //! Default Constructor
  29. constexpr quaternion() :
  30. X(0.0f), Y(0.0f), Z(0.0f), W(1.0f) {}
  31. //! Constructor
  32. constexpr quaternion(f32 x, f32 y, f32 z, f32 w) :
  33. X(x), Y(y), Z(z), W(w) {}
  34. //! Constructor which converts Euler angles (radians) to a quaternion
  35. quaternion(f32 x, f32 y, f32 z);
  36. //! Constructor which converts Euler angles (radians) to a quaternion
  37. quaternion(const vector3df &vec);
  38. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  39. //! Constructor which converts a matrix to a quaternion
  40. quaternion(const matrix4 &mat);
  41. #endif
  42. //! Equality operator
  43. constexpr bool operator==(const quaternion &other) const
  44. {
  45. return ((X == other.X) &&
  46. (Y == other.Y) &&
  47. (Z == other.Z) &&
  48. (W == other.W));
  49. }
  50. //! inequality operator
  51. constexpr bool operator!=(const quaternion &other) const
  52. {
  53. return !(*this == other);
  54. }
  55. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  56. //! Matrix assignment operator
  57. inline quaternion &operator=(const matrix4 &other);
  58. #endif
  59. //! Add operator
  60. quaternion operator+(const quaternion &other) const;
  61. //! Multiplication operator
  62. //! Be careful, unfortunately the operator order here is opposite of that in CMatrix4::operator*
  63. quaternion operator*(const quaternion &other) const;
  64. //! Multiplication operator with scalar
  65. quaternion operator*(f32 s) const;
  66. //! Multiplication operator with scalar
  67. quaternion &operator*=(f32 s);
  68. //! Multiplication operator
  69. vector3df operator*(const vector3df &v) const;
  70. //! Multiplication operator
  71. quaternion &operator*=(const quaternion &other);
  72. //! Calculates the dot product
  73. inline f32 dotProduct(const quaternion &other) const;
  74. //! Sets new quaternion
  75. inline quaternion &set(f32 x, f32 y, f32 z, f32 w);
  76. //! Sets new quaternion based on Euler angles (radians)
  77. inline quaternion &set(f32 x, f32 y, f32 z);
  78. //! Sets new quaternion based on Euler angles (radians)
  79. inline quaternion &set(const core::vector3df &vec);
  80. //! Sets new quaternion from other quaternion
  81. inline quaternion &set(const core::quaternion &quat);
  82. //! returns if this quaternion equals the other one, taking floating point rounding errors into account
  83. inline bool equals(const quaternion &other,
  84. const f32 tolerance = ROUNDING_ERROR_f32) const;
  85. //! Normalizes the quaternion
  86. inline quaternion &normalize();
  87. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  88. //! Creates a matrix from this quaternion
  89. matrix4 getMatrix() const;
  90. #endif
  91. //! Faster method to create a rotation matrix, you should normalize the quaternion before!
  92. void getMatrixFast(matrix4 &dest) const;
  93. //! Creates a matrix from this quaternion
  94. void getMatrix(matrix4 &dest, const core::vector3df &translation = core::vector3df()) const;
  95. /*!
  96. Creates a matrix from this quaternion
  97. Rotate about a center point
  98. shortcut for
  99. core::quaternion q;
  100. q.rotationFromTo ( vin[i].Normal, forward );
  101. q.getMatrixCenter ( lookat, center, newPos );
  102. core::matrix4 m2;
  103. m2.setInverseTranslation ( center );
  104. lookat *= m2;
  105. core::matrix4 m3;
  106. m2.setTranslation ( newPos );
  107. lookat *= m3;
  108. */
  109. void getMatrixCenter(matrix4 &dest, const core::vector3df &center, const core::vector3df &translation) const;
  110. //! Creates a matrix from this quaternion
  111. inline void getMatrix_transposed(matrix4 &dest) const;
  112. //! Inverts this quaternion
  113. quaternion &makeInverse();
  114. //! Set this quaternion to the linear interpolation between two quaternions
  115. /** NOTE: lerp result is *not* a normalized quaternion. In most cases
  116. you will want to use lerpN instead as most other quaternion functions expect
  117. to work with a normalized quaternion.
  118. \param q1 First quaternion to be interpolated.
  119. \param q2 Second quaternion to be interpolated.
  120. \param time Progress of interpolation. For time=0 the result is
  121. q1, for time=1 the result is q2. Otherwise interpolation
  122. between q1 and q2. Result is not normalized.
  123. */
  124. quaternion &lerp(quaternion q1, quaternion q2, f32 time);
  125. //! Set this quaternion to the linear interpolation between two quaternions and normalize the result
  126. /**
  127. \param q1 First quaternion to be interpolated.
  128. \param q2 Second quaternion to be interpolated.
  129. \param time Progress of interpolation. For time=0 the result is
  130. q1, for time=1 the result is q2. Otherwise interpolation
  131. between q1 and q2. Result is normalized.
  132. */
  133. quaternion &lerpN(quaternion q1, quaternion q2, f32 time);
  134. //! Set this quaternion to the result of the spherical interpolation between two quaternions
  135. /** \param q1 First quaternion to be interpolated.
  136. \param q2 Second quaternion to be interpolated.
  137. \param time Progress of interpolation. For time=0 the result is
  138. q1, for time=1 the result is q2. Otherwise interpolation
  139. between q1 and q2.
  140. \param threshold To avoid inaccuracies at the end (time=1) the
  141. interpolation switches to linear interpolation at some point.
  142. This value defines how much of the remaining interpolation will
  143. be calculated with lerp. Everything from 1-threshold up will be
  144. linear interpolation.
  145. */
  146. quaternion &slerp(quaternion q1, quaternion q2,
  147. f32 time, f32 threshold = .05f);
  148. //! Set this quaternion to represent a rotation from angle and axis.
  149. /** Axis must be unit length.
  150. The quaternion representing the rotation is
  151. q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k).
  152. \param angle Rotation Angle in radians.
  153. \param axis Rotation axis. */
  154. quaternion &fromAngleAxis(f32 angle, const vector3df &axis);
  155. //! Fills an angle (radians) around an axis (unit vector)
  156. void toAngleAxis(f32 &angle, core::vector3df &axis) const;
  157. //! Output this quaternion to an Euler angle (radians)
  158. void toEuler(vector3df &euler) const;
  159. //! Set quaternion to identity
  160. quaternion &makeIdentity();
  161. //! Set quaternion to represent a rotation from one vector to another.
  162. quaternion &rotationFromTo(const vector3df &from, const vector3df &to);
  163. //! Quaternion elements.
  164. f32 X; // vectorial (imaginary) part
  165. f32 Y;
  166. f32 Z;
  167. f32 W; // real part
  168. };
  169. // Constructor which converts Euler angles to a quaternion
  170. inline quaternion::quaternion(f32 x, f32 y, f32 z)
  171. {
  172. set(x, y, z);
  173. }
  174. // Constructor which converts Euler angles to a quaternion
  175. inline quaternion::quaternion(const vector3df &vec)
  176. {
  177. set(vec.X, vec.Y, vec.Z);
  178. }
  179. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  180. // Constructor which converts a matrix to a quaternion
  181. inline quaternion::quaternion(const matrix4 &mat)
  182. {
  183. (*this) = mat;
  184. }
  185. #endif
  186. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  187. // matrix assignment operator
  188. inline quaternion &quaternion::operator=(const matrix4 &m)
  189. {
  190. const f32 diag = m[0] + m[5] + m[10] + 1;
  191. if (diag > 0.0f) {
  192. const f32 scale = sqrtf(diag) * 2.0f; // get scale from diagonal
  193. // TODO: speed this up
  194. X = (m[6] - m[9]) / scale;
  195. Y = (m[8] - m[2]) / scale;
  196. Z = (m[1] - m[4]) / scale;
  197. W = 0.25f * scale;
  198. } else {
  199. if (m[0] > m[5] && m[0] > m[10]) {
  200. // 1st element of diag is greatest value
  201. // find scale according to 1st element, and double it
  202. const f32 scale = sqrtf(1.0f + m[0] - m[5] - m[10]) * 2.0f;
  203. // TODO: speed this up
  204. X = 0.25f * scale;
  205. Y = (m[4] + m[1]) / scale;
  206. Z = (m[2] + m[8]) / scale;
  207. W = (m[6] - m[9]) / scale;
  208. } else if (m[5] > m[10]) {
  209. // 2nd element of diag is greatest value
  210. // find scale according to 2nd element, and double it
  211. const f32 scale = sqrtf(1.0f + m[5] - m[0] - m[10]) * 2.0f;
  212. // TODO: speed this up
  213. X = (m[4] + m[1]) / scale;
  214. Y = 0.25f * scale;
  215. Z = (m[9] + m[6]) / scale;
  216. W = (m[8] - m[2]) / scale;
  217. } else {
  218. // 3rd element of diag is greatest value
  219. // find scale according to 3rd element, and double it
  220. const f32 scale = sqrtf(1.0f + m[10] - m[0] - m[5]) * 2.0f;
  221. // TODO: speed this up
  222. X = (m[8] + m[2]) / scale;
  223. Y = (m[9] + m[6]) / scale;
  224. Z = 0.25f * scale;
  225. W = (m[1] - m[4]) / scale;
  226. }
  227. }
  228. normalize();
  229. return *this;
  230. }
  231. #endif
  232. // multiplication operator
  233. inline quaternion quaternion::operator*(const quaternion &other) const
  234. {
  235. quaternion tmp;
  236. tmp.W = (other.W * W) - (other.X * X) - (other.Y * Y) - (other.Z * Z);
  237. tmp.X = (other.W * X) + (other.X * W) + (other.Y * Z) - (other.Z * Y);
  238. tmp.Y = (other.W * Y) + (other.Y * W) + (other.Z * X) - (other.X * Z);
  239. tmp.Z = (other.W * Z) + (other.Z * W) + (other.X * Y) - (other.Y * X);
  240. return tmp;
  241. }
  242. // multiplication operator
  243. inline quaternion quaternion::operator*(f32 s) const
  244. {
  245. return quaternion(s * X, s * Y, s * Z, s * W);
  246. }
  247. // multiplication operator
  248. inline quaternion &quaternion::operator*=(f32 s)
  249. {
  250. X *= s;
  251. Y *= s;
  252. Z *= s;
  253. W *= s;
  254. return *this;
  255. }
  256. // multiplication operator
  257. inline quaternion &quaternion::operator*=(const quaternion &other)
  258. {
  259. return (*this = other * (*this));
  260. }
  261. // add operator
  262. inline quaternion quaternion::operator+(const quaternion &b) const
  263. {
  264. return quaternion(X + b.X, Y + b.Y, Z + b.Z, W + b.W);
  265. }
  266. #ifndef IRR_TEST_BROKEN_QUATERNION_USE
  267. // Creates a matrix from this quaternion
  268. inline matrix4 quaternion::getMatrix() const
  269. {
  270. core::matrix4 m;
  271. getMatrix(m);
  272. return m;
  273. }
  274. #endif
  275. //! Faster method to create a rotation matrix, you should normalize the quaternion before!
  276. inline void quaternion::getMatrixFast(matrix4 &dest) const
  277. {
  278. // TODO:
  279. // gpu quaternion skinning => fast Bones transform chain O_O YEAH!
  280. // http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
  281. dest[0] = 1.0f - 2.0f * Y * Y - 2.0f * Z * Z;
  282. dest[1] = 2.0f * X * Y + 2.0f * Z * W;
  283. dest[2] = 2.0f * X * Z - 2.0f * Y * W;
  284. dest[3] = 0.0f;
  285. dest[4] = 2.0f * X * Y - 2.0f * Z * W;
  286. dest[5] = 1.0f - 2.0f * X * X - 2.0f * Z * Z;
  287. dest[6] = 2.0f * Z * Y + 2.0f * X * W;
  288. dest[7] = 0.0f;
  289. dest[8] = 2.0f * X * Z + 2.0f * Y * W;
  290. dest[9] = 2.0f * Z * Y - 2.0f * X * W;
  291. dest[10] = 1.0f - 2.0f * X * X - 2.0f * Y * Y;
  292. dest[11] = 0.0f;
  293. dest[12] = 0.f;
  294. dest[13] = 0.f;
  295. dest[14] = 0.f;
  296. dest[15] = 1.f;
  297. dest.setDefinitelyIdentityMatrix(false);
  298. }
  299. /*!
  300. Creates a matrix from this quaternion
  301. */
  302. inline void quaternion::getMatrix(matrix4 &dest,
  303. const core::vector3df &center) const
  304. {
  305. // ok creating a copy may be slower, but at least avoid internal
  306. // state chance (also because otherwise we cannot keep this method "const").
  307. quaternion q(*this);
  308. q.normalize();
  309. f32 X = q.X;
  310. f32 Y = q.Y;
  311. f32 Z = q.Z;
  312. f32 W = q.W;
  313. dest[0] = 1.0f - 2.0f * Y * Y - 2.0f * Z * Z;
  314. dest[1] = 2.0f * X * Y + 2.0f * Z * W;
  315. dest[2] = 2.0f * X * Z - 2.0f * Y * W;
  316. dest[3] = 0.0f;
  317. dest[4] = 2.0f * X * Y - 2.0f * Z * W;
  318. dest[5] = 1.0f - 2.0f * X * X - 2.0f * Z * Z;
  319. dest[6] = 2.0f * Z * Y + 2.0f * X * W;
  320. dest[7] = 0.0f;
  321. dest[8] = 2.0f * X * Z + 2.0f * Y * W;
  322. dest[9] = 2.0f * Z * Y - 2.0f * X * W;
  323. dest[10] = 1.0f - 2.0f * X * X - 2.0f * Y * Y;
  324. dest[11] = 0.0f;
  325. dest[12] = center.X;
  326. dest[13] = center.Y;
  327. dest[14] = center.Z;
  328. dest[15] = 1.f;
  329. dest.setDefinitelyIdentityMatrix(false);
  330. }
  331. /*!
  332. Creates a matrix from this quaternion
  333. Rotate about a center point
  334. shortcut for
  335. core::quaternion q;
  336. q.rotationFromTo(vin[i].Normal, forward);
  337. q.getMatrix(lookat, center);
  338. core::matrix4 m2;
  339. m2.setInverseTranslation(center);
  340. lookat *= m2;
  341. */
  342. inline void quaternion::getMatrixCenter(matrix4 &dest,
  343. const core::vector3df &center,
  344. const core::vector3df &translation) const
  345. {
  346. quaternion q(*this);
  347. q.normalize();
  348. f32 X = q.X;
  349. f32 Y = q.Y;
  350. f32 Z = q.Z;
  351. f32 W = q.W;
  352. dest[0] = 1.0f - 2.0f * Y * Y - 2.0f * Z * Z;
  353. dest[1] = 2.0f * X * Y + 2.0f * Z * W;
  354. dest[2] = 2.0f * X * Z - 2.0f * Y * W;
  355. dest[3] = 0.0f;
  356. dest[4] = 2.0f * X * Y - 2.0f * Z * W;
  357. dest[5] = 1.0f - 2.0f * X * X - 2.0f * Z * Z;
  358. dest[6] = 2.0f * Z * Y + 2.0f * X * W;
  359. dest[7] = 0.0f;
  360. dest[8] = 2.0f * X * Z + 2.0f * Y * W;
  361. dest[9] = 2.0f * Z * Y - 2.0f * X * W;
  362. dest[10] = 1.0f - 2.0f * X * X - 2.0f * Y * Y;
  363. dest[11] = 0.0f;
  364. dest.setRotationCenter(center, translation);
  365. }
  366. // Creates a matrix from this quaternion
  367. inline void quaternion::getMatrix_transposed(matrix4 &dest) const
  368. {
  369. quaternion q(*this);
  370. q.normalize();
  371. f32 X = q.X;
  372. f32 Y = q.Y;
  373. f32 Z = q.Z;
  374. f32 W = q.W;
  375. dest[0] = 1.0f - 2.0f * Y * Y - 2.0f * Z * Z;
  376. dest[4] = 2.0f * X * Y + 2.0f * Z * W;
  377. dest[8] = 2.0f * X * Z - 2.0f * Y * W;
  378. dest[12] = 0.0f;
  379. dest[1] = 2.0f * X * Y - 2.0f * Z * W;
  380. dest[5] = 1.0f - 2.0f * X * X - 2.0f * Z * Z;
  381. dest[9] = 2.0f * Z * Y + 2.0f * X * W;
  382. dest[13] = 0.0f;
  383. dest[2] = 2.0f * X * Z + 2.0f * Y * W;
  384. dest[6] = 2.0f * Z * Y - 2.0f * X * W;
  385. dest[10] = 1.0f - 2.0f * X * X - 2.0f * Y * Y;
  386. dest[14] = 0.0f;
  387. dest[3] = 0.f;
  388. dest[7] = 0.f;
  389. dest[11] = 0.f;
  390. dest[15] = 1.f;
  391. dest.setDefinitelyIdentityMatrix(false);
  392. }
  393. // Inverts this quaternion
  394. inline quaternion &quaternion::makeInverse()
  395. {
  396. X = -X;
  397. Y = -Y;
  398. Z = -Z;
  399. return *this;
  400. }
  401. // sets new quaternion
  402. inline quaternion &quaternion::set(f32 x, f32 y, f32 z, f32 w)
  403. {
  404. X = x;
  405. Y = y;
  406. Z = z;
  407. W = w;
  408. return *this;
  409. }
  410. // sets new quaternion based on Euler angles
  411. inline quaternion &quaternion::set(f32 x, f32 y, f32 z)
  412. {
  413. f64 angle;
  414. angle = x * 0.5;
  415. const f64 sr = sin(angle);
  416. const f64 cr = cos(angle);
  417. angle = y * 0.5;
  418. const f64 sp = sin(angle);
  419. const f64 cp = cos(angle);
  420. angle = z * 0.5;
  421. const f64 sy = sin(angle);
  422. const f64 cy = cos(angle);
  423. const f64 cpcy = cp * cy;
  424. const f64 spcy = sp * cy;
  425. const f64 cpsy = cp * sy;
  426. const f64 spsy = sp * sy;
  427. X = (f32)(sr * cpcy - cr * spsy);
  428. Y = (f32)(cr * spcy + sr * cpsy);
  429. Z = (f32)(cr * cpsy - sr * spcy);
  430. W = (f32)(cr * cpcy + sr * spsy);
  431. return normalize();
  432. }
  433. // sets new quaternion based on Euler angles
  434. inline quaternion &quaternion::set(const core::vector3df &vec)
  435. {
  436. return set(vec.X, vec.Y, vec.Z);
  437. }
  438. // sets new quaternion based on other quaternion
  439. inline quaternion &quaternion::set(const core::quaternion &quat)
  440. {
  441. return (*this = quat);
  442. }
  443. //! returns if this quaternion equals the other one, taking floating point rounding errors into account
  444. inline bool quaternion::equals(const quaternion &other, const f32 tolerance) const
  445. {
  446. return core::equals(X, other.X, tolerance) &&
  447. core::equals(Y, other.Y, tolerance) &&
  448. core::equals(Z, other.Z, tolerance) &&
  449. core::equals(W, other.W, tolerance);
  450. }
  451. // normalizes the quaternion
  452. inline quaternion &quaternion::normalize()
  453. {
  454. // removed conditional branch since it may slow down and anyway the condition was
  455. // false even after normalization in some cases.
  456. return (*this *= (f32)reciprocal_squareroot((f64)(X * X + Y * Y + Z * Z + W * W)));
  457. }
  458. // Set this quaternion to the result of the linear interpolation between two quaternions
  459. inline quaternion &quaternion::lerp(quaternion q1, quaternion q2, f32 time)
  460. {
  461. const f32 scale = 1.0f - time;
  462. return (*this = (q1 * scale) + (q2 * time));
  463. }
  464. // Set this quaternion to the result of the linear interpolation between two quaternions and normalize the result
  465. inline quaternion &quaternion::lerpN(quaternion q1, quaternion q2, f32 time)
  466. {
  467. const f32 scale = 1.0f - time;
  468. return (*this = ((q1 * scale) + (q2 * time)).normalize());
  469. }
  470. // set this quaternion to the result of the interpolation between two quaternions
  471. inline quaternion &quaternion::slerp(quaternion q1, quaternion q2, f32 time, f32 threshold)
  472. {
  473. f32 angle = q1.dotProduct(q2);
  474. // make sure we use the short rotation
  475. if (angle < 0.0f) {
  476. q1 *= -1.0f;
  477. angle *= -1.0f;
  478. }
  479. if (angle <= (1 - threshold)) { // spherical interpolation
  480. const f32 theta = acosf(angle);
  481. const f32 invsintheta = reciprocal(sinf(theta));
  482. const f32 scale = sinf(theta * (1.0f - time)) * invsintheta;
  483. const f32 invscale = sinf(theta * time) * invsintheta;
  484. return (*this = (q1 * scale) + (q2 * invscale));
  485. } else // linear interpolation
  486. return lerpN(q1, q2, time);
  487. }
  488. // calculates the dot product
  489. inline f32 quaternion::dotProduct(const quaternion &q2) const
  490. {
  491. return (X * q2.X) + (Y * q2.Y) + (Z * q2.Z) + (W * q2.W);
  492. }
  493. //! axis must be unit length, angle in radians
  494. inline quaternion &quaternion::fromAngleAxis(f32 angle, const vector3df &axis)
  495. {
  496. const f32 fHalfAngle = 0.5f * angle;
  497. const f32 fSin = sinf(fHalfAngle);
  498. W = cosf(fHalfAngle);
  499. X = fSin * axis.X;
  500. Y = fSin * axis.Y;
  501. Z = fSin * axis.Z;
  502. return *this;
  503. }
  504. inline void quaternion::toAngleAxis(f32 &angle, core::vector3df &axis) const
  505. {
  506. const f32 scale = sqrtf(X * X + Y * Y + Z * Z);
  507. if (core::iszero(scale) || W > 1.0f || W < -1.0f) {
  508. angle = 0.0f;
  509. axis.X = 0.0f;
  510. axis.Y = 1.0f;
  511. axis.Z = 0.0f;
  512. } else {
  513. const f32 invscale = reciprocal(scale);
  514. angle = 2.0f * acosf(W);
  515. axis.X = X * invscale;
  516. axis.Y = Y * invscale;
  517. axis.Z = Z * invscale;
  518. }
  519. }
  520. inline void quaternion::toEuler(vector3df &euler) const
  521. {
  522. const f64 sqw = W * W;
  523. const f64 sqx = X * X;
  524. const f64 sqy = Y * Y;
  525. const f64 sqz = Z * Z;
  526. const f64 test = 2.0 * (Y * W - X * Z);
  527. if (core::equals(test, 1.0, 0.000001)) {
  528. // heading = rotation about z-axis
  529. euler.Z = (f32)(-2.0 * atan2(X, W));
  530. // bank = rotation about x-axis
  531. euler.X = 0;
  532. // attitude = rotation about y-axis
  533. euler.Y = (f32)(core::PI64 / 2.0);
  534. } else if (core::equals(test, -1.0, 0.000001)) {
  535. // heading = rotation about z-axis
  536. euler.Z = (f32)(2.0 * atan2(X, W));
  537. // bank = rotation about x-axis
  538. euler.X = 0;
  539. // attitude = rotation about y-axis
  540. euler.Y = (f32)(core::PI64 / -2.0);
  541. } else {
  542. // heading = rotation about z-axis
  543. euler.Z = (f32)atan2(2.0 * (X * Y + Z * W), (sqx - sqy - sqz + sqw));
  544. // bank = rotation about x-axis
  545. euler.X = (f32)atan2(2.0 * (Y * Z + X * W), (-sqx - sqy + sqz + sqw));
  546. // attitude = rotation about y-axis
  547. euler.Y = (f32)asin(clamp(test, -1.0, 1.0));
  548. }
  549. }
  550. inline vector3df quaternion::operator*(const vector3df &v) const
  551. {
  552. // nVidia SDK implementation
  553. vector3df uv, uuv;
  554. const vector3df qvec(X, Y, Z);
  555. uv = qvec.crossProduct(v);
  556. uuv = qvec.crossProduct(uv);
  557. uv *= (2.0f * W);
  558. uuv *= 2.0f;
  559. return v + uv + uuv;
  560. }
  561. // set quaternion to identity
  562. inline core::quaternion &quaternion::makeIdentity()
  563. {
  564. W = 1.f;
  565. X = 0.f;
  566. Y = 0.f;
  567. Z = 0.f;
  568. return *this;
  569. }
  570. inline core::quaternion &quaternion::rotationFromTo(const vector3df &from, const vector3df &to)
  571. {
  572. // Based on Stan Melax's article in Game Programming Gems
  573. // Optimized by Robert Eisele: https://raw.org/proof/quaternion-from-two-vectors
  574. // Copy, since cannot modify local
  575. vector3df v0 = from;
  576. vector3df v1 = to;
  577. v0.normalize();
  578. v1.normalize();
  579. const f32 d = v0.dotProduct(v1);
  580. if (d >= 1.0f) { // If dot == 1, vectors are the same
  581. return makeIdentity();
  582. } else if (d <= -1.0f) { // exactly opposite
  583. core::vector3df axis(1.0f, 0.f, 0.f);
  584. axis = axis.crossProduct(v0);
  585. if (axis.getLength() == 0) {
  586. axis.set(0.f, 1.f, 0.f);
  587. axis = axis.crossProduct(v0);
  588. }
  589. // same as fromAngleAxis(core::PI, axis).normalize();
  590. return set(axis.X, axis.Y, axis.Z, 0).normalize();
  591. }
  592. const vector3df c = v0.crossProduct(v1);
  593. return set(c.X, c.Y, c.Z, 1 + d).normalize();
  594. }
  595. } // end namespace core
  596. } // end namespace irr