Matrix3.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. using System;
  4. using System.Runtime.InteropServices;
  5. namespace BansheeEngine
  6. {
  7. /** @addtogroup Math
  8. * @{
  9. */
  10. /// <summary>
  11. /// A 3x3 matrix. Can be used for non-homogenous transformations of three dimensional vectors and points.
  12. /// </summary>
  13. [StructLayout(LayoutKind.Sequential), SerializeObject]
  14. public struct Matrix3 // Note: Must match C++ class Matrix3
  15. {
  16. /// <summary>
  17. /// Contains constant data that is used when calculating euler angles in a certain order.
  18. /// </summary>
  19. private struct EulerAngleOrderData
  20. {
  21. public EulerAngleOrderData(int a, int b, int c, float sign)
  22. {
  23. this.a = a;
  24. this.b = b;
  25. this.c = c;
  26. this.sign = sign;
  27. }
  28. public int a, b, c;
  29. public float sign;
  30. };
  31. private static EulerAngleOrderData[] EA_LOOKUP =
  32. { new EulerAngleOrderData(0, 1, 2, 1.0f), new EulerAngleOrderData(0, 2, 1, -1.0f), new EulerAngleOrderData(1, 0, 2, -1.0f),
  33. new EulerAngleOrderData(1, 2, 0, 1.0f), new EulerAngleOrderData(2, 0, 1, 1.0f), new EulerAngleOrderData(2, 1, 0, -1.0f) };
  34. /// <summary>
  35. /// A matrix with all zero values.
  36. /// </summary>
  37. public static readonly Matrix3 Zero = new Matrix3();
  38. /// <summary>
  39. /// Identity matrix.
  40. /// </summary>
  41. public static readonly Matrix3 Identity = new Matrix3(1, 0, 0, 0, 1, 0, 0, 0, 1);
  42. public float m00;
  43. public float m01;
  44. public float m02;
  45. public float m10;
  46. public float m11;
  47. public float m12;
  48. public float m20;
  49. public float m21;
  50. public float m22;
  51. /// <summary>
  52. /// Creates a new matrix with the specified elements.
  53. /// </summary>
  54. public Matrix3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22)
  55. {
  56. this.m00 = m00;
  57. this.m01 = m01;
  58. this.m02 = m02;
  59. this.m10 = m10;
  60. this.m11 = m11;
  61. this.m12 = m12;
  62. this.m20 = m20;
  63. this.m21 = m21;
  64. this.m22 = m22;
  65. }
  66. /// <summary>
  67. /// Value of the specified element in the matrix.
  68. /// </summary>
  69. /// <param name="row">Row index of the element to retrieve.</param>
  70. /// <param name="column">Column index of the element to retrieve.</param>
  71. /// <returns>Value of the element.</returns>
  72. public float this[int row, int column]
  73. {
  74. get
  75. {
  76. return this[row * 3 + column];
  77. }
  78. set
  79. {
  80. this[row * 3 + column] = value;
  81. }
  82. }
  83. /// <summary>
  84. /// Value of the specified element in the matrix using a linear index.
  85. /// Linear index can be calculated using the following formula: idx = row * 3 + column.
  86. /// </summary>
  87. /// <param name="index">Linear index to get the value of.</param>
  88. /// <returns>Value of the element.</returns>
  89. public float this[int index]
  90. {
  91. get
  92. {
  93. switch (index)
  94. {
  95. case 0:
  96. return m00;
  97. case 1:
  98. return m01;
  99. case 2:
  100. return m02;
  101. case 3:
  102. return m10;
  103. case 4:
  104. return m11;
  105. case 5:
  106. return m12;
  107. case 6:
  108. return m20;
  109. case 7:
  110. return m21;
  111. case 8:
  112. return m22;
  113. default:
  114. throw new IndexOutOfRangeException("Invalid matrix index.");
  115. }
  116. }
  117. set
  118. {
  119. switch (index)
  120. {
  121. case 0:
  122. m00 = value;
  123. break;
  124. case 1:
  125. m01 = value;
  126. break;
  127. case 2:
  128. m02 = value;
  129. break;
  130. case 3:
  131. m10 = value;
  132. break;
  133. case 4:
  134. m11 = value;
  135. break;
  136. case 5:
  137. m12 = value;
  138. break;
  139. case 6:
  140. m20 = value;
  141. break;
  142. case 7:
  143. m21 = value;
  144. break;
  145. case 8:
  146. m22 = value;
  147. break;
  148. default:
  149. throw new IndexOutOfRangeException("Invalid matrix index.");
  150. }
  151. }
  152. }
  153. public static Matrix3 operator *(Matrix3 lhs, Matrix3 rhs)
  154. {
  155. return new Matrix3()
  156. {
  157. m00 = lhs.m00 * rhs.m00 + lhs.m01 * rhs.m10 + lhs.m02 * rhs.m20,
  158. m01 = lhs.m00 * rhs.m01 + lhs.m01 * rhs.m11 + lhs.m02 * rhs.m21,
  159. m02 = lhs.m00 * rhs.m02 + lhs.m01 * rhs.m12 + lhs.m02 * rhs.m22,
  160. m10 = lhs.m10 * rhs.m00 + lhs.m11 * rhs.m10 + lhs.m12 * rhs.m20,
  161. m11 = lhs.m10 * rhs.m01 + lhs.m11 * rhs.m11 + lhs.m12 * rhs.m21,
  162. m12 = lhs.m10 * rhs.m02 + lhs.m11 * rhs.m12 + lhs.m12 * rhs.m22,
  163. m20 = lhs.m20 * rhs.m00 + lhs.m21 * rhs.m10 + lhs.m22 * rhs.m20,
  164. m21 = lhs.m20 * rhs.m01 + lhs.m21 * rhs.m11 + lhs.m22 * rhs.m21,
  165. m22 = lhs.m20 * rhs.m02 + lhs.m21 * rhs.m12 + lhs.m22 * rhs.m22,
  166. };
  167. }
  168. public static bool operator== (Matrix3 lhs, Matrix3 rhs)
  169. {
  170. if (lhs.m00 == rhs.m00 && lhs.m01 == rhs.m01 && lhs.m02 == rhs.m02 &&
  171. lhs.m10 == rhs.m10 && lhs.m11 == rhs.m11 && lhs.m12 == rhs.m12 &&
  172. lhs.m20 == rhs.m20 && lhs.m21 == rhs.m21 && lhs.m22 == rhs.m22)
  173. return true;
  174. else
  175. return false;
  176. }
  177. public static bool operator !=(Matrix3 lhs, Matrix3 rhs)
  178. {
  179. return !(lhs == rhs);
  180. }
  181. /// <inheritdoc/>
  182. public override int GetHashCode()
  183. {
  184. float hash1 = m00.GetHashCode() ^ m10.GetHashCode() << 2 ^ m20.GetHashCode() >> 2;
  185. float hash2 = m01.GetHashCode() ^ m11.GetHashCode() << 2 ^ m21.GetHashCode() >> 2;
  186. float hash3 = m02.GetHashCode() ^ m12.GetHashCode() << 2 ^ m22.GetHashCode() >> 2;
  187. return hash1.GetHashCode() ^ hash2.GetHashCode() << 2 ^ hash3.GetHashCode() >> 2;
  188. }
  189. /// <inheritdoc/>
  190. public override bool Equals(object other)
  191. {
  192. if (!(other is Matrix3))
  193. return false;
  194. Matrix3 mat = (Matrix3)other;
  195. if (m00 == mat.m00 && m01 == mat.m01 && m02 == mat.m02 &&
  196. m10 == mat.m10 && m11 == mat.m11 && m12 == mat.m12 &&
  197. m20 == mat.m20 && m21 == mat.m21 && m22 == mat.m22)
  198. return true;
  199. else
  200. return false;
  201. }
  202. /// <summary>
  203. /// Calculates an inverse of the matrix if it exists.
  204. /// </summary>
  205. public void Invert()
  206. {
  207. float[,] invVals = new float[3,3];
  208. invVals[0, 0] = m11 * m22 - m12 * m21;
  209. invVals[1, 0] = m12 * m20 - m10 * m22;
  210. invVals[2, 0] = m10 * m21 - m11 * m20;
  211. float det = m00 * invVals[0, 0] + m01 * invVals[1, 0] + m02 * invVals[2, 0];
  212. if (MathEx.Abs(det) <= 1e-06f)
  213. throw new DivideByZeroException("Matrix determinant is zero. Cannot invert.");
  214. invVals[0, 1] = m02 * m21 - m01 * m22;
  215. invVals[0, 2] = m01 * m12 - m02 * m11;
  216. invVals[1, 1] = m00 * m22 - m02 * m20;
  217. invVals[1, 2] = m02 * m10 - m00 * m12;
  218. invVals[2, 1] = m01 * m20 - m00 * m21;
  219. invVals[2, 2] = m00 * m11 - m01 * m10;
  220. float invDet = 1.0f/det;
  221. for (int row = 0; row < 3; row++)
  222. {
  223. for (int col = 0; col < 3; col++)
  224. invVals[row, col] *= invDet;
  225. }
  226. }
  227. /// <summary>
  228. /// Returns a transpose of the matrix (switched columns and rows).
  229. /// </summary>
  230. public void Transpose()
  231. {
  232. float tmp = m10;
  233. m10 = m01;
  234. m01 = tmp;
  235. tmp = m20;
  236. m20 = m02;
  237. m02 = tmp;
  238. tmp = m12;
  239. m12 = m21;
  240. m21 = tmp;
  241. }
  242. /// <summary>
  243. /// Calculates the matrix determinant.
  244. /// </summary>
  245. /// <returns>Determinant of the matrix.</returns>
  246. public float Determinant()
  247. {
  248. float cofactor00 = m11 * m22 - m12 * m21;
  249. float cofactor10 = m12 * m20 - m10 * m22;
  250. float cofactor20 = m10 * m21 - m11 * m20;
  251. float det = m00 * cofactor00 + m01 * cofactor10 + m02 * cofactor20;
  252. return det;
  253. }
  254. /// <summary>
  255. /// Transforms the given vector by this matrix and returns the newly transformed vector.
  256. /// </summary>
  257. /// <param name="vec">Three dimensional vector to transform.</param>
  258. /// <returns>Vector transformed by the matrix.</returns>
  259. public Vector3 Transform(Vector3 vec)
  260. {
  261. Vector3 outVec;
  262. outVec.x = m00 * vec.x + m01 * vec.y + m02 * vec.z;
  263. outVec.y = m10 * vec.x + m11 * vec.y + m12 * vec.z;
  264. outVec.z = m20 * vec.x + m21 * vec.y + m22 * vec.z;
  265. return outVec;
  266. }
  267. /// <summary>
  268. /// Decomposes the matrix into a set of values.
  269. /// </summary>
  270. /// <param name="matQ">Columns form orthonormal bases. If your matrix is affine and doesn't use non-uniform scaling
  271. /// this matrix will be the rotation part of the matrix.
  272. /// </param>
  273. /// <param name="vecD">If the matrix is affine these will be scaling factors of the matrix.</param>
  274. /// <param name="vecU">If the matrix is affine these will be shear factors of the matrix.</param>
  275. public void QDUDecomposition(out Matrix3 matQ, out Vector3 vecD, out Vector3 vecU)
  276. {
  277. matQ = new Matrix3();
  278. vecD = new Vector3();
  279. vecU = new Vector3();
  280. // Build orthogonal matrix Q
  281. float invLength = MathEx.InvSqrt(m00*m00 + m10*m10 + m20*m20);
  282. matQ.m00 = m00*invLength;
  283. matQ.m10 = m10*invLength;
  284. matQ.m20 = m20*invLength;
  285. float dot = matQ.m00*m01 + matQ.m10*m11 + matQ.m20*m21;
  286. matQ.m01 = m01-dot*matQ.m00;
  287. matQ.m11 = m11-dot*matQ.m10;
  288. matQ.m21 = m21-dot*matQ.m20;
  289. invLength = MathEx.InvSqrt(matQ.m01*matQ.m01 + matQ.m11*matQ.m11 + matQ.m21*matQ.m21);
  290. matQ.m01 *= invLength;
  291. matQ.m11 *= invLength;
  292. matQ.m21 *= invLength;
  293. dot = matQ.m00*m02 + matQ.m10*m12 + matQ.m20*m22;
  294. matQ.m02 = m02-dot*matQ.m00;
  295. matQ.m12 = m12-dot*matQ.m10;
  296. matQ.m22 = m22-dot*matQ.m20;
  297. dot = matQ.m01*m02 + matQ.m11*m12 + matQ.m21*m22;
  298. matQ.m02 -= dot*matQ.m01;
  299. matQ.m12 -= dot*matQ.m11;
  300. matQ.m22 -= dot*matQ.m21;
  301. invLength = MathEx.InvSqrt(matQ.m02*matQ.m02 + matQ.m12*matQ.m12 + matQ.m22*matQ.m22);
  302. matQ.m02 *= invLength;
  303. matQ.m12 *= invLength;
  304. matQ.m22 *= invLength;
  305. // Guarantee that orthogonal matrix has determinant 1 (no reflections)
  306. float fDet = matQ.m00*matQ.m11*matQ.m22 + matQ.m01*matQ.m12*matQ.m20 +
  307. matQ.m02*matQ.m10*matQ.m21 - matQ.m02*matQ.m11*matQ.m20 -
  308. matQ.m01*matQ.m10*matQ.m22 - matQ.m00*matQ.m12*matQ.m21;
  309. if (fDet < 0.0f)
  310. {
  311. matQ.m00 = -matQ.m00;
  312. matQ.m01 = -matQ.m01;
  313. matQ.m02 = -matQ.m02;
  314. matQ.m10 = -matQ.m10;
  315. matQ.m11 = -matQ.m11;
  316. matQ.m12 = -matQ.m12;
  317. matQ.m20 = -matQ.m20;
  318. matQ.m21 = -matQ.m21;
  319. matQ.m21 = -matQ.m22;
  320. }
  321. // Build "right" matrix R
  322. Matrix3 matRight = new Matrix3();
  323. matRight.m00 = matQ.m00 * m00 + matQ.m10 * m10 + matQ.m20 * m20;
  324. matRight.m01 = matQ.m00 * m01 + matQ.m10 * m11 + matQ.m20 * m21;
  325. matRight.m11 = matQ.m01 * m01 + matQ.m11 * m11 + matQ.m21 * m21;
  326. matRight.m02 = matQ.m00 * m02 + matQ.m10 * m12 + matQ.m20 * m22;
  327. matRight.m12 = matQ.m01 * m02 + matQ.m11 * m12 + matQ.m21 * m22;
  328. matRight.m22 = matQ.m02 * m02 + matQ.m12 * m12 + matQ.m22 * m22;
  329. // The scaling component
  330. vecD[0] = matRight.m00;
  331. vecD[1] = matRight.m11;
  332. vecD[2] = matRight.m22;
  333. // The shear component
  334. float invD0 = 1.0f/vecD[0];
  335. vecU[0] = matRight.m01 * invD0;
  336. vecU[1] = matRight.m02 * invD0;
  337. vecU[2] = matRight.m12 / vecD[1];
  338. }
  339. /// <summary>
  340. /// Converts an orthonormal matrix to euler angle (pitch/yaw/roll) representation.
  341. /// </summary>
  342. /// <returns>Euler angles in degrees representing the rotation in this matrix.</returns>
  343. public Vector3 ToEulerAngles()
  344. {
  345. Radian xAngle = -MathEx.Asin(this[1, 2]);
  346. if (xAngle < MathEx.HalfPi)
  347. {
  348. if (xAngle > -MathEx.HalfPi)
  349. {
  350. Radian yAngle = MathEx.Atan2(this[0, 2], this[2, 2]);
  351. Radian zAngle = MathEx.Atan2(this[1, 0], this[1, 1]);
  352. return new Vector3(xAngle.Degrees, yAngle.Degrees, zAngle.Degrees);
  353. }
  354. else
  355. {
  356. // Note: Not an unique solution.
  357. xAngle = -MathEx.HalfPi;
  358. Radian yAngle = MathEx.Atan2(-this[0, 1], this[0, 0]);
  359. Radian zAngle = (Radian)0.0f;
  360. return new Vector3(xAngle.Degrees, yAngle.Degrees, zAngle.Degrees);
  361. }
  362. }
  363. else
  364. {
  365. // Note: Not an unique solution.
  366. xAngle = MathEx.HalfPi;
  367. Radian yAngle = MathEx.Atan2(this[0, 1], this[0, 0]);
  368. Radian zAngle = (Radian)0.0f;
  369. return new Vector3(xAngle.Degrees, yAngle.Degrees, zAngle.Degrees);
  370. }
  371. }
  372. /// <summary>
  373. /// Converts an orthonormal matrix to quaternion representation.
  374. /// </summary>
  375. /// <returns>Quaternion representing the rotation in this matrix.</returns>
  376. public Quaternion ToQuaternion()
  377. {
  378. return Quaternion.FromRotationMatrix(this);
  379. }
  380. /// <summary>
  381. /// Converts an orthonormal matrix to axis angle representation.
  382. /// </summary>
  383. /// <param name="axis">Axis around which the rotation is performed.</param>
  384. /// <param name="angle">Amount of rotation.</param>
  385. public void ToAxisAngle(out Vector3 axis, out Degree angle)
  386. {
  387. float trace = m00 + m11 + m22;
  388. float cos = 0.5f*(trace-1.0f);
  389. Radian radians = (Radian)MathEx.Acos(cos); // In [0, PI]
  390. angle = radians;
  391. if (radians > (Radian)0.0f)
  392. {
  393. if (radians < MathEx.Pi)
  394. {
  395. axis.x = m21 - m12;
  396. axis.y = m02 - m20;
  397. axis.z = m10 - m01;
  398. axis.Normalize();
  399. }
  400. else
  401. {
  402. // Angle is PI
  403. float halfInverse;
  404. if (m00 >= m11)
  405. {
  406. // r00 >= r11
  407. if (m00 >= m22)
  408. {
  409. // r00 is maximum diagonal term
  410. axis.x = 0.5f*MathEx.Sqrt(m00 - m11 - m22 + 1.0f);
  411. halfInverse = 0.5f/axis.x;
  412. axis.y = halfInverse*m01;
  413. axis.z = halfInverse*m02;
  414. }
  415. else
  416. {
  417. // r22 is maximum diagonal term
  418. axis.z = 0.5f*MathEx.Sqrt(m22 - m00 - m11 + 1.0f);
  419. halfInverse = 0.5f/axis.z;
  420. axis.x = halfInverse*m02;
  421. axis.y = halfInverse*m12;
  422. }
  423. }
  424. else
  425. {
  426. // r11 > r00
  427. if (m11 >= m22)
  428. {
  429. // r11 is maximum diagonal term
  430. axis.y = 0.5f*MathEx.Sqrt(m11 - m00 - m22 + 1.0f);
  431. halfInverse = 0.5f/axis.y;
  432. axis.x = halfInverse*m01;
  433. axis.z = halfInverse*m12;
  434. }
  435. else
  436. {
  437. // r22 is maximum diagonal term
  438. axis.z = 0.5f*MathEx.Sqrt(m22 - m00 - m11 + 1.0f);
  439. halfInverse = 0.5f/axis.z;
  440. axis.x = halfInverse*m02;
  441. axis.y = halfInverse*m12;
  442. }
  443. }
  444. }
  445. }
  446. else
  447. {
  448. // The angle is 0 and the matrix is the identity. Any axis will
  449. // work, so just use the x-axis.
  450. axis.x = 1.0f;
  451. axis.y = 0.0f;
  452. axis.z = 0.0f;
  453. }
  454. }
  455. /// <summary>
  456. /// Calculates the inverse of the matrix if it exists.
  457. /// </summary>
  458. /// <param name="mat">Matrix to calculate the inverse of.</param>
  459. /// <returns>Inverse of the matrix.</returns>
  460. public static Matrix3 Inverse(Matrix3 mat)
  461. {
  462. Matrix3 copy = mat;
  463. copy.Invert();
  464. return copy;
  465. }
  466. /// <summary>
  467. /// Calculates the transpose of the matrix.
  468. /// </summary>
  469. /// <param name="mat">Matrix to calculate the transpose of.</param>
  470. /// <returns>Transpose of the matrix.</returns>
  471. public static Matrix3 Transpose(Matrix3 mat)
  472. {
  473. Matrix3 copy = mat;
  474. copy.Transpose();
  475. return copy;
  476. }
  477. /// <summary>
  478. /// Creates a rotation matrix from the provided euler angle (pitch/yaw/roll) rotation.
  479. /// </summary>
  480. /// <param name="euler">Euler angles in degrees.</param>
  481. /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
  482. /// on the order.</param>
  483. /// <returns>Rotation matrix that can rotate an object to the specified angles.</returns>
  484. public static Matrix3 FromEuler(Vector3 euler, EulerAngleOrder order)
  485. {
  486. return FromEuler(new Degree(euler.x), new Degree(euler.y), new Degree(euler.y), order);
  487. }
  488. /// <summary>
  489. /// Creates a rotation matrix from the provided euler angle (pitch/yaw/roll) rotation.
  490. /// </summary>
  491. /// <param name="xAngle">Pitch angle of rotation.</param>
  492. /// <param name="yAngle">Yar angle of rotation.</param>
  493. /// <param name="zAngle">Roll angle of rotation.</param>
  494. /// <param name="order">The order in which rotations will be applied. Different rotations can be created depending
  495. /// on the order.</param>
  496. /// <returns>Rotation matrix that can rotate an object to the specified angles.</returns>
  497. public static Matrix3 FromEuler(Radian xAngle, Radian yAngle, Radian zAngle, EulerAngleOrder order)
  498. {
  499. EulerAngleOrderData l = EA_LOOKUP[(int)order];
  500. Matrix3[] mats = new Matrix3[3];
  501. float cx = MathEx.Cos(xAngle);
  502. float sx = MathEx.Sin(xAngle);
  503. mats[0] = new Matrix3(
  504. 1.0f, 0.0f, 0.0f,
  505. 0.0f, cx, -sx,
  506. 0.0f, sx, cx);
  507. float cy = MathEx.Cos(yAngle);
  508. float sy = MathEx.Sin(yAngle);
  509. mats[1] = new Matrix3(
  510. cy, 0.0f, sy,
  511. 0.0f, 1.0f, 0.0f,
  512. -sy, 0.0f, cy);
  513. float cz = MathEx.Cos(zAngle);
  514. float sz = MathEx.Sin(zAngle);
  515. mats[2] = new Matrix3(
  516. cz, -sz, 0.0f,
  517. sz, cz, 0.0f,
  518. 0.0f, 0.0f, 1.0f);
  519. return mats[l.a]*(mats[l.b]*mats[l.c]);
  520. }
  521. /// <summary>
  522. /// Creates a rotation matrix from the provided euler angle (pitch/yaw/roll) rotation. Angles are applied in YXZ
  523. /// order.
  524. /// </summary>
  525. /// <param name="euler">Euler angles in degrees.</param>
  526. /// <returns>Rotation matrix that can rotate an object to the specified angles.</returns>
  527. public static Matrix3 FromEuler(Vector3 euler)
  528. {
  529. return FromEuler(new Degree(euler.x), new Degree(euler.y), new Degree(euler.y));
  530. }
  531. /// <summary>
  532. /// Creates a rotation matrix from the provided euler angle (pitch/yaw/roll) rotation. Angles are applied in YXZ
  533. /// order.
  534. /// </summary>
  535. /// <param name="xAngle">Pitch angle of rotation.</param>
  536. /// <param name="yAngle">Yar angle of rotation.</param>
  537. /// <param name="zAngle">Roll angle of rotation.</param>
  538. /// <returns>Rotation matrix that can rotate an object to the specified angles.</returns>
  539. public static Matrix3 FromEuler(Radian xAngle, Radian yAngle, Radian zAngle)
  540. {
  541. Matrix3 m = new Matrix3();
  542. float cx = MathEx.Cos(xAngle);
  543. float sx = MathEx.Sin(xAngle);
  544. float cy = MathEx.Cos(yAngle);
  545. float sy = MathEx.Sin(yAngle);
  546. float cz = MathEx.Cos(zAngle);
  547. float sz = MathEx.Sin(zAngle);
  548. m[0, 0] = cy * cz + sx * sy * sz;
  549. m[0, 1] = cz * sx * sy - cy * sz;
  550. m[0, 2] = cx * sy;
  551. m[1, 0] = cx * sz;
  552. m[1, 1] = cx * cz;
  553. m[1, 2] = -sx;
  554. m[2, 0] = -cz * sy + cy * sx * sz;
  555. m[2, 1] = cy * cz * sx + sy * sz;
  556. m[2, 2] = cx * cy;
  557. return m;
  558. }
  559. /// <summary>
  560. /// Creates a rotation matrix from axis/angle rotation.
  561. /// </summary>
  562. /// <param name="axis">Axis around which the rotation is performed.</param>
  563. /// <param name="angle">Amount of rotation.</param>
  564. /// <returns>Rotation matrix that can rotate an object around the specified axis for the specified amount.</returns>
  565. public static Matrix3 FromAxisAngle(Vector3 axis, Degree angle)
  566. {
  567. Matrix3 mat;
  568. float cos = MathEx.Cos(angle);
  569. float sin = MathEx.Sin(angle);
  570. float oneMinusCos = 1.0f - cos;
  571. float x2 = axis.x * axis.x;
  572. float y2 = axis.y * axis.y;
  573. float z2 = axis.z * axis.z;
  574. float xym = axis.x * axis.y * oneMinusCos;
  575. float xzm = axis.x * axis.z * oneMinusCos;
  576. float yzm = axis.y * axis.z * oneMinusCos;
  577. float xSin = axis.x * sin;
  578. float ySin = axis.y * sin;
  579. float zSin = axis.z * sin;
  580. mat.m00 = x2 * oneMinusCos + cos;
  581. mat.m01 = xym - zSin;
  582. mat.m02 = xzm + ySin;
  583. mat.m10 = xym + zSin;
  584. mat.m11 = y2 * oneMinusCos + cos;
  585. mat.m12 = yzm - xSin;
  586. mat.m20 = xzm - ySin;
  587. mat.m21 = yzm + xSin;
  588. mat.m22 = z2 * oneMinusCos + cos;
  589. return mat;
  590. }
  591. /// <summary>
  592. /// Creates a rotation matrix from a quaternion rotation.
  593. /// </summary>
  594. /// <param name="quat">Quaternion to create the matrix from.</param>
  595. /// <returns>Rotation matrix containing the equivalent rotation of the provided quaternion.</returns>
  596. public static Matrix3 FromQuaternion(Quaternion quat)
  597. {
  598. return quat.ToRotationMatrix();
  599. }
  600. /// <inheritdoc/>
  601. public override string ToString()
  602. {
  603. return String.Format("({0}, {1}, {2},\n{3}, {4}, {5}\n{6}, {7}, {8})",
  604. m00, m01, m02, m10, m11, m12, m20, m21, m22);
  605. }
  606. }
  607. /** @} */
  608. }