Matrix4.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace BansheeEngine
  4. {
  5. [StructLayout(LayoutKind.Sequential)]
  6. public struct Matrix4
  7. {
  8. public static readonly Matrix4 zero = new Matrix4();
  9. public static readonly Matrix4 identity = new Matrix4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
  10. public float m00;
  11. public float m01;
  12. public float m02;
  13. public float m03;
  14. public float m10;
  15. public float m11;
  16. public float m12;
  17. public float m13;
  18. public float m20;
  19. public float m21;
  20. public float m22;
  21. public float m23;
  22. public float m30;
  23. public float m31;
  24. public float m32;
  25. public float m33;
  26. public Matrix4(float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13,
  27. float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33)
  28. {
  29. this.m00 = m00;
  30. this.m01 = m01;
  31. this.m02 = m02;
  32. this.m03 = m03;
  33. this.m10 = m10;
  34. this.m11 = m11;
  35. this.m12 = m12;
  36. this.m13 = m13;
  37. this.m20 = m20;
  38. this.m21 = m21;
  39. this.m22 = m22;
  40. this.m23 = m23;
  41. this.m30 = m30;
  42. this.m31 = m31;
  43. this.m32 = m32;
  44. this.m33 = m33;
  45. }
  46. public float this[int row, int column]
  47. {
  48. get
  49. {
  50. return this[row * 4 + column];
  51. }
  52. set
  53. {
  54. this[row * 4 + column] = value;
  55. }
  56. }
  57. public float this[int index]
  58. {
  59. get
  60. {
  61. switch (index)
  62. {
  63. case 0:
  64. return m00;
  65. case 1:
  66. return m01;
  67. case 2:
  68. return m02;
  69. case 3:
  70. return m03;
  71. case 4:
  72. return m10;
  73. case 5:
  74. return m11;
  75. case 6:
  76. return m12;
  77. case 7:
  78. return m13;
  79. case 8:
  80. return m20;
  81. case 9:
  82. return m21;
  83. case 10:
  84. return m22;
  85. case 11:
  86. return m23;
  87. case 12:
  88. return m30;
  89. case 13:
  90. return m31;
  91. case 14:
  92. return m32;
  93. case 15:
  94. return m33;
  95. default:
  96. throw new IndexOutOfRangeException("Invalid matrix index.");
  97. }
  98. }
  99. set
  100. {
  101. switch (index)
  102. {
  103. case 0:
  104. m00 = value;
  105. break;
  106. case 1:
  107. m01 = value;
  108. break;
  109. case 2:
  110. m02 = value;
  111. break;
  112. case 3:
  113. m03 = value;
  114. break;
  115. case 4:
  116. m10 = value;
  117. break;
  118. case 5:
  119. m11 = value;
  120. break;
  121. case 6:
  122. m12 = value;
  123. break;
  124. case 7:
  125. m13 = value;
  126. break;
  127. case 8:
  128. m20 = value;
  129. break;
  130. case 9:
  131. m21 = value;
  132. break;
  133. case 10:
  134. m22 = value;
  135. break;
  136. case 11:
  137. m23 = value;
  138. break;
  139. case 12:
  140. m30 = value;
  141. break;
  142. case 13:
  143. m31 = value;
  144. break;
  145. case 14:
  146. m32 = value;
  147. break;
  148. case 15:
  149. m33 = value;
  150. break;
  151. default:
  152. throw new IndexOutOfRangeException("Invalid matrix index.");
  153. }
  154. }
  155. }
  156. public static Matrix4 operator *(Matrix4 lhs, Matrix4 rhs)
  157. {
  158. return new Matrix4()
  159. {
  160. m00 = lhs.m00 * rhs.m00 + lhs.m01 * rhs.m10 + lhs.m02 * rhs.m20 + lhs.m03 * rhs.m30,
  161. m01 = lhs.m00 * rhs.m01 + lhs.m01 * rhs.m11 + lhs.m02 * rhs.m21 + lhs.m03 * rhs.m31,
  162. m02 = lhs.m00 * rhs.m02 + lhs.m01 * rhs.m12 + lhs.m02 * rhs.m22 + lhs.m03 * rhs.m32,
  163. m03 = lhs.m00 * rhs.m03 + lhs.m01 * rhs.m13 + lhs.m02 * rhs.m23 + lhs.m03 * rhs.m33,
  164. m10 = lhs.m10 * rhs.m00 + lhs.m11 * rhs.m10 + lhs.m12 * rhs.m20 + lhs.m13 * rhs.m30,
  165. m11 = lhs.m10 * rhs.m01 + lhs.m11 * rhs.m11 + lhs.m12 * rhs.m21 + lhs.m13 * rhs.m31,
  166. m12 = lhs.m10 * rhs.m02 + lhs.m11 * rhs.m12 + lhs.m12 * rhs.m22 + lhs.m13 * rhs.m32,
  167. m13 = lhs.m10 * rhs.m03 + lhs.m11 * rhs.m13 + lhs.m12 * rhs.m23 + lhs.m13 * rhs.m33,
  168. m20 = lhs.m20 * rhs.m00 + lhs.m21 * rhs.m10 + lhs.m22 * rhs.m20 + lhs.m23 * rhs.m30,
  169. m21 = lhs.m20 * rhs.m01 + lhs.m21 * rhs.m11 + lhs.m22 * rhs.m21 + lhs.m23 * rhs.m31,
  170. m22 = lhs.m20 * rhs.m02 + lhs.m21 * rhs.m12 + lhs.m22 * rhs.m22 + lhs.m23 * rhs.m32,
  171. m23 = lhs.m20 * rhs.m03 + lhs.m21 * rhs.m13 + lhs.m22 * rhs.m23 + lhs.m23 * rhs.m33,
  172. m30 = lhs.m30 * rhs.m00 + lhs.m31 * rhs.m10 + lhs.m32 * rhs.m20 + lhs.m33 * rhs.m30,
  173. m31 = lhs.m30 * rhs.m01 + lhs.m31 * rhs.m11 + lhs.m32 * rhs.m21 + lhs.m33 * rhs.m31,
  174. m32 = lhs.m30 * rhs.m02 + lhs.m31 * rhs.m12 + lhs.m32 * rhs.m22 + lhs.m33 * rhs.m32,
  175. m33 = lhs.m30 * rhs.m03 + lhs.m31 * rhs.m13 + lhs.m32 * rhs.m23 + lhs.m33 * rhs.m33
  176. };
  177. }
  178. public static bool operator ==(Matrix4 lhs, Matrix4 rhs)
  179. {
  180. if (lhs.m00 == rhs.m00 && lhs.m01 == rhs.m01 && lhs.m02 == rhs.m02 && lhs.m03 == rhs.m03 &&
  181. lhs.m10 == rhs.m10 && lhs.m11 == rhs.m11 && lhs.m12 == rhs.m12 && lhs.m13 == rhs.m13 &&
  182. lhs.m20 == rhs.m20 && lhs.m21 == rhs.m21 && lhs.m22 == rhs.m22 && lhs.m23 == rhs.m23 &&
  183. lhs.m30 == rhs.m30 && lhs.m31 == rhs.m31 && lhs.m32 == rhs.m32 && lhs.m33 == rhs.m33)
  184. return true;
  185. else
  186. return false;
  187. }
  188. public static bool operator !=(Matrix4 lhs, Matrix4 rhs)
  189. {
  190. return !(lhs == rhs);
  191. }
  192. public override int GetHashCode()
  193. {
  194. float hash1 = m00.GetHashCode() ^ m10.GetHashCode() << 2 ^ m20.GetHashCode() >> 2 ^ m30.GetHashCode() >> 1;
  195. float hash2 = m01.GetHashCode() ^ m11.GetHashCode() << 2 ^ m21.GetHashCode() >> 2 ^ m31.GetHashCode() >> 1;
  196. float hash3 = m02.GetHashCode() ^ m12.GetHashCode() << 2 ^ m22.GetHashCode() >> 2 ^ m32.GetHashCode() >> 1;
  197. float hash4 = m03.GetHashCode() ^ m13.GetHashCode() << 2 ^ m23.GetHashCode() >> 2 ^ m33.GetHashCode() >> 1;
  198. return hash1.GetHashCode() ^ hash2.GetHashCode() << 2 ^ hash3.GetHashCode() >> 2 ^ hash4.GetHashCode() >> 1;
  199. }
  200. public override bool Equals(object other)
  201. {
  202. if (!(other is Matrix4))
  203. return false;
  204. Matrix4 mat = (Matrix4)other;
  205. if (m00 == mat.m00 && m01 == mat.m01 && m02 == mat.m02 && m03 == mat.m03 &&
  206. m10 == mat.m10 && m11 == mat.m11 && m12 == mat.m12 && m13 == mat.m13 &&
  207. m20 == mat.m20 && m21 == mat.m21 && m22 == mat.m22 && m23 == mat.m23 &&
  208. m30 == mat.m30 && m31 == mat.m31 && m32 == mat.m32 && m33 == mat.m33)
  209. return true;
  210. else
  211. return false;
  212. }
  213. public void Invert()
  214. {
  215. float v0 = m20 * m31 - m21 * m30;
  216. float v1 = m20 * m32 - m22 * m30;
  217. float v2 = m20 * m33 - m23 * m30;
  218. float v3 = m21 * m32 - m22 * m31;
  219. float v4 = m21 * m33 - m23 * m31;
  220. float v5 = m22 * m33 - m23 * m32;
  221. float t00 = +(v5 * m11 - v4 * m12 + v3 * m13);
  222. float t10 = -(v5 * m10 - v2 * m12 + v1 * m13);
  223. float t20 = +(v4 * m10 - v2 * m11 + v0 * m13);
  224. float t30 = -(v3 * m10 - v1 * m11 + v0 * m12);
  225. float invDet = 1 / (t00 * m00 + t10 * m01 + t20 * m02 + t30 * m03);
  226. float d00 = t00 * invDet;
  227. float d10 = t10 * invDet;
  228. float d20 = t20 * invDet;
  229. float d30 = t30 * invDet;
  230. float d01 = -(v5 * m01 - v4 * m02 + v3 * m03) * invDet;
  231. float d11 = +(v5 * m00 - v2 * m02 + v1 * m03) * invDet;
  232. float d21 = -(v4 * m00 - v2 * m01 + v0 * m03) * invDet;
  233. float d31 = +(v3 * m00 - v1 * m01 + v0 * m02) * invDet;
  234. v0 = m10 * m31 - m11 * m30;
  235. v1 = m10 * m32 - m12 * m30;
  236. v2 = m10 * m33 - m13 * m30;
  237. v3 = m11 * m32 - m12 * m31;
  238. v4 = m11 * m33 - m13 * m31;
  239. v5 = m12 * m33 - m13 * m32;
  240. float d02 = +(v5 * m01 - v4 * m02 + v3 * m03) * invDet;
  241. float d12 = -(v5 * m00 - v2 * m02 + v1 * m03) * invDet;
  242. float d22 = +(v4 * m00 - v2 * m01 + v0 * m03) * invDet;
  243. float d32 = -(v3 * m00 - v1 * m01 + v0 * m02) * invDet;
  244. v0 = m21 * m10 - m20 * m11;
  245. v1 = m22 * m10 - m20 * m12;
  246. v2 = m23 * m10 - m20 * m13;
  247. v3 = m22 * m11 - m21 * m12;
  248. v4 = m23 * m11 - m21 * m13;
  249. v5 = m23 * m12 - m22 * m13;
  250. float d03 = -(v5 * m01 - v4 * m02 + v3 * m03) * invDet;
  251. float d13 = +(v5 * m00 - v2 * m02 + v1 * m03) * invDet;
  252. float d23 = -(v4 * m00 - v2 * m01 + v0 * m03) * invDet;
  253. float d33 = +(v3 * m00 - v1 * m01 + v0 * m02) * invDet;
  254. this = new Matrix4(
  255. d00, d01, d02, d03,
  256. d10, d11, d12, d13,
  257. d20, d21, d22, d23,
  258. d30, d31, d32, d33);
  259. }
  260. public void InvertAffine()
  261. {
  262. float t00 = m22 * m11 - m21 * m12;
  263. float t10 = m20 * m12 - m22 * m10;
  264. float t20 = m21 * m10 - m20 * m11;
  265. float invDet = 1 / (m00 * t00 + m01 * t10 + m02 * t20);
  266. t00 *= invDet; t10 *= invDet; t20 *= invDet;
  267. m00 *= invDet; m01 *= invDet; m02 *= invDet;
  268. float r00 = t00;
  269. float r01 = m02 * m21 - m01 * m22;
  270. float r02 = m01 * m12 - m02 * m11;
  271. float r10 = t10;
  272. float r11 = m00 * m22 - m02 * m20;
  273. float r12 = m02 * m10 - m00 * m12;
  274. float r20 = t20;
  275. float r21 = m01 * m20 - m00 * m21;
  276. float r22 = m00 * m11 - m01 * m10;
  277. float r03 = -(r00 * m03 + r01 * m13 + r02 * m23);
  278. float r13 = -(r10 * m03 + r11 * m13 + r12 * m23);
  279. float r23 = -(r20 * m03 + r21 * m13 + r22 * m23);
  280. this = new Matrix4(
  281. r00, r01, r02, r03,
  282. r10, r11, r12, r13,
  283. r20, r21, r22, r23,
  284. 0, 0, 0, 1);
  285. }
  286. public void Transpose()
  287. {
  288. float tmp = m01;
  289. m01 = m10;
  290. m10 = tmp;
  291. tmp = m02;
  292. m02 = m20;
  293. m20 = tmp;
  294. tmp = m03;
  295. m03 = m30;
  296. m30 = tmp;
  297. tmp = m12;
  298. m12 = m21;
  299. m21 = tmp;
  300. tmp = m13;
  301. m13 = m31;
  302. m31 = tmp;
  303. tmp = m23;
  304. m23 = m32;
  305. m32 = tmp;
  306. }
  307. public float Determinant()
  308. {
  309. float m1 = m11 * (m22 * m33 - m32 * m23) -
  310. m12 * (m21 * m33 - m31 * m23) +
  311. m13 * (m21 * m32 - m31 * m22);
  312. float m2 = m10 * (m22 * m33 - m32 * m23) -
  313. m12 * (m20 * m33 - m30 * m23) +
  314. m13 * (m20 * m32 - m30 * m22);
  315. float m3 = m10 * (m21 * m33 - m31 * m23) -
  316. m11 * (m20 * m33 - m30 * m23) +
  317. m13 * (m20 * m31 - m30 * m21);
  318. float m4 = m10 * (m21 * m32 - m31 * m22) -
  319. m11 * (m20 * m32 - m30 * m22) +
  320. m12 * (m20 * m31 - m30 * m21);
  321. return m00 * m1 - m01 * m2 + m02 * m3 - m03 * m4;
  322. }
  323. /**
  324. * @brief Decompose a Matrix4 to translation, rotation and scale.
  325. *
  326. * @note Matrix must consist only of translation, rotation and uniform scale transformations,
  327. * otherwise accurate results are not guaranteed. Applying non-uniform scale guarantees
  328. * results will not be accurate.
  329. */
  330. public void GetTRS(out Vector3 translation, out Quaternion rotation, out Vector3 scale)
  331. {
  332. Matrix3 m3x3 = ToMatrix3(this);
  333. Matrix3 matQ;
  334. Vector3 vecU;
  335. m3x3.QDUDecomposition(out matQ, out scale, out vecU);
  336. rotation = Quaternion.FromRotationMatrix(matQ);
  337. translation = new Vector3(m03, m13, m23);
  338. }
  339. /**
  340. * @brief Transform a 3D vector by this matrix.
  341. *
  342. * @note Matrix must be affine, if it is not use "Multiply" method.
  343. */
  344. public Vector3 Multiply3x4(Vector3 v)
  345. {
  346. return new Vector3(
  347. m00 * v.x + m01 * v.y + m02 * v.z + m03,
  348. m10 * v.x + m11 * v.y + m12 * v.z + m13,
  349. m20 * v.x + m21 * v.y + m22 * v.z + m23);
  350. }
  351. /**
  352. * @brief Transform a 4D vector by this matrix.
  353. *
  354. * @note Matrix must be affine, if it is not use "Multiply" method.
  355. */
  356. public Vector4 Multiply3x4(Vector4 v)
  357. {
  358. return new Vector4(
  359. m00 * v.x + m01 * v.y + m02 * v.z + m03 * v.w,
  360. m10 * v.x + m11 * v.y + m12 * v.z + m13 * v.w,
  361. m20 * v.x + m21 * v.y + m22 * v.z + m23 * v.w,
  362. v.w);
  363. }
  364. /**
  365. * @brief Transform a 3D vector by this matrix.
  366. *
  367. * @note w component of the vector is assumed to be 1. After transformation all components
  368. * are projected back so that w remains 1.
  369. *
  370. * If your matrix doesn't contain projection components use "Multiply3x4" method as it is faster.
  371. */
  372. public Vector3 Multiply(Vector3 v)
  373. {
  374. Vector3 r = new Vector3();
  375. float fInvW = 1.0f / (m30 * v.x + m31 * v.y + m32 * v.z + m33);
  376. r.x = (m00 * v.x + m01 * v.y + m02 * v.z + m03) * fInvW;
  377. r.y = (m10 * v.x + m11 * v.y + m12 * v.z + m13) * fInvW;
  378. r.z = (m20 * v.x + m21 * v.y + m22 * v.z + m23) * fInvW;
  379. return r;
  380. }
  381. /**
  382. * @brief Transform a 3D vector by this matrix.
  383. *
  384. * @note After transformation all components are projected back so that w remains 1.
  385. *
  386. * If your matrix doesn't contain projection components use "Multiply3x4" method as it is faster.
  387. */
  388. public Vector4 Multiply(Vector4 v)
  389. {
  390. return new Vector4(
  391. m00 * v.x + m01 * v.y + m02 * v.z + m03 * v.w,
  392. m10 * v.x + m11 * v.y + m12 * v.z + m13 * v.w,
  393. m20 * v.x + m21 * v.y + m22 * v.z + m23 * v.w,
  394. m30 * v.x + m31 * v.y + m32 * v.z + m33 * v.w);
  395. }
  396. public static Matrix4 TRS(Vector3 translation, Quaternion rotation, Vector3 scale)
  397. {
  398. Matrix3 rot3x3 = rotation.ToRotationMatrix();
  399. Matrix4 mat = new Matrix4();
  400. mat.m00 = scale.x * rot3x3.m00; mat.m01 = scale.y * rot3x3.m01; mat.m02 = scale.z * rot3x3.m02; mat.m03 = translation.x;
  401. mat.m10 = scale.x * rot3x3.m10; mat.m11 = scale.y * rot3x3.m11; mat.m12 = scale.z * rot3x3.m12; mat.m13 = translation.y;
  402. mat.m20 = scale.x * rot3x3.m20; mat.m21 = scale.y * rot3x3.m21; mat.m22 = scale.z * rot3x3.m22; mat.m23 = translation.z;
  403. // No projection term
  404. mat.m30 = 0; mat.m31 = 0; mat.m32 = 0; mat.m33 = 1;
  405. return mat;
  406. }
  407. public static Matrix3 ToMatrix3(Matrix4 mat)
  408. {
  409. return new Matrix3(
  410. mat.m00, mat.m01, mat.m02,
  411. mat.m10, mat.m11, mat.m12,
  412. mat.m20, mat.m21, mat.m22);
  413. }
  414. public static Matrix4 Inverse(Matrix4 mat)
  415. {
  416. Matrix4 copy = mat;
  417. copy.Invert();
  418. return copy;
  419. }
  420. public static Matrix4 InverseAffine(Matrix4 mat)
  421. {
  422. Matrix4 copy = mat;
  423. copy.InvertAffine();
  424. return copy;
  425. }
  426. public static Matrix4 Transpose(Matrix4 mat)
  427. {
  428. Matrix4 copy = mat;
  429. copy.Transpose();
  430. return copy;
  431. }
  432. }
  433. }