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 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*!
  2. * \file src/Quaternion.cpp
  3. * \brief Quaternion
  4. *
  5. * \author Mongoose
  6. */
  7. #include <math.h>
  8. #include "Quaternion.h"
  9. Quaternion::Quaternion() {
  10. mW = 0;
  11. mX = 0;
  12. mY = 0;
  13. mZ = 0;
  14. }
  15. Quaternion::Quaternion(vec_t w, vec_t x, vec_t y, vec_t z) {
  16. mW = w;
  17. mX = x;
  18. mY = y;
  19. mZ = z;
  20. }
  21. Quaternion::Quaternion(vec4_t v) {
  22. mW = v[0];
  23. mX = v[1];
  24. mY = v[2];
  25. mZ = v[3];
  26. }
  27. void Quaternion::getMatrix(matrix_t m) {
  28. m[ 0] = 1.0f - 2.0f * (mY*mY + mZ*mZ);
  29. m[ 1] = 2.0f * (mX*mY - mW*mZ);
  30. m[ 2] = 2.0f * (mX*mZ + mW*mY);
  31. m[ 3] = 0.0f;
  32. m[ 4] = 2.0f * (mX*mY + mW*mZ);
  33. m[ 5] = 1.0f - 2.0f * (mX*mX + mZ*mZ);
  34. m[ 6] = 2.0f * (mY*mZ - mW*mX);
  35. m[ 7] = 0.0f;
  36. m[ 8] = 2.0f * (mX*mZ - mW*mY);
  37. m[ 9] = 2.0f * (mY*mZ + mW*mX);
  38. m[10] = 1.0f - 2.0f * (mX*mX + mY*mY);
  39. m[11] = 0.0f;
  40. m[12] = 0.0f;
  41. m[13] = 0.0f;
  42. m[14] = 0.0f;
  43. m[15] = 1.0f;
  44. }
  45. Quaternion Quaternion::operator *(const Quaternion &q) {
  46. return multiply(*this, q);
  47. }
  48. Quaternion Quaternion::operator /(const Quaternion &q) {
  49. return divide(*this, q);
  50. }
  51. Quaternion Quaternion::operator +(const Quaternion &q) {
  52. return add(*this, q);
  53. }
  54. Quaternion Quaternion::operator -(const Quaternion &q) {
  55. return subtract(*this, q);
  56. }
  57. bool Quaternion::operator ==(const Quaternion &q) {
  58. //return (mX == q.mX && mY == q.mY && mZ == q.mZ && mW == q.mW);
  59. return (equalEpsilon(mX, q.mX) && equalEpsilon(mY, q.mY) &&
  60. equalEpsilon(mZ, q.mZ) && equalEpsilon(mW, q.mW));
  61. }
  62. Quaternion Quaternion::conjugate() {
  63. return Quaternion(mW, -mX, -mY, -mZ);
  64. }
  65. Quaternion Quaternion::scale(vec_t s) {
  66. return Quaternion(mW * s, mX * s, mY * s, mZ * s);
  67. }
  68. Quaternion Quaternion::inverse() {
  69. return conjugate().scale(1/magnitude());
  70. }
  71. vec_t Quaternion::dot(Quaternion a, Quaternion b) {
  72. return ((a.mW * b.mW) + (a.mX * b.mX) + (a.mY * b.mY) + (a.mZ * b.mZ));
  73. }
  74. vec_t Quaternion::magnitude() {
  75. return sqrtf(dot(*this, *this));
  76. }
  77. void Quaternion::setIdentity() {
  78. mW = 1.0;
  79. mX = 0.0;
  80. mY = 0.0;
  81. mZ = 0.0;
  82. }
  83. void Quaternion::set(vec_t angle, vec_t x, vec_t y, vec_t z) {
  84. vec_t temp, dist;
  85. // Normalize
  86. temp = x*x + y*y + z*z;
  87. dist = 1.0f / sqrtf(temp);
  88. x *= dist;
  89. y *= dist;
  90. z *= dist;
  91. mX = x;
  92. mY = y;
  93. mZ = z;
  94. mW = cosf(angle / 2.0f);
  95. }
  96. void Quaternion::normalize() {
  97. vec_t dist, square;
  98. square = mX * mX + mY * mY + mZ * mZ + mW * mW;
  99. if (square > 0.0) {
  100. dist = 1.0f / sqrtf(square);
  101. } else {
  102. dist = 1;
  103. }
  104. mX *= dist;
  105. mY *= dist;
  106. mZ *= dist;
  107. mW *= dist;
  108. }
  109. void Quaternion::copy(Quaternion q) {
  110. mW = q.mW;
  111. mX = q.mX;
  112. mY = q.mY;
  113. mZ = q.mZ;
  114. }
  115. Quaternion Quaternion::slerp(Quaternion a, Quaternion b, vec_t time) {
  116. /*******************************************************************
  117. * Spherical Linear Interpolation algorthim
  118. *-----------------------------------------------------------------
  119. *
  120. * Interpolate between A and B rotations ( Find qI )
  121. *
  122. * qI = (((qB . qA)^ -1)^ Time) qA
  123. *
  124. * http://www.magic-software.com/Documentation/quat.pdf
  125. *
  126. * Thanks to digiben for algorithms and basis of the notes in
  127. * this func
  128. *
  129. *******************************************************************/
  130. vec_t result, scaleA, scaleB;
  131. Quaternion i;
  132. // Don't bother if it's the same rotation, it's the same as the result
  133. if (a == b)
  134. return a;
  135. // A . B
  136. result = dot(a, b);
  137. // If the dot product is less than 0, the angle is greater than 90 degrees
  138. if (result < 0.0f) {
  139. // Negate quaternion B and the result of the dot product
  140. b = Quaternion(-b.mW, -b.mX, -b.mY, -b.mZ);
  141. result = -result;
  142. }
  143. // Set the first and second scale for the interpolation
  144. scaleA = 1 - time;
  145. scaleB = time;
  146. // Next, we want to actually calculate the spherical interpolation. Since this
  147. // calculation is quite computationally expensive, we want to only perform it
  148. // if the angle between the 2 quaternions is large enough to warrant it. If the
  149. // angle is fairly small, we can actually just do a simpler linear interpolation
  150. // of the 2 quaternions, and skip all the complex math. We create a "delta" value
  151. // of 0.1 to say that if the cosine of the angle (result of the dot product) between
  152. // the 2 quaternions is smaller than 0.1, then we do NOT want to perform the full on
  153. // interpolation using. This is because you won't really notice the difference.
  154. // Check if the angle between the 2 quaternions was big enough
  155. // to warrant such calculations
  156. if (1 - result > 0.1f) {
  157. // Get the angle between the 2 quaternions, and then
  158. // store the sin() of that angle
  159. vec_t theta = (float)acos(result);
  160. vec_t sinTheta = (float)sin(theta);
  161. // Calculate the scale for qA and qB, according to
  162. // the angle and it's sine value
  163. scaleA = (float)sin((1 - time) * theta) / sinTheta;
  164. scaleB = (float)sin((time * theta)) / sinTheta;
  165. }
  166. // Calculate the x, y, z and w values for the quaternion by using a special
  167. // form of linear interpolation for quaternions.
  168. return (a.scale(scaleA) + b.scale(scaleB));
  169. }
  170. void Quaternion::setByMatrix(matrix_t matrix) {
  171. float diagonal = matrix[0] + matrix[5] + matrix[10] + 1.0f;
  172. float scale = 0.0f;
  173. float w = 0.0f, x = 0.0f, y = 0.0f, z = 0.0f;
  174. if (diagonal > 0.00000001) {
  175. // Calculate the scale of the diagonal
  176. scale = (float)(sqrt(diagonal) * 2);
  177. w = 0.25f * scale;
  178. x = (matrix[9] - matrix[6]) / scale;
  179. y = (matrix[2] - matrix[8]) / scale;
  180. z = (matrix[4] - matrix[1]) / scale;
  181. } else {
  182. // If the first element of the diagonal is the greatest value
  183. if (matrix[0] > matrix[5] && matrix[0] > matrix[10]) {
  184. // Find the scale according to the first element, and double it
  185. scale = (float)sqrt(1.0f + matrix[0] - matrix[5] - matrix[10])*2.0f;
  186. // Calculate the quaternion
  187. w = (matrix[9] - matrix[6]) / scale;
  188. x = 0.25f * scale;
  189. y = (matrix[4] + matrix[1]) / scale;
  190. z = (matrix[2] + matrix[8]) / scale;
  191. } else if (matrix[5] > matrix[10]) {
  192. // The second element of the diagonal is the greatest value
  193. // Find the scale according to the second element, and double it
  194. scale = (float)sqrt(1.0f + matrix[5] - matrix[0] - matrix[10])*2.0f;
  195. // Calculate the quaternion
  196. w = (matrix[2] - matrix[8]) / scale;
  197. x = (matrix[4] + matrix[1]) / scale;
  198. y = 0.25f * scale;
  199. z = (matrix[9] + matrix[6]) / scale;
  200. } else { // The third element of the diagonal is the greatest value
  201. // Find the scale according to the third element, and double it
  202. scale = (float)sqrt(1.0f + matrix[10] - matrix[0] - matrix[5])*2.0f;
  203. // Calculate the quaternion
  204. w = (matrix[4] - matrix[1]) / scale;
  205. x = (matrix[2] + matrix[8]) / scale;
  206. y = (matrix[9] + matrix[6]) / scale;
  207. z = 0.25f * scale;
  208. }
  209. }
  210. mW = w;
  211. mX = x;
  212. mY = y;
  213. mZ = z;
  214. }
  215. Quaternion Quaternion::multiply(Quaternion a, Quaternion b) {
  216. return Quaternion(a.mW * b.mW - a.mX * b.mX - a.mY * b.mY - a.mZ * b.mZ,
  217. a.mW * b.mX + a.mX * b.mW + a.mY * b.mZ - a.mZ * b.mY,
  218. a.mW * b.mY + a.mY * b.mW + a.mZ * b.mX - a.mX * b.mZ,
  219. a.mW * b.mZ + a.mZ * b.mW + a.mX * b.mY - a.mY * b.mX);
  220. }
  221. Quaternion Quaternion::divide(Quaternion a, Quaternion b) {
  222. return (a * (b.inverse()));
  223. }
  224. Quaternion Quaternion::add(Quaternion a, Quaternion b) {
  225. return Quaternion(a.mW + b.mW,
  226. a.mX + b.mX,
  227. a.mY + b.mY,
  228. a.mZ + b.mZ);
  229. }
  230. Quaternion Quaternion::subtract(Quaternion a, Quaternion b) {
  231. return Quaternion(a.mW - b.mW,
  232. a.mX - b.mX,
  233. a.mY - b.mY,
  234. a.mZ - b.mZ);
  235. }