quaternion.h 17 KB

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