Matrix3x3.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. #include "rparticle/Utilities/Matrix3x3.h"
  2. #include "rparticle/Math/FloatConversion.h"
  3. using namespace std;
  4. USING_NS_RRP;
  5. namespace
  6. {
  7. Matrix3x3f CreateIdentityMatrix3x3f ()
  8. {
  9. Matrix3x3f temp;
  10. temp.SetIdentity ();
  11. return temp;
  12. }
  13. Matrix3x3f CreateZeroMatrix3x3f ()
  14. {
  15. Matrix3x3f temp;
  16. temp.SetZero ();
  17. return temp;
  18. }
  19. }
  20. void QuaternionToMatrix (const Quaternionf& q, Matrix3x3f& m)
  21. {
  22. // If q is guaranteed to be a unit quaternion, s will always
  23. // be 1. In that case, this calculation can be optimized out.
  24. #if DEBUGMODE
  25. if (!CompareApproximately (SqrMagnitude (q), 1.0F, Vector3f::epsilon))
  26. {
  27. AssertString(Format("Quaternion To Matrix conversion failed because input Quaternion is invalid {%f, %f, %f, %f} l=%f", q.x, q.y, q.z, q.w, SqrMagnitude(q)));
  28. }
  29. #endif
  30. //float norm = GetNorm (q);
  31. //float s = (norm > 0.0) ? 2.0/norm : 0;
  32. // Precalculate coordinate products
  33. float x = q.x * 2.0F;
  34. float y = q.y * 2.0F;
  35. float z = q.z * 2.0F;
  36. float xx = q.x * x;
  37. float yy = q.y * y;
  38. float zz = q.z * z;
  39. float xy = q.x * y;
  40. float xz = q.x * z;
  41. float yz = q.y * z;
  42. float wx = q.w * x;
  43. float wy = q.w * y;
  44. float wz = q.w * z;
  45. // Calculate 3x3 matrix from orthonormal basis
  46. m.m_Data[0] = 1.0f - (yy + zz);
  47. m.m_Data[1] = xy + wz;
  48. m.m_Data[2] = xz - wy;
  49. m.m_Data[3] = xy - wz;
  50. m.m_Data[4] = 1.0f - (xx + zz);
  51. m.m_Data[5] = yz + wx;
  52. m.m_Data[6] = xz + wy;
  53. m.m_Data[7] = yz - wx;
  54. m.m_Data[8] = 1.0f - (xx + yy);
  55. }
  56. const Matrix3x3f Matrix3x3f::identity = CreateIdentityMatrix3x3f ();
  57. const Matrix3x3f Matrix3x3f::zero = CreateZeroMatrix3x3f ();
  58. void GetRotMatrixNormVec (float* out, const float* inVec, float radians);
  59. Matrix3x3f& Matrix3x3f::operator = (const Matrix4x4f& other)
  60. {
  61. m_Data[0] = other.m[0];
  62. m_Data[1] = other.m[1];
  63. m_Data[2] = other.m[2];
  64. m_Data[3] = other.m[4];
  65. m_Data[4] = other.m[5];
  66. m_Data[5] = other.m[6];
  67. m_Data[6] = other.m[8];
  68. m_Data[7] = other.m[9];
  69. m_Data[8] = other.m[10];
  70. return *this;
  71. }
  72. Matrix3x3f::Matrix3x3f (const Matrix4x4f& other)
  73. {
  74. m_Data[0] = other.m[0];
  75. m_Data[1] = other.m[1];
  76. m_Data[2] = other.m[2];
  77. m_Data[3] = other.m[4];
  78. m_Data[4] = other.m[5];
  79. m_Data[5] = other.m[6];
  80. m_Data[6] = other.m[8];
  81. m_Data[7] = other.m[9];
  82. m_Data[8] = other.m[10];
  83. }
  84. Matrix3x3f& Matrix3x3f::SetIdentity ()
  85. {
  86. Get (0, 0) = 1.0F; Get (0, 1) = 0.0F; Get (0, 2) = 0.0F;
  87. Get (1, 0) = 0.0F; Get (1, 1) = 1.0F; Get (1, 2) = 0.0F;
  88. Get (2, 0) = 0.0F; Get (2, 1) = 0.0F; Get (2, 2) = 1.0F;
  89. return *this;
  90. }
  91. Matrix3x3f& Matrix3x3f::SetZero ()
  92. {
  93. Get (0, 0) = 0.0F; Get (0, 1) = 0.0F; Get (0, 2) = 0.0F;
  94. Get (1, 0) = 0.0F; Get (1, 1) = 0.0F; Get (1, 2) = 0.0F;
  95. Get (2, 0) = 0.0F; Get (2, 1) = 0.0F; Get (2, 2) = 0.0F;
  96. return *this;
  97. }
  98. Matrix3x3f& Matrix3x3f::SetOrthoNormalBasis (const Vector3f& inX, const Vector3f& inY, const Vector3f& inZ)
  99. {
  100. Get (0, 0) = inX.x; Get (0, 1) = inY.x; Get (0, 2) = inZ.x;
  101. Get (1, 0) = inX.y; Get (1, 1) = inY.y; Get (1, 2) = inZ.y;
  102. Get (2, 0) = inX.z; Get (2, 1) = inY.z; Get (2, 2) = inZ.z;
  103. return *this;
  104. }
  105. Matrix3x3f& Matrix3x3f::SetOrthoNormalBasisInverse (const Vector3f& inX, const Vector3f& inY, const Vector3f& inZ)
  106. {
  107. Get (0, 0) = inX.x; Get (1, 0) = inY.x; Get (2, 0) = inZ.x;
  108. Get (0, 1) = inX.y; Get (1, 1) = inY.y; Get (2, 1) = inZ.y;
  109. Get (0, 2) = inX.z; Get (1, 2) = inY.z; Get (2, 2) = inZ.z;
  110. return *this;
  111. }
  112. Matrix3x3f& Matrix3x3f::SetScale (const Vector3f& inScale)
  113. {
  114. Get (0, 0) = inScale.x; Get (0, 1) = 0.0F; Get (0, 2) = 0.0F;
  115. Get (1, 0) = 0.0F; Get (1, 1) = inScale.y; Get (1, 2) = 0.0F;
  116. Get (2, 0) = 0.0F; Get (2, 1) = 0.0F; Get (2, 2) = inScale.z;
  117. return *this;
  118. }
  119. bool Matrix3x3f::IsIdentity (float threshold) {
  120. return false;
  121. }
  122. Matrix3x3f& Matrix3x3f::Scale (const Vector3f& inScale)
  123. {
  124. Get (0, 0) *= inScale.x;
  125. Get (1, 0) *= inScale.x;
  126. Get (2, 0) *= inScale.x;
  127. Get (0, 1) *= inScale.y;
  128. Get (1, 1) *= inScale.y;
  129. Get (2, 1) *= inScale.y;
  130. Get (0, 2) *= inScale.z;
  131. Get (1, 2) *= inScale.z;
  132. Get (2, 2) *= inScale.z;
  133. return *this;
  134. }
  135. float Matrix3x3f::GetDeterminant () const
  136. {
  137. float fCofactor0 = Get (0, 0) * Get (1, 1) * Get (2, 2);
  138. float fCofactor1 = Get (0, 1) * Get (1, 2) * Get (2, 0);
  139. float fCofactor2 = Get (0, 2) * Get (1, 0) * Get (2, 1);
  140. float fCofactor3 = Get (0, 2) * Get (1, 1) * Get (2, 0);
  141. float fCofactor4 = Get (0, 1) * Get (1, 0) * Get (2, 2);
  142. float fCofactor5 = Get (0, 0) * Get (1, 2) * Get (2, 1);
  143. return fCofactor0 + fCofactor1 + fCofactor2 - fCofactor3 - fCofactor4 - fCofactor5;
  144. }
  145. Matrix3x3f& Matrix3x3f::Transpose ()
  146. {
  147. swap (Get (0, 1), Get (1, 0));
  148. swap (Get (0, 2), Get (2, 0));
  149. swap (Get (2, 1), Get (1, 2));
  150. return *this;
  151. }
  152. /*
  153. Matrix3x3f& Matrix3x3f::Transpose (const Matrix3x3f& inMat)
  154. {
  155. int i;
  156. for (i=0;i<3;i++)
  157. {
  158. Get (i, 0) = inMat.Get (0, i);
  159. Get (i, 1) = inMat.Get (1, i);
  160. Get (i, 2) = inMat.Get (2, i);
  161. }
  162. return *this;
  163. }
  164. */
  165. bool Matrix3x3f::Invert ()
  166. {
  167. ///@TODO make a fast but robust inverse matrix 3x3
  168. // Matrix4x4f m = *this;
  169. // bool success = InvertMatrix4x4_Full( m.GetPtr(), m.GetPtr() );
  170. // *this = m;
  171. // return success;
  172. #if 1
  173. ////// THIS METHOD IS NUMERICALLY LESS ROBUST
  174. // Invert a 3x3 using cofactors. This is faster than using a generic
  175. // Gaussian elimination because of the loop overhead of such a method.
  176. Matrix3x3f kInverse;
  177. kInverse.Get (0, 0) = Get (1, 1) * Get (2, 2) - Get (1, 2) * Get (2, 1);
  178. kInverse.Get (0, 1) = Get (0, 2) * Get (2, 1) - Get (0, 1) * Get (2, 2);
  179. kInverse.Get (0, 2) = Get (0, 1) * Get (1, 2) - Get (0, 2) * Get (1, 1);
  180. kInverse.Get (1, 0) = Get (1, 2) * Get (2, 0) - Get (1, 0) * Get (2, 2);
  181. kInverse.Get (1, 1) = Get (0, 0) * Get (2, 2) - Get (0, 2) * Get (2, 0);
  182. kInverse.Get (1, 2) = Get (0, 2) * Get (1, 0) - Get (0, 0) * Get (1, 2);
  183. kInverse.Get (2, 0) = Get (1, 0) * Get (2, 1) - Get (1, 1) * Get (2, 0);
  184. kInverse.Get (2, 1) = Get (0, 1) * Get (2, 0) - Get (0, 0) * Get (2, 1);
  185. kInverse.Get (2, 2) = Get (0, 0) * Get (1, 1) - Get (0, 1) * Get (1, 0);
  186. float fDet = Get (0, 0) * kInverse.Get (0, 0) + Get (0, 1) * kInverse.Get (1, 0) + Get (0, 2) * kInverse.Get (2, 0);
  187. if (abs (fDet) > 0.00001F)
  188. {
  189. kInverse /= fDet;
  190. *this = kInverse;
  191. return true;
  192. }
  193. else
  194. {
  195. SetZero ();
  196. return false;
  197. }
  198. #endif
  199. }
  200. void Matrix3x3f::InvertTranspose ()
  201. {
  202. Invert ();
  203. Transpose ();
  204. }
  205. Matrix3x3f& Matrix3x3f::operator *= (float f)
  206. {
  207. for (int i=0;i<9;i++)
  208. m_Data[i] *= f;
  209. return *this;
  210. }
  211. Matrix3x3f& Matrix3x3f::operator *= (const Matrix3x3f& inM)
  212. {
  213. int i;
  214. for (i=0;i<3;i++)
  215. {
  216. float v[3] = {Get (i, 0), Get (i, 1), Get (i, 2)};
  217. Get (i, 0) = v[0] * inM.Get (0, 0) + v[1] * inM.Get (1, 0) + v[2] * inM.Get (2, 0);
  218. Get (i, 1) = v[0] * inM.Get (0, 1) + v[1] * inM.Get (1, 1) + v[2] * inM.Get (2, 1);
  219. Get (i, 2) = v[0] * inM.Get (0, 2) + v[1] * inM.Get (1, 2) + v[2] * inM.Get (2, 2);
  220. }
  221. return *this;
  222. }
  223. Matrix3x3f& Matrix3x3f::operator *= (const Matrix4x4f& inM)
  224. {
  225. int i;
  226. for (i=0;i<3;i++)
  227. {
  228. float v[3] = {Get (i, 0), Get (i, 1), Get (i, 2)};
  229. Get (i, 0) = v[0] * inM.Get (0, 0) + v[1] * inM.Get (1, 0) + v[2] * inM.Get (2, 0);
  230. Get (i, 1) = v[0] * inM.Get (0, 1) + v[1] * inM.Get (1, 1) + v[2] * inM.Get (2, 1);
  231. Get (i, 2) = v[0] * inM.Get (0, 2) + v[1] * inM.Get (1, 2) + v[2] * inM.Get (2, 2);
  232. }
  233. return *this;
  234. }
  235. Matrix3x3f& Matrix3x3f::SetAxisAngle (const Vector3f& rotationAxis, float radians)
  236. {
  237. float rotationAxisPtr[3] = {rotationAxis.x, rotationAxis.y, rotationAxis.z};
  238. GetRotMatrixNormVec (m_Data, rotationAxisPtr, radians);
  239. return *this;
  240. }
  241. void fromToRotation(const float from[3], const float to[3],float mtx[3][3]);
  242. Matrix3x3f& Matrix3x3f::SetFromToRotation (const Vector3f& from, const Vector3f& to)
  243. {
  244. float mtx[3][3];
  245. float fromPtr[3] = {from.x, from.y, from.z};
  246. float toPtr[3] = {to.x, to.y, to.z};
  247. fromToRotation (fromPtr, toPtr, mtx);
  248. Get (0, 0) = mtx[0][0]; Get (0, 1) = mtx[0][1]; Get (0, 2) = mtx[0][2];
  249. Get (1, 0) = mtx[1][0]; Get (1, 1) = mtx[1][1]; Get (1, 2) = mtx[1][2];
  250. Get (2, 0) = mtx[2][0]; Get (2, 1) = mtx[2][1]; Get (2, 2) = mtx[2][2];
  251. return *this;
  252. }
  253. inline void MakePositive (Vector3f& euler)
  254. {
  255. const float negativeFlip = -0.0001F;
  256. const float positiveFlip = (kPI * 2.0F) - 0.0001F;
  257. if (euler.x < negativeFlip)
  258. euler.x += 2.0 * kPI;
  259. else if (euler.x > positiveFlip)
  260. euler.x -= 2.0 * kPI;
  261. if (euler.y < negativeFlip)
  262. euler.y += 2.0 * kPI;
  263. else if (euler.y > positiveFlip)
  264. euler.y -= 2.0 * kPI;
  265. if (euler.z < negativeFlip)
  266. euler.z += 2.0 * kPI;
  267. else if (euler.z > positiveFlip)
  268. euler.z -= 2.0 * kPI;
  269. }
  270. inline void SanitizeEuler (Vector3f& euler)
  271. {
  272. MakePositive (euler);
  273. /*
  274. Vector3f option0 = euler;
  275. option0.x = kPI - option0.x;
  276. option0.y = kPI - option0.y;
  277. option0.z = kPI - option0.z;
  278. MakePositive (euler);
  279. MakePositive (option0);
  280. if (option0.x+option0.y+option0.z < euler.x+euler.y+euler.z)
  281. euler = option0;
  282. */
  283. }
  284. void EulerToMatrix (const Vector3f& v, Matrix3x3f& matrix)
  285. {
  286. float cx = cos (v.x);
  287. float sx = sin (v.x);
  288. float cy = cos (v.y);
  289. float sy = sin (v.y);
  290. float cz = cos (v.z);
  291. float sz = sin (v.z);
  292. matrix.Get(0,0) = cy*cz + sx*sy*sz;
  293. matrix.Get(0,1) = cz*sx*sy - cy*sz;
  294. matrix.Get(0,2) = cx*sy;
  295. matrix.Get(1,0) = cx*sz;
  296. matrix.Get(1,1) = cx*cz;
  297. matrix.Get(1,2) = -sx;
  298. matrix.Get(2,0) = -cz*sy + cy*sx*sz;
  299. matrix.Get(2,1) = cy*cz*sx + sy*sz;
  300. matrix.Get(2,2) = cx*cy;
  301. }
  302. /// This is YXZ euler conversion
  303. bool MatrixToEuler (const Matrix3x3f& matrix, Vector3f& v)
  304. {
  305. // from http://www.geometrictools.com/Documentation/EulerAngles.pdf
  306. // YXZ order
  307. if ( matrix.Get(1,2) < 0.999F ) // some fudge for imprecision
  308. {
  309. if ( matrix.Get(1,2) > -0.999F ) // some fudge for imprecision
  310. {
  311. v.x = asin(-matrix.Get(1,2));
  312. v.y = atan2(matrix.Get(0,2), matrix.Get(2,2));
  313. v.z = atan2(matrix.Get(1,0), matrix.Get(1,1));
  314. SanitizeEuler (v);
  315. return true;
  316. }
  317. else
  318. {
  319. // WARNING. Not unique. YA - ZA = atan2(r01,r00)
  320. v.x = kPI * 0.5F;
  321. v.y = atan2(matrix.Get (0,1), matrix.Get(0,0));
  322. v.z = 0.0F;
  323. SanitizeEuler (v);
  324. return false;
  325. }
  326. }
  327. else
  328. {
  329. // WARNING. Not unique. YA + ZA = atan2(-r01,r00)
  330. v.x = -kPI * 0.5F;
  331. v.y = atan2(-matrix.Get(0,1),matrix.Get(0,0));
  332. v.z = 0.0F;
  333. SanitizeEuler (v);
  334. return false;
  335. }
  336. }
  337. #define EPSILON 0.000001
  338. #define CROSS(dest,v1,v2){ \
  339. dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
  340. dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
  341. dest[2]=v1[0]*v2[1]-v1[1]*v2[0];}
  342. #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
  343. #define SUB(dest,v1,v2){ \
  344. dest[0]=v1[0]-v2[0]; \
  345. dest[1]=v1[1]-v2[1]; \
  346. dest[2]=v1[2]-v2[2];}
  347. /*
  348. * A function for creating a rotation matrix that rotates a vector called
  349. * "from" into another vector called "to".
  350. * Input : from[3], to[3] which both must be *normalized* non-zero vectors
  351. * Output: mtx[3][3] -- a 3x3 matrix in colum-major form
  352. * Author: Tomas Möller, 1999
  353. */
  354. void fromToRotation(const float* from, const float* to,float mtx[3][3])
  355. {
  356. float v[3];
  357. float e,h;
  358. CROSS(v,from,to);
  359. e=DOT(from,to);
  360. if(e>1.0-EPSILON) /* "from" almost or equal to "to"-vector? */
  361. {
  362. /* return identity */
  363. mtx[0][0]=1.0; mtx[0][1]=0.0; mtx[0][2]=0.0;
  364. mtx[1][0]=0.0; mtx[1][1]=1.0; mtx[1][2]=0.0;
  365. mtx[2][0]=0.0; mtx[2][1]=0.0; mtx[2][2]=1.0;
  366. }
  367. else if(e<-1.0+EPSILON) /* "from" almost or equal to negated "to"? */
  368. {
  369. float up[3],left[3];
  370. float invlen;
  371. float fxx,fyy,fzz,fxy,fxz,fyz;
  372. float uxx,uyy,uzz,uxy,uxz,uyz;
  373. float lxx,lyy,lzz,lxy,lxz,lyz;
  374. /* left=CROSS(from, (1,0,0)) */
  375. left[0]=0.0; left[1]=from[2]; left[2]=-from[1];
  376. if(DOT(left,left)<EPSILON) /* was left=CROSS(from,(1,0,0)) a good choice? */
  377. {
  378. /* here we now that left = CROSS(from, (1,0,0)) will be a good choice */
  379. left[0]=-from[2]; left[1]=0.0; left[2]=from[0];
  380. }
  381. /* normalize "left" */
  382. invlen=1.0f/sqrt(DOT(left,left));
  383. left[0]*=invlen;
  384. left[1]*=invlen;
  385. left[2]*=invlen;
  386. CROSS(up,left,from);
  387. /* now we have a coordinate system, i.e., a basis; */
  388. /* M=(from, up, left), and we want to rotate to: */
  389. /* N=(-from, up, -left). This is done with the matrix:*/
  390. /* N*M^T where M^T is the transpose of M */
  391. fxx=-from[0]*from[0]; fyy=-from[1]*from[1]; fzz=-from[2]*from[2];
  392. fxy=-from[0]*from[1]; fxz=-from[0]*from[2]; fyz=-from[1]*from[2];
  393. uxx=up[0]*up[0]; uyy=up[1]*up[1]; uzz=up[2]*up[2];
  394. uxy=up[0]*up[1]; uxz=up[0]*up[2]; uyz=up[1]*up[2];
  395. lxx=-left[0]*left[0]; lyy=-left[1]*left[1]; lzz=-left[2]*left[2];
  396. lxy=-left[0]*left[1]; lxz=-left[0]*left[2]; lyz=-left[1]*left[2];
  397. /* symmetric matrix */
  398. mtx[0][0]=fxx+uxx+lxx; mtx[0][1]=fxy+uxy+lxy; mtx[0][2]=fxz+uxz+lxz;
  399. mtx[1][0]=mtx[0][1]; mtx[1][1]=fyy+uyy+lyy; mtx[1][2]=fyz+uyz+lyz;
  400. mtx[2][0]=mtx[0][2]; mtx[2][1]=mtx[1][2]; mtx[2][2]=fzz+uzz+lzz;
  401. }
  402. else /* the most common case, unless "from"="to", or "from"=-"to" */
  403. {
  404. /* ...otherwise use this hand optimized version (9 mults less) */
  405. float hvx,hvz,hvxy,hvxz,hvyz;
  406. h=(1.0f-e)/DOT(v,v);
  407. hvx=h*v[0];
  408. hvz=h*v[2];
  409. hvxy=hvx*v[1];
  410. hvxz=hvx*v[2];
  411. hvyz=hvz*v[1];
  412. mtx[0][0]=e+hvx*v[0]; mtx[0][1]=hvxy-v[2]; mtx[0][2]=hvxz+v[1];
  413. mtx[1][0]=hvxy+v[2]; mtx[1][1]=e+h*v[1]*v[1]; mtx[1][2]=hvyz-v[0];
  414. mtx[2][0]=hvxz-v[1]; mtx[2][1]=hvyz+v[0]; mtx[2][2]=e+hvz*v[2];
  415. }
  416. }
  417. // Right handed
  418. bool LookRotationToMatrix (const Vector3f& viewVec, const Vector3f& upVec, Matrix3x3f* m)
  419. {
  420. Vector3f z = viewVec;
  421. // compute u0
  422. float mag = Magnitude (z);
  423. if (mag < Vector3f_Epsilon)
  424. {
  425. m->SetIdentity();
  426. return false;
  427. }
  428. z = z / mag;
  429. Vector3f x = Cross (upVec, z);
  430. mag = Magnitude (x);
  431. if (mag < Vector3f_Epsilon)
  432. {
  433. m->SetIdentity();
  434. return false;
  435. }
  436. x = x /mag;
  437. Vector3f y (Cross (z, x));
  438. if (!CompareApproximately (SqrMagnitude (y), 1.0F))
  439. return false;
  440. m->SetOrthoNormalBasis (x, y, z);
  441. return true;
  442. }
  443. /*
  444. //Left handed
  445. bool LookRotationToMatrixLeftHanded (const Vector3f& viewVec, const Vector3f& upVec, Matrix3x3f* m)
  446. {
  447. Vector3f z = viewVec;
  448. // compute u0
  449. float mag = Magnitude (z);
  450. if (mag < Vector3f::epsilon)
  451. return false;
  452. z /= mag;
  453. Vector3f x = Cross (z, upVec);
  454. mag = Magnitude (x);
  455. if (mag < Vector3f::epsilon)
  456. return false;
  457. x /= mag;
  458. Vector3f y (Cross (x, z));
  459. if (!CompareApproximately (SqrMagnitude (y), 1.0F))
  460. return false;
  461. m->SetOrthoNormalBasis (x, y, z);
  462. return true;
  463. }
  464. */
  465. void GetRotMatrixNormVec (float* out, const float* inVec, float radians)
  466. {
  467. /* This function contributed by Erich Boleyn (erich@uruk.org) */
  468. /* This function used from the Mesa OpenGL code (matrix.c) */
  469. float s, c;
  470. float vx, vy, vz, xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
  471. s = sin (radians);
  472. c = cos (radians);
  473. vx = inVec[0];
  474. vy = inVec[1];
  475. vz = inVec[2];
  476. #define M(row,col) out[row*3 + col]
  477. /*
  478. * Arbitrary axis rotation matrix.
  479. *
  480. * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
  481. * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
  482. * (which is about the X-axis), and the two composite transforms
  483. * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
  484. * from the arbitrary axis to the X-axis then back. They are
  485. * all elementary rotations.
  486. *
  487. * Rz' is a rotation about the Z-axis, to bring the axis vector
  488. * into the x-z plane. Then Ry' is applied, rotating about the
  489. * Y-axis to bring the axis vector parallel with the X-axis. The
  490. * rotation about the X-axis is then performed. Ry and Rz are
  491. * simply the respective inverse transforms to bring the arbitrary
  492. * axis back to its original orientation. The first transforms
  493. * Rz' and Ry' are considered inverses, since the data from the
  494. * arbitrary axis gives you info on how to get to it, not how
  495. * to get away from it, and an inverse must be applied.
  496. *
  497. * The basic calculation used is to recognize that the arbitrary
  498. * axis vector (x, y, z), since it is of unit length, actually
  499. * represents the sines and cosines of the angles to rotate the
  500. * X-axis to the same orientation, with theta being the angle about
  501. * Z and phi the angle about Y (in the order described above)
  502. * as follows:
  503. *
  504. * cos ( theta ) = x / sqrt ( 1 - z^2 )
  505. * sin ( theta ) = y / sqrt ( 1 - z^2 )
  506. *
  507. * cos ( phi ) = sqrt ( 1 - z^2 )
  508. * sin ( phi ) = z
  509. *
  510. * Note that cos ( phi ) can further be inserted to the above
  511. * formulas:
  512. *
  513. * cos ( theta ) = x / cos ( phi )
  514. * sin ( theta ) = y / cos ( phi )
  515. *
  516. * ...etc. Because of those relations and the standard trigonometric
  517. * relations, it is pssible to reduce the transforms down to what
  518. * is used below. It may be that any primary axis chosen will give the
  519. * same results (modulo a sign convention) using thie method.
  520. *
  521. * Particularly nice is to notice that all divisions that might
  522. * have caused trouble when parallel to certain planes or
  523. * axis go away with care paid to reducing the expressions.
  524. * After checking, it does perform correctly under all cases, since
  525. * in all the cases of division where the denominator would have
  526. * been zero, the numerator would have been zero as well, giving
  527. * the expected result.
  528. */
  529. xx = vx * vx;
  530. yy = vy * vy;
  531. zz = vz * vz;
  532. xy = vx * vy;
  533. yz = vy * vz;
  534. zx = vz * vx;
  535. xs = vx * s;
  536. ys = vy * s;
  537. zs = vz * s;
  538. one_c = 1.0F - c;
  539. M(0,0) = (one_c * xx) + c;
  540. M(1,0) = (one_c * xy) - zs;
  541. M(2,0) = (one_c * zx) + ys;
  542. M(0,1) = (one_c * xy) + zs;
  543. M(1,1) = (one_c * yy) + c;
  544. M(2,1) = (one_c * yz) - xs;
  545. M(0,2) = (one_c * zx) - ys;
  546. M(1,2) = (one_c * yz) + xs;
  547. M(2,2) = (one_c * zz) + c;
  548. #undef M
  549. }
  550. void OrthoNormalize (Matrix3x3f& matrix)
  551. {
  552. Vector3f* c0 = (Vector3f*)matrix.GetPtr () + 0;
  553. Vector3f* c1 = (Vector3f*)matrix.GetPtr () + 3;
  554. Vector3f* c2 = (Vector3f*)matrix.GetPtr () + 6;
  555. OrthoNormalize (c0, c1, c2);
  556. }
  557. Matrix4x4f& converterMatrix(Matrix4x4f& self, const Matrix3x3f& other)
  558. {
  559. self.m[0] = other.m_Data[0];
  560. self.m[1] = other.m_Data[1];
  561. self.m[2] = other.m_Data[2];
  562. self.m[3] = 0.0F;
  563. self.m[4] = other.m_Data[3];
  564. self.m[5] = other.m_Data[4];
  565. self.m[6] = other.m_Data[5];
  566. self.m[7] = 0.0F;
  567. self.m[8] = other.m_Data[6];
  568. self.m[9] = other.m_Data[7];
  569. self.m[10] = other.m_Data[8];
  570. self.m[11] = 0.0F;
  571. self.m[12] = 0.0F;
  572. self.m[13] = 0.0F;
  573. self.m[14] = 0.0F;
  574. self.m[15] = 1.0F;
  575. return self;
  576. }