mQuat.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "math/mQuat.h"
  24. #include "math/mAngAxis.h"
  25. #include "math/mMatrix.h"
  26. #include "platform/profiler.h"
  27. const QuatF QuatF::Identity(0.0f,0.0f,0.0f,1.0f);
  28. QuatF& QuatF::set( const EulerF & e )
  29. {
  30. F32 cx, sx;
  31. F32 cy, sy;
  32. F32 cz, sz;
  33. mSinCos( e.x * 0.5f, sx, cx );
  34. mSinCos( e.y * 0.5f, sy, cy );
  35. mSinCos( e.z * 0.5f, sz, cz );
  36. // Qyaw(z) = [ (0, 0, sin z/2), cos z/2 ]
  37. // Qpitch(x) = [ (sin x/2, 0, 0), cos x/2 ]
  38. // Qroll(y) = [ (0, sin y/2, 0), cos y/2 ]
  39. // this = Qresult = Qyaw*Qpitch*Qroll ZXY
  40. //
  41. // The code that folows is a simplification of:
  42. // roll*=pitch;
  43. // roll*=yaw;
  44. // *this = roll;
  45. F32 cycz, sysz, sycz, cysz;
  46. cycz = cy*cz;
  47. sysz = sy*sz;
  48. sycz = sy*cz;
  49. cysz = cy*sz;
  50. w = cycz*cx - sysz*sx;
  51. x = cycz*sx + sysz*cx;
  52. y = sycz*cx + cysz*sx;
  53. z = cysz*cx - sycz*sx;
  54. return *this;
  55. }
  56. QuatF& QuatF::operator *=( const QuatF & b )
  57. {
  58. QuatF prod;
  59. prod.w = w * b.w - x * b.x - y * b.y - z * b.z;
  60. prod.x = w * b.x + x * b.w + y * b.z - z * b.y;
  61. prod.y = w * b.y + y * b.w + z * b.x - x * b.z;
  62. prod.z = w * b.z + z * b.w + x * b.y - y * b.x;
  63. *this = prod;
  64. return (*this);
  65. }
  66. QuatF& QuatF::operator /=( const QuatF & c )
  67. {
  68. QuatF temp = c;
  69. return ( (*this) *= temp.inverse() );
  70. }
  71. QuatF& QuatF::square()
  72. {
  73. F32 t = w*2.0f;
  74. w = (w*w) - (x*x + y*y + z*z);
  75. x *= t;
  76. y *= t;
  77. z *= t;
  78. return *this;
  79. }
  80. QuatF& QuatF::inverse()
  81. {
  82. F32 magnitude = w*w + x*x + y*y + z*z;
  83. F32 invMagnitude;
  84. if( magnitude == 1.0f ) // special case unit quaternion
  85. {
  86. x = -x;
  87. y = -y;
  88. z = -z;
  89. }
  90. else // else scale
  91. {
  92. if( magnitude == 0.0f )
  93. invMagnitude = 1.0f;
  94. else
  95. invMagnitude = 1.0f / magnitude;
  96. w *= invMagnitude;
  97. x *= -invMagnitude;
  98. y *= -invMagnitude;
  99. z *= -invMagnitude;
  100. }
  101. return *this;
  102. }
  103. QuatF & QuatF::set( const AngAxisF & a )
  104. {
  105. return set( a.axis, a.angle );
  106. }
  107. QuatF & QuatF::set( const Point3F &axis, F32 angle )
  108. {
  109. PROFILE_SCOPE( QuatF_set_AngAxisF );
  110. F32 sinHalfAngle, cosHalfAngle;
  111. mSinCos( angle * 0.5f, sinHalfAngle, cosHalfAngle );
  112. x = axis.x * sinHalfAngle;
  113. y = axis.y * sinHalfAngle;
  114. z = axis.z * sinHalfAngle;
  115. w = cosHalfAngle;
  116. return *this;
  117. }
  118. QuatF & QuatF::normalize()
  119. {
  120. PROFILE_SCOPE( QuatF_normalize );
  121. F32 l = mSqrt( x*x + y*y + z*z + w*w );
  122. if( l == 0.0f )
  123. identity();
  124. else
  125. {
  126. x /= l;
  127. y /= l;
  128. z /= l;
  129. w /= l;
  130. }
  131. return *this;
  132. }
  133. #define idx(r,c) (r*4 + c)
  134. QuatF & QuatF::set( const MatrixF & mat )
  135. {
  136. PROFILE_SCOPE( QuatF_set_MatrixF );
  137. F32 const *m = mat;
  138. F32 trace = m[idx(0, 0)] + m[idx(1, 1)] + m[idx(2, 2)];
  139. if (trace > 0.0f)
  140. {
  141. F32 s = mSqrt(trace + F32(1));
  142. w = s * 0.5f;
  143. s = 0.5f / s;
  144. x = (m[idx(1,2)] - m[idx(2,1)]) * s;
  145. y = (m[idx(2,0)] - m[idx(0,2)]) * s;
  146. z = (m[idx(0,1)] - m[idx(1,0)]) * s;
  147. }
  148. else
  149. {
  150. F32* q = &x;
  151. U32 i = 0;
  152. if (m[idx(1, 1)] > m[idx(0, 0)]) i = 1;
  153. if (m[idx(2, 2)] > m[idx(i, i)]) i = 2;
  154. U32 j = (i + 1) % 3;
  155. U32 k = (j + 1) % 3;
  156. F32 s = mSqrt((m[idx(i, i)] - (m[idx(j, j)] + m[idx(k, k)])) + 1.0f);
  157. q[i] = s * 0.5f;
  158. s = 0.5f / s;
  159. q[j] = (m[idx(i,j)] + m[idx(j,i)]) * s;
  160. q[k] = (m[idx(i,k)] + m[idx(k, i)]) * s;
  161. w = (m[idx(j,k)] - m[idx(k, j)]) * s;
  162. }
  163. // Added to resolve issue #2230
  164. normalize();
  165. return *this;
  166. }
  167. MatrixF * QuatF::setMatrix( MatrixF * mat ) const
  168. {
  169. if( x*x + y*y + z*z < 10E-20f) // isIdentity() -- substituted code a little more stringent but a lot faster
  170. mat->identity();
  171. else
  172. m_quatF_set_matF( x, y, z, w, *mat );
  173. return mat;
  174. }
  175. QuatF & QuatF::slerp( const QuatF & q, F32 t )
  176. {
  177. return interpolate( *this, q, t );
  178. }
  179. QuatF & QuatF::extrapolate( const QuatF & q1, const QuatF & q2, F32 t )
  180. {
  181. // assert t >= 0 && t <= 1
  182. // q1 is value at time = 0
  183. // q2 is value at time = t
  184. // Computes quaternion at time = 1
  185. F64 flip,cos = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
  186. if (cos < 0.0)
  187. {
  188. cos = -cos;
  189. flip = -1.0;
  190. }
  191. else
  192. flip = 1.0;
  193. F64 s1,s2;
  194. if ((1.0 - cos) > 0.00001)
  195. {
  196. F64 om = mAcos(cos) / t;
  197. F64 sd = 1.0 / mSin(t * om);
  198. s1 = flip * mSin(om) * sd;
  199. s2 = mSin((1.0 - t) * om) * sd;
  200. }
  201. else
  202. {
  203. // If quats are very close, do linear interpolation
  204. s1 = flip / t;
  205. s2 = (1.0 - t) / t;
  206. }
  207. x = F32(s1 * q2.x - s2 * q1.x);
  208. y = F32(s1 * q2.y - s2 * q1.y);
  209. z = F32(s1 * q2.z - s2 * q1.z);
  210. w = F32(s1 * q2.w - s2 * q1.w);
  211. return *this;
  212. }
  213. QuatF & QuatF::interpolate( const QuatF & q1, const QuatF & q2, F32 t )
  214. {
  215. //-----------------------------------
  216. // Calculate the cosine of the angle:
  217. double cosOmega = q1.dot( q2 );
  218. //-----------------------------------
  219. // adjust signs if necessary:
  220. F32 sign2;
  221. if ( cosOmega < 0.0 )
  222. {
  223. cosOmega = -cosOmega;
  224. sign2 = -1.0f;
  225. }
  226. else
  227. sign2 = 1.0f;
  228. //-----------------------------------
  229. // calculate interpolating coeffs:
  230. F64 scale1, scale2;
  231. if ( (1.0 - cosOmega) > 0.00001 )
  232. {
  233. // standard case
  234. F64 omega = mAcos(cosOmega);
  235. F64 sinOmega = mSin(omega);
  236. scale1 = mSin((1.0 - t) * omega) / sinOmega;
  237. scale2 = sign2 * mSin(t * omega) / sinOmega;
  238. }
  239. else
  240. {
  241. // if quats are very close, just do linear interpolation
  242. scale1 = 1.0 - t;
  243. scale2 = sign2 * t;
  244. }
  245. //-----------------------------------
  246. // actually do the interpolation:
  247. x = F32(scale1 * q1.x + scale2 * q2.x);
  248. y = F32(scale1 * q1.y + scale2 * q2.y);
  249. z = F32(scale1 * q1.z + scale2 * q2.z);
  250. w = F32(scale1 * q1.w + scale2 * q2.w);
  251. return *this;
  252. }
  253. Point3F & QuatF::mulP(const Point3F& p, Point3F* r)
  254. {
  255. QuatF qq;
  256. QuatF qi = *this;
  257. QuatF qv( p.x, p.y, p.z, 0.0f);
  258. qi.inverse();
  259. qq.mul(qi, qv);
  260. qv.mul(qq, *this);
  261. r->set(qv.x, qv.y, qv.z);
  262. return *r;
  263. }
  264. QuatF & QuatF::mul( const QuatF &a, const QuatF &b)
  265. {
  266. AssertFatal( &a != this && &b != this, "QuatF::mul: dest should not be same as source" );
  267. w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
  268. x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
  269. y = a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z;
  270. z = a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x;
  271. return *this;
  272. }
  273. QuatF & QuatF::shortestArc( const VectorF &a, const VectorF &b )
  274. {
  275. // From Game Programming Gems pg. 217
  276. VectorF c = mCross( a, b );
  277. F32 d = mDot( a, b );
  278. F32 s = mSqrt( ( 1 + d ) * 2 );
  279. x = c.x / s;
  280. y = c.y / s;
  281. z = c.z / s;
  282. w = s / 2.f;
  283. return *this;
  284. }