Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

Quaternion.cpp 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: t; c-basic-offset: 3 -*- */
  2. /*================================================================
  3. *
  4. * Project : Hel
  5. * Author : Terry 'Mongoose' Hendrix II
  6. * Website : http://www.westga.edu/~stu7440/
  7. * Email : stu7440@westga.edu
  8. * Object : Quaternion
  9. * License : No use w/o permission (C) 2002 Mongoose
  10. * Comments: Quaternion now in C++ class form fresh from the grove
  11. *
  12. *
  13. * This file was generated using Mongoose's C++
  14. * template generator script. <stu7440@westga.edu>
  15. *
  16. *-- History -------------------------------------------------
  17. *
  18. * 2002.12.16:
  19. * Mongoose - Created, based on mtk3d ( freyja )
  20. =================================================================*/
  21. #include <math.h>
  22. #include <Quaternion.h>
  23. ////////////////////////////////////////////////////////////
  24. // Constructors
  25. ////////////////////////////////////////////////////////////
  26. Quaternion::Quaternion()
  27. {
  28. mW = 0;
  29. mX = 0;
  30. mY = 0;
  31. mZ = 0;
  32. }
  33. Quaternion::Quaternion(vec_t w, vec_t x, vec_t y, vec_t z)
  34. {
  35. mW = w;
  36. mX = x;
  37. mY = y;
  38. mZ = z;
  39. }
  40. Quaternion::Quaternion(vec4_t v)
  41. {
  42. mW = v[0];
  43. mX = v[1];
  44. mY = v[2];
  45. mZ = v[3];
  46. }
  47. Quaternion::~Quaternion()
  48. {
  49. }
  50. ////////////////////////////////////////////////////////////
  51. // Public Accessors
  52. ////////////////////////////////////////////////////////////
  53. void Quaternion::getMatrix(matrix_t m)
  54. {
  55. m[ 0] = 1.0f - 2.0f * (mY*mY + mZ*mZ);
  56. m[ 1] = 2.0f * (mX*mY - mW*mZ);
  57. m[ 2] = 2.0f * (mX*mZ + mW*mY);
  58. m[ 3] = 0.0f;
  59. m[ 4] = 2.0f * (mX*mY + mW*mZ);
  60. m[ 5] = 1.0f - 2.0f * (mX*mX + mZ*mZ);
  61. m[ 6] = 2.0f * (mY*mZ - mW*mX);
  62. m[ 7] = 0.0f;
  63. m[ 8] = 2.0f * (mX*mZ - mW*mY);
  64. m[ 9] = 2.0f * (mY*mZ + mW*mX);
  65. m[10] = 1.0 - 2.0f * (mX*mX + mY*mY);
  66. m[11] = 0.0f;
  67. m[12] = 0.0f;
  68. m[13] = 0.0f;
  69. m[14] = 0.0f;
  70. m[15] = 1.0f;
  71. }
  72. Quaternion Quaternion::operator =(const Quaternion &q)
  73. {
  74. mW = q.mW;
  75. mX = q.mX;
  76. mY = q.mY;
  77. mZ = q.mZ;
  78. return (*this);
  79. }
  80. Quaternion Quaternion::operator *(const Quaternion &q)
  81. {
  82. return multiply(*this, q);
  83. }
  84. Quaternion Quaternion::operator /(const Quaternion &q)
  85. {
  86. return divide(*this, q);
  87. }
  88. Quaternion Quaternion::operator +(const Quaternion &q)
  89. {
  90. return add(*this, q);
  91. }
  92. Quaternion Quaternion::operator -(const Quaternion &q)
  93. {
  94. return subtract(*this, q);
  95. }
  96. bool Quaternion::operator ==(const Quaternion &q)
  97. {
  98. return (mX == q.mX && mY == q.mY && mZ == q.mZ && mW == q.mW);
  99. }
  100. Quaternion Quaternion::conjugate()
  101. {
  102. return Quaternion(mW, -mX, -mY, -mZ);
  103. }
  104. Quaternion Quaternion::scale(vec_t s)
  105. {
  106. return Quaternion(mW * s, mX * s, mY * s, mZ * s);
  107. }
  108. Quaternion Quaternion::inverse()
  109. {
  110. return conjugate().scale(1/magnitude());
  111. }
  112. vec_t Quaternion::dot(Quaternion a, Quaternion b)
  113. {
  114. return ((a.mW * b.mW) + (a.mX * b.mX) + (a.mY * b.mY) + (a.mZ * b.mZ));
  115. }
  116. vec_t Quaternion::magnitude()
  117. {
  118. return sqrt(dot(*this, *this));
  119. }
  120. ////////////////////////////////////////////////////////////
  121. // Public Mutators
  122. ////////////////////////////////////////////////////////////
  123. void Quaternion::setIdentity()
  124. {
  125. mW = 1.0;
  126. mX = 0.0;
  127. mY = 0.0;
  128. mZ = 0.0;
  129. }
  130. void Quaternion::set(vec_t angle, vec_t x, vec_t y, vec_t z)
  131. {
  132. vec_t temp, dist;
  133. // Normalize
  134. temp = x*x + y*y + z*z;
  135. dist = (float)(1.0 / sqrt(temp));
  136. x *= dist;
  137. y *= dist;
  138. z *= dist;
  139. mX = x;
  140. mY = y;
  141. mZ = z;
  142. mW = (float)cos(angle / 2.0f);
  143. }
  144. void Quaternion::normalize()
  145. {
  146. vec_t dist, square;
  147. square = mX * mX + mY * mY + mZ * mZ + mW * mW;
  148. if (square > 0.0)
  149. {
  150. dist = (float)(1.0 / sqrt(square));
  151. }
  152. else
  153. {
  154. dist = 1;
  155. }
  156. mX *= dist;
  157. mY *= dist;
  158. mZ *= dist;
  159. mW *= dist;
  160. }
  161. void Quaternion::copy(Quaternion q)
  162. {
  163. mW = q.mW;
  164. mX = q.mX;
  165. mY = q.mY;
  166. mZ = q.mZ;
  167. }
  168. Quaternion Quaternion::slerp(Quaternion a, Quaternion b, vec_t time)
  169. {
  170. /*******************************************************************
  171. * Spherical Linear Interpolation algorthim
  172. *-----------------------------------------------------------------
  173. *
  174. * Interpolate between A and B rotations ( Find qI )
  175. *
  176. * qI = (((qB . qA)^ -1)^ Time) qA
  177. *
  178. * http://www.magic-software.com/Documentation/quat.pdf
  179. *
  180. * Thanks to digiben for algorithms and basis of the notes in
  181. * this func
  182. *
  183. *******************************************************************/
  184. vec_t result, scaleA, scaleB, theta, sinTheta;
  185. Quaternion i;
  186. // Don't bother if it's the same rotation, it's the same as the result
  187. if (a == b)
  188. {
  189. return a;
  190. }
  191. // A . B
  192. result = dot(a, b);
  193. // If the dot product is less than 0, the angle is greater than 90 degrees
  194. if (result < 0.0f)
  195. {
  196. // Negate quaternion B and the result of the dot product
  197. b = Quaternion(-b.mW, -b.mX, -b.mY, -b.mZ);
  198. result = -result;
  199. }
  200. // Set the first and second scale for the interpolation
  201. scaleA = 1 - time;
  202. scaleB = time;
  203. // Next, we want to actually calculate the spherical interpolation. Since this
  204. // calculation is quite computationally expensive, we want to only perform it
  205. // if the angle between the 2 quaternions is large enough to warrant it. If the
  206. // angle is fairly small, we can actually just do a simpler linear interpolation
  207. // of the 2 quaternions, and skip all the complex math. We create a "delta" value
  208. // of 0.1 to say that if the cosine of the angle (result of the dot product) between
  209. // the 2 quaternions is smaller than 0.1, then we do NOT want to perform the full on
  210. // interpolation using. This is because you won't really notice the difference.
  211. // Check if the angle between the 2 quaternions was big enough
  212. // to warrant such calculations
  213. if (1 - result > 0.1f)
  214. {
  215. // Get the angle between the 2 quaternions, and then
  216. // store the sin() of that angle
  217. theta = (float)acos(result);
  218. sinTheta = (float)sin(theta);
  219. // Calculate the scale for qA and qB, according to
  220. // the angle and it's sine value
  221. scaleA = (float)sin((1 - time) * theta) / sinTheta;
  222. scaleB = (float)sin((time * theta)) / sinTheta;
  223. }
  224. // Calculate the x, y, z and w values for the quaternion by using a special
  225. // form of linear interpolation for quaternions.
  226. return (a.scale(scaleA) + b.scale(scaleB));
  227. }
  228. void Quaternion::setByMatrix(matrix_t matrix)
  229. {
  230. float diagonal = matrix[0] + matrix[5] + matrix[10] + 1.0f;
  231. float scale = 0.0f;
  232. float w = 0.0f, x = 0.0f, y = 0.0f, z = 0.0f;
  233. if (diagonal > 0.00000001)
  234. {
  235. // Calculate the scale of the diagonal
  236. scale = (float)(sqrt(diagonal) * 2);
  237. w = 0.25f * scale;
  238. x = (matrix[9] - matrix[6]) / scale;
  239. y = (matrix[2] - matrix[8]) / scale;
  240. z = (matrix[4] - matrix[1]) / scale;
  241. }
  242. else
  243. {
  244. // If the first element of the diagonal is the greatest value
  245. if (matrix[0] > matrix[5] && matrix[0] > matrix[10])
  246. {
  247. // Find the scale according to the first element, and double it
  248. scale = (float)sqrt(1.0f + matrix[0] - matrix[5] - matrix[10])*2.0f;
  249. // Calculate the quaternion
  250. w = (matrix[9] - matrix[6]) / scale;
  251. x = 0.25f * scale;
  252. y = (matrix[4] + matrix[1]) / scale;
  253. z = (matrix[2] + matrix[8]) / scale;
  254. }
  255. // The second element of the diagonal is the greatest value
  256. else if (matrix[5] > matrix[10])
  257. {
  258. // Find the scale according to the second element, and double it
  259. scale = (float)sqrt(1.0f + matrix[5] - matrix[0] - matrix[10])*2.0f;
  260. // Calculate the quaternion
  261. w = (matrix[2] - matrix[8]) / scale;
  262. x = (matrix[4] + matrix[1]) / scale;
  263. y = 0.25f * scale;
  264. z = (matrix[9] + matrix[6]) / scale;
  265. }
  266. // The third element of the diagonal is the greatest value
  267. else
  268. {
  269. // Find the scale according to the third element, and double it
  270. scale = (float)sqrt(1.0f + matrix[10] - matrix[0] - matrix[5])*2.0f;
  271. // Calculate the quaternion
  272. w = (matrix[4] - matrix[1]) / scale;
  273. x = (matrix[2] + matrix[8]) / scale;
  274. y = (matrix[9] + matrix[6]) / scale;
  275. z = 0.25f * scale;
  276. }
  277. }
  278. mW = w;
  279. mX = x;
  280. mY = y;
  281. mZ = z;
  282. }
  283. ////////////////////////////////////////////////////////////
  284. // Private Accessors
  285. ////////////////////////////////////////////////////////////
  286. Quaternion Quaternion::multiply(Quaternion a, Quaternion b)
  287. {
  288. return Quaternion(a.mW * b.mW - a.mX * b.mX - a.mY * b.mY - a.mZ * b.mZ,
  289. a.mW * b.mX + a.mX * b.mW + a.mY * b.mZ - a.mZ * b.mY,
  290. a.mW * b.mY + a.mY * b.mW + a.mZ * b.mX - a.mX * b.mZ,
  291. a.mW * b.mZ + a.mZ * b.mW + a.mX * b.mY - a.mY * b.mX);
  292. }
  293. Quaternion Quaternion::divide(Quaternion a, Quaternion b)
  294. {
  295. return (a * (b.inverse()));
  296. }
  297. Quaternion Quaternion::add(Quaternion a, Quaternion b)
  298. {
  299. return Quaternion(a.mW + b.mW,
  300. a.mX + b.mX,
  301. a.mY + b.mY,
  302. a.mZ + b.mZ);
  303. }
  304. Quaternion Quaternion::subtract(Quaternion a, Quaternion b)
  305. {
  306. return Quaternion(a.mW - b.mW,
  307. a.mX - b.mX,
  308. a.mY - b.mY,
  309. a.mZ - b.mZ);
  310. }
  311. ////////////////////////////////////////////////////////////
  312. // Private Mutators
  313. ////////////////////////////////////////////////////////////