PageRenderTime 59ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/Utilities/Datatypes/Matrix.cs

#
C# | 1820 lines | 1114 code | 118 blank | 588 comment | 86 complexity | 02a0f05e85a992c0b9fa7d8b4153d0c5 MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.IO;
  3. using System.Runtime.InteropServices;
  4. using Delta.Utilities.Helpers;
  5. using Delta.Utilities.Profiling;
  6. using NUnit.Framework;
  7. // Disable warnings for some tests where we don't use created values
  8. #pragma warning disable 219
  9. // Disable the obsolete warnings for Matrix.Multiply here, it is optimized
  10. // already here and when it is not in some unit test, its ok too.
  11. #pragma warning disable 618
  12. namespace Delta.Utilities.Datatypes
  13. {
  14. /// <summary>
  15. /// Matrix struct, used mostly for 3D calculations. If possible this shares
  16. /// all the functionality of the XNA Matrix struct (if we are compiling
  17. /// only). In case we do not compile with XNA or SlimDX enabled (like on
  18. /// this class still provides all the basic functionality as a fallback. It
  19. /// might not be as optimized as some specialized xna code paths for the
  20. /// Xbox 360, but those only work on the XNA define and platform anyway.
  21. /// </summary>
  22. /// <remarks>
  23. /// Represents a row based matrix. Good wiki page about the coordinate
  24. /// system (right handed):
  25. /// http://en.wikipedia.org/wiki/Cartesian_coordinate_system
  26. /// <para />
  27. /// Note: This Matrix class was heavily profiled and optimized with help of
  28. /// the MatrixPerformance helper class included here. Many code paths
  29. /// are platform and framework dependant, this is why this class is so huge,
  30. /// but since this is very low level and highly performance critical, it is
  31. /// well worth the complexity and effort (the class is still easy to use).
  32. /// On the Xbox we will always try to use XNA implementation for performance
  33. /// critical methods, all other platforms are mostly implemented by us
  34. /// after testing performance. You can also checkout the SlimDX math classes,
  35. /// which mostly are just C#, only certain heavy methods like multiplying
  36. /// an array of matrices uses PInvoke to D3DXMatrixMultiply for example.
  37. /// <para />
  38. /// There are still performance improvements possible for this class
  39. /// like using ref for most performance critical methods like Invert,
  40. /// Multiply and most other operators, but that makes this class much harder
  41. /// to use and we can still do code-optimizations directly with the exposed
  42. /// data when needed (e.g. Bone Matrix code should be heavily optimized if
  43. /// it has to run on CPU). Currently this is fixed by marking slow methods
  44. /// as obsolete, which will give you compiler warnings, use the ref
  45. /// overload methods instead.
  46. /// <para />
  47. /// Also note that many methods are not faster by using the native XNA,
  48. /// OpenTK or SharpDX or SlimDX code paths, especially when just assigning
  49. /// values (where our code is almost always faster). But remember when any
  50. /// framework is using special tricks like low level assembly code or native
  51. /// code to calculate complex math operations, it can be faster and will be
  52. /// replaced by the build system automatically. If you notice any method
  53. /// that should be faster, contact us immediately so we can investigate!
  54. /// </remarks>
  55. [Serializable]
  56. [StructLayout(LayoutKind.Explicit)]
  57. public struct Matrix : ISaveLoadBinary, IEquatable<Matrix>
  58. {
  59. #region Constants
  60. /// <summary>
  61. /// Represents the number of values of that Matrix struct (here 4x4 = 16).
  62. /// </summary>
  63. public const int ValueCount = 16;
  64. /// <summary>
  65. /// Returns a zeroed matrix.
  66. /// </summary>
  67. public static readonly Matrix Zero = new Matrix(
  68. 0, 0, 0, 0,
  69. 0, 0, 0, 0,
  70. 0, 0, 0, 0,
  71. 0, 0, 0, 0);
  72. #endregion
  73. #region Invert (Static)
  74. /// <summary>
  75. /// Invert matrix, this is only slightly faster on the xna platform
  76. /// specific implementation, for performance critical code use the ref
  77. /// version!
  78. /// </summary>
  79. /// <param name="a">Matrix to invert</param>
  80. /// <returns>Inverted Matrix</returns>
  81. public static Matrix Invert(Matrix a)
  82. {
  83. //Check performance difference again:
  84. //Note: Performance results from 10 million calls:
  85. //Delta: 1962ms
  86. //XNA: 1076ms
  87. //OpenTK: 8611ms
  88. //SlimDX: 981ms
  89. // Ugly code that is actually lots faster than our clean implementation
  90. // below (see link on how it works basically). This is basically getting
  91. // the Determinant and then also calculating the inverse matrix in one
  92. // big ugly swoop.
  93. float m11 = a.M11;
  94. float m12 = a.M12;
  95. float m13 = a.M13;
  96. float m14 = a.M14;
  97. float m21 = a.M21;
  98. float m22 = a.M22;
  99. float m23 = a.M23;
  100. float m24 = a.M24;
  101. float m31 = a.M31;
  102. float m32 = a.M32;
  103. float m33 = a.M33;
  104. float m34 = a.M34;
  105. float m41 = a.M41;
  106. float m42 = a.M42;
  107. float m43 = a.M43;
  108. float m44 = a.M44;
  109. float m33x44m34x43 = (m33 * m44) - (m34 * m43);
  110. float m32x44m34x42 = (m32 * m44) - (m34 * m42);
  111. float m32x43m33x42 = (m32 * m43) - (m33 * m42);
  112. float m31x44m34x41 = (m31 * m44) - (m34 * m41);
  113. float m31x43m33x41 = (m31 * m43) - (m33 * m41);
  114. float m31x42m32x41 = (m31 * m42) - (m32 * m41);
  115. float m22m23m24 = ((m22 * m33x44m34x43) - (m23 * m32x44m34x42)) +
  116. (m24 * m32x43m33x42);
  117. float m21m23m24 = -(((m21 * m33x44m34x43) - (m23 * m31x44m34x41)) +
  118. (m24 * m31x43m33x41));
  119. float m21m22m24 = ((m21 * m32x44m34x42) - (m22 * m31x44m34x41)) +
  120. (m24 * m31x42m32x41);
  121. float m21m22m23 = -(((m21 * m32x43m33x42) - (m22 * m31x43m33x41)) +
  122. (m23 * m31x42m32x41));
  123. // Compute the the determinant
  124. float det =
  125. (m11 * m22m23m24) + (m12 * m21m23m24) + (m13 * m21m22m24) +
  126. (m14 * m21m22m23);
  127. if (det == 0.0f)
  128. {
  129. det = 0.000001f;
  130. }
  131. // Inverse(A) = 1/det(A) * B
  132. float inverseDet = 1f / det;
  133. float m23x44m24x43 = (m23 * m44) - (m24 * m43);
  134. float m22x44m24x42 = (m22 * m44) - (m24 * m42);
  135. float m22x43m23x42 = (m22 * m43) - (m23 * m42);
  136. float m21x44m24x41 = (m21 * m44) - (m24 * m41);
  137. float m21x43m23x41 = (m21 * m43) - (m23 * m41);
  138. float m21x42m22x41 = (m21 * m42) - (m22 * m41);
  139. float m23x34m24x33 = (m23 * m34) - (m24 * m33);
  140. float m22x34m24x32 = (m22 * m34) - (m24 * m32);
  141. float m22x33m23x32 = (m22 * m33) - (m23 * m32);
  142. float m21x34m23x31 = (m21 * m34) - (m24 * m31);
  143. float m21x33m23x31 = (m21 * m33) - (m23 * m31);
  144. float m21x32m22x31 = (m21 * m32) - (m22 * m31);
  145. return new Matrix(
  146. m22m23m24 * inverseDet,
  147. -(((m12 * m33x44m34x43) - (m13 * m32x44m34x42)) +
  148. (m14 * m32x43m33x42)) * inverseDet,
  149. (((m12 * m23x44m24x43) - (m13 * m22x44m24x42)) +
  150. (m14 * m22x43m23x42)) * inverseDet,
  151. -(((m12 * m23x34m24x33) - (m13 * m22x34m24x32)) +
  152. (m14 * m22x33m23x32)) * inverseDet,
  153. m21m23m24 * inverseDet,
  154. (((m11 * m33x44m34x43) - (m13 * m31x44m34x41)) +
  155. (m14 * m31x43m33x41)) * inverseDet,
  156. -(((m11 * m23x44m24x43) - (m13 * m21x44m24x41)) +
  157. (m14 * m21x43m23x41)) * inverseDet,
  158. (((m11 * m23x34m24x33) - (m13 * m21x34m23x31)) +
  159. (m14 * m21x33m23x31)) * inverseDet,
  160. m21m22m24 * inverseDet,
  161. -(((m11 * m32x44m34x42) - (m12 * m31x44m34x41)) +
  162. (m14 * m31x42m32x41)) * inverseDet,
  163. (((m11 * m22x44m24x42) - (m12 * m21x44m24x41)) +
  164. (m14 * m21x42m22x41)) * inverseDet,
  165. -(((m11 * m22x34m24x32) - (m12 * m21x34m23x31)) +
  166. (m14 * m21x32m22x31)) * inverseDet,
  167. m21m22m23 * inverseDet,
  168. (((m11 * m32x43m33x42) - (m12 * m31x43m33x41)) +
  169. (m13 * m31x42m32x41)) * inverseDet,
  170. -(((m11 * m22x43m23x42) - (m12 * m21x43m23x41)) +
  171. (m13 * m21x42m22x41)) * inverseDet,
  172. (((m11 * m22x33m23x32) - (m12 * m21x33m23x31)) +
  173. (m13 * m21x32m22x31)) * inverseDet);
  174. }
  175. /// <summary>
  176. /// Invert matrix ref version, this is the fastest one, especially if
  177. /// you use matrix and result for the same value, which will copy values
  178. /// over quickly.
  179. /// </summary>
  180. /// <param name="matrix">Matrix</param>
  181. /// <param name="result">Result</param>
  182. public static void Invert(ref Matrix matrix, ref Matrix result)
  183. {
  184. //Check performance difference again:
  185. // Ugly code that is actually lots faster than our clean implementation
  186. // below (see link on how it works basically). This is basically getting
  187. // the Determinant and then also calculating the inverse matrix in one
  188. // big ugly swoop.
  189. float m11 = matrix.M11;
  190. float m12 = matrix.M12;
  191. float m13 = matrix.M13;
  192. float m14 = matrix.M14;
  193. float m21 = matrix.M21;
  194. float m22 = matrix.M22;
  195. float m23 = matrix.M23;
  196. float m24 = matrix.M24;
  197. float m31 = matrix.M31;
  198. float m32 = matrix.M32;
  199. float m33 = matrix.M33;
  200. float m34 = matrix.M34;
  201. float m41 = matrix.M41;
  202. float m42 = matrix.M42;
  203. float m43 = matrix.M43;
  204. float m44 = matrix.M44;
  205. float m33x44m34x43 = (m33 * m44) - (m34 * m43);
  206. float m32x44m34x42 = (m32 * m44) - (m34 * m42);
  207. float m32x43m33x42 = (m32 * m43) - (m33 * m42);
  208. float m31x44m34x41 = (m31 * m44) - (m34 * m41);
  209. float m31x43m33x41 = (m31 * m43) - (m33 * m41);
  210. float m31x42m32x41 = (m31 * m42) - (m32 * m41);
  211. float m22m23m24 = ((m22 * m33x44m34x43) - (m23 * m32x44m34x42)) +
  212. (m24 * m32x43m33x42);
  213. float m21m23m24 = -(((m21 * m33x44m34x43) - (m23 * m31x44m34x41)) +
  214. (m24 * m31x43m33x41));
  215. float m21m22m24 = ((m21 * m32x44m34x42) - (m22 * m31x44m34x41)) +
  216. (m24 * m31x42m32x41);
  217. float m21m22m23 = -(((m21 * m32x43m33x42) - (m22 * m31x43m33x41)) +
  218. (m23 * m31x42m32x41));
  219. // Computing the determinant
  220. float det = (m11 * m22m23m24) + (m12 * m21m23m24) + (m13 * m21m22m24) +
  221. (m14 * m21m22m23);
  222. if (det == 0.0f)
  223. {
  224. det = 0.000001f;
  225. }
  226. // Inverse(A) = 1/det(A) * B
  227. float inverseDet = 1f / det;
  228. float m23x44m24x43 = (m23 * m44) - (m24 * m43);
  229. float m22x44m24x42 = (m22 * m44) - (m24 * m42);
  230. float m22x43m23x42 = (m22 * m43) - (m23 * m42);
  231. float m21x44m24x41 = (m21 * m44) - (m24 * m41);
  232. float m21x43m23x41 = (m21 * m43) - (m23 * m41);
  233. float m21x42m22x41 = (m21 * m42) - (m22 * m41);
  234. float m23x34m24x33 = (m23 * m34) - (m24 * m33);
  235. float m22x34m24x32 = (m22 * m34) - (m24 * m32);
  236. float m22x33m23x32 = (m22 * m33) - (m23 * m32);
  237. float m21x34m23x31 = (m21 * m34) - (m24 * m31);
  238. float m21x33m23x31 = (m21 * m33) - (m23 * m31);
  239. float m21x32m22x31 = (m21 * m32) - (m22 * m31);
  240. // Now just set everything to the output result matrix, which even can
  241. // be the same as the input matrix (for best performance).
  242. result.M11 = m22m23m24 * inverseDet;
  243. result.M12 = -(((m12 * m33x44m34x43) - (m13 * m32x44m34x42)) +
  244. (m14 * m32x43m33x42)) * inverseDet;
  245. result.M13 = (((m12 * m23x44m24x43) - (m13 * m22x44m24x42)) +
  246. (m14 * m22x43m23x42)) * inverseDet;
  247. result.M14 = -(((m12 * m23x34m24x33) - (m13 * m22x34m24x32)) +
  248. (m14 * m22x33m23x32)) * inverseDet;
  249. result.M21 = m21m23m24 * inverseDet;
  250. result.M22 = (((m11 * m33x44m34x43) - (m13 * m31x44m34x41)) +
  251. (m14 * m31x43m33x41)) * inverseDet;
  252. result.M23 = -(((m11 * m23x44m24x43) - (m13 * m21x44m24x41)) +
  253. (m14 * m21x43m23x41)) * inverseDet;
  254. result.M24 = (((m11 * m23x34m24x33) - (m13 * m21x34m23x31)) +
  255. (m14 * m21x33m23x31)) * inverseDet;
  256. result.M31 = m21m22m24 * inverseDet;
  257. result.M32 = -(((m11 * m32x44m34x42) - (m12 * m31x44m34x41)) +
  258. (m14 * m31x42m32x41)) * inverseDet;
  259. result.M33 = (((m11 * m22x44m24x42) - (m12 * m21x44m24x41)) +
  260. (m14 * m21x42m22x41)) * inverseDet;
  261. result.M34 = -(((m11 * m22x34m24x32) - (m12 * m21x34m23x31)) +
  262. (m14 * m21x32m22x31)) * inverseDet;
  263. result.M41 = m21m22m23 * inverseDet;
  264. result.M42 = (((m11 * m32x43m33x42) - (m12 * m31x43m33x41)) +
  265. (m13 * m31x42m32x41)) * inverseDet;
  266. result.M43 = -(((m11 * m22x43m23x42) - (m12 * m21x43m23x41)) +
  267. (m13 * m21x42m22x41)) * inverseDet;
  268. result.M44 = (((m11 * m22x33m23x32) - (m12 * m21x33m23x31)) +
  269. (m13 * m21x32m22x31)) * inverseDet;
  270. }
  271. #endregion
  272. #region Transpose (Static)
  273. /// <summary>
  274. /// Transpose, which basically just means we switch from a row to a column
  275. /// based matrix.
  276. /// </summary>
  277. /// <param name="matrix">Matrix</param>
  278. /// <returns>Transposed matrix (row/columns switched)</returns>
  279. public static Matrix Transpose(Matrix matrix)
  280. {
  281. //Check performance difference again:
  282. // Note: In all cases our implementation is slighly faster/or a lot faster
  283. //Delta: 569ms (10 mio calls)
  284. //XNA: 760ms (10 mio calls)
  285. //OpenTK: 904ms (10 mio calls)
  286. //SlimDX: 658ms (10 mio calls)
  287. return new Matrix(
  288. // First row
  289. matrix.M11, matrix.M21, matrix.M31, matrix.M41,
  290. // Second row
  291. matrix.M12, matrix.M22, matrix.M32, matrix.M42,
  292. // Third row
  293. matrix.M13, matrix.M23, matrix.M33, matrix.M43,
  294. // Forth row
  295. matrix.M14, matrix.M24, matrix.M34, matrix.M44);
  296. }
  297. /// <summary>
  298. /// Transpose, which basically just means we switch from a row to a column
  299. /// based matrix. Faster version using ref input and output values.
  300. /// </summary>
  301. /// <param name="matrix">Matrix</param>
  302. /// <param name="result">result</param>
  303. public static void Transpose(ref Matrix matrix, ref Matrix result)
  304. {
  305. result.M11 = matrix.M11;
  306. result.M12 = matrix.M21;
  307. result.M13 = matrix.M31;
  308. result.M14 = matrix.M41;
  309. result.M21 = matrix.M12;
  310. result.M22 = matrix.M22;
  311. result.M23 = matrix.M32;
  312. result.M24 = matrix.M42;
  313. result.M31 = matrix.M13;
  314. result.M32 = matrix.M23;
  315. result.M33 = matrix.M33;
  316. result.M34 = matrix.M43;
  317. result.M41 = matrix.M14;
  318. result.M42 = matrix.M24;
  319. result.M43 = matrix.M34;
  320. result.M44 = matrix.M44;
  321. }
  322. #endregion
  323. #region CreateColumnBased (Static)
  324. /// <summary>
  325. /// Create column based matrix, also used for creating an exported collada
  326. /// matrix, because the normal XNA/OpenTK/whatever matrix is row based.
  327. /// </summary>
  328. /// <param name="floatValues">Float values</param>
  329. /// <returns>Matrix</returns>
  330. public static Matrix CreateColumnBased(float[] floatValues)
  331. {
  332. // If we get no valid or an incorrect number of float values, then we
  333. // return only the identity matrix
  334. if (floatValues == null ||
  335. floatValues.Length != 16)
  336. {
  337. return Identity;
  338. }
  339. return new Matrix(
  340. floatValues[0], floatValues[4], floatValues[8], floatValues[12],
  341. floatValues[1], floatValues[5], floatValues[9], floatValues[13],
  342. floatValues[2], floatValues[6], floatValues[10], floatValues[14],
  343. floatValues[3], floatValues[7], floatValues[11], floatValues[15]);
  344. }
  345. #endregion
  346. #region CreateScale (Static)
  347. /// <summary>
  348. /// Create a scale matrix with the specified value for X, Y and Z.
  349. /// </summary>
  350. /// <param name="scale">Scale</param>
  351. /// <returns>New Matrix with the given scale</returns>
  352. public static Matrix CreateScale(float scale)
  353. {
  354. return new Matrix(
  355. scale, 0f, 0f, 0f,
  356. 0f, scale, 0f, 0f,
  357. 0f, 0f, scale, 0f,
  358. 0f, 0f, 0f, 1.0f);
  359. }
  360. /// <summary>
  361. /// Create scale
  362. /// </summary>
  363. /// <param name="scale">Scale</param>
  364. /// <returns>New Matrix with the given scale</returns>
  365. public static Matrix CreateScale(Vector scale)
  366. {
  367. return CreateScale(scale.X, scale.Y, scale.Z);
  368. }
  369. /// <summary>
  370. /// Create a scale matrix with the specified X, Y and Z scaling values.
  371. /// </summary>
  372. /// <param name="scaleX">The amount of scaling in X dimension.</param>
  373. /// <param name="scaleY">The amount of scaling in Y dimension.</param>
  374. /// <param name="scaleZ">The amount of scaling in Z dimension.</param>
  375. /// <returns>New Matrix with the given scale</returns>
  376. public static Matrix CreateScale(float scaleX, float scaleY, float scaleZ)
  377. {
  378. return new Matrix(
  379. scaleX, 0f, 0f, 0f,
  380. 0f, scaleY, 0f, 0f,
  381. 0f, 0f, scaleZ, 0f,
  382. 0f, 0f, 0f, 1f);
  383. }
  384. #endregion
  385. #region CreateRotationX (Static)
  386. /// <summary>
  387. /// Create rotation around x-axis (pitch)
  388. /// <para />
  389. /// It is important to know which axis is meant with Yaw, Pitch and Roll:
  390. /// http://www.spotimage.com/dimap/spec/dictionary/Spot_Scene/Illustrations/YAW.gif
  391. /// </summary>
  392. public static Matrix CreateRotationX(float degrees)
  393. {
  394. //Check performance difference again:
  395. // Note: All CreateRotation implementations are slow, there are slightly
  396. // faster on XNA, but overall not much of a difference between all
  397. // platforms and frameworks (see below in MatrixPerformance class).
  398. float cosValue = MathHelper.Cos(degrees);
  399. float sinValue = MathHelper.Sin(degrees);
  400. return new Matrix(
  401. 1f, 0f, 0f, 0f,
  402. 0f, cosValue, sinValue, 0f,
  403. 0f, -sinValue, cosValue, 0f,
  404. 0f, 0f, 0f, 1f);
  405. }
  406. #endregion
  407. #region CreateRotationY (Static)
  408. /// <summary>
  409. /// Create rotation around y-axis (yaw)
  410. /// <para />
  411. /// It is important to know which axis is meant with Yaw, Pitch and Roll:
  412. /// http://www.spotimage.com/dimap/spec/dictionary/Spot_Scene/Illustrations/YAW.gif
  413. /// </summary>
  414. /// <param name="degrees">Degrees to rotate around the Y axis</param>
  415. /// <returns>New matrix with the given rotation</returns>
  416. public static Matrix CreateRotationY(float degrees)
  417. {
  418. //Check performance difference again:
  419. // Note: All CreateRotation implementations are slow, there are slightly
  420. // faster on XNA, but overall not much of a difference between all
  421. // platforms and frameworks (see below in MatrixPerformance class).
  422. float cosValue = MathHelper.Cos(degrees);
  423. float sinValue = MathHelper.Sin(degrees);
  424. return new Matrix(
  425. cosValue, 0f, -sinValue, 0f,
  426. 0f, 1f, 0f, 0f,
  427. sinValue, 0f, cosValue, 0f,
  428. 0f, 0f, 0f, 1f);
  429. }
  430. #endregion
  431. #region CreateRotationZ (Static)
  432. /// <summary>
  433. /// Create rotation around z-axis (roll)
  434. /// <para />
  435. /// It is important to know which axis is meant with Yaw, Pitch and Roll:
  436. /// http://www.spotimage.com/dimap/spec/dictionary/Spot_Scene/Illustrations/YAW.gif
  437. /// </summary>
  438. /// <param name="degrees">Degrees to rotate around the Z axis</param>
  439. /// <returns>New matrix with the given rotation</returns>
  440. public static Matrix CreateRotationZ(float degrees)
  441. {
  442. //Check performance difference again:
  443. // Note: All CreateRotation implementations are slow, there are slightly
  444. // faster on XNA, but overall not much of a difference between all
  445. // platforms and frameworks (see below in MatrixPerformance class).
  446. float cosValue = MathHelper.Cos(degrees);
  447. float sinValue = MathHelper.Sin(degrees);
  448. return new Matrix(
  449. cosValue, sinValue, 0f, 0f,
  450. -sinValue, cosValue, 0f, 0f,
  451. 0f, 0f, 1f, 0f,
  452. 0f, 0f, 0f, 1f);
  453. }
  454. #endregion
  455. #region CreateRotationZYX (Static)
  456. /// <summary>
  457. /// Rotate around the Z axis, then the Y axis, and finally the X axis
  458. /// (rotX * rotY * rotZ). Please note that this is not the same as
  459. /// FromYawPitchRoll, which uses Z (yaw), then X (pitch), then Y (roll).
  460. /// <para />
  461. /// Note: This is the same as calling the CreateRotationX, Y, Z methods,
  462. /// just combined all together without having to multiply matrices).
  463. /// </summary>
  464. /// <param name="x">Degrees to rotate around the X axis</param>
  465. /// <param name="y">Degrees to rotate around the Y axis</param>
  466. /// <param name="z">Degrees to rotate around the Z axis</param>
  467. /// <returns>New matrix with the given rotation</returns>
  468. public static Matrix CreateRotationZYX(float x, float y, float z)
  469. {
  470. float cx = 1;
  471. float sx = 0;
  472. float cy = 1;
  473. float sy = 0;
  474. float cz = 1;
  475. float sz = 0;
  476. if (x != 0.0f)
  477. {
  478. cx = MathHelper.Cos(x);
  479. sx = MathHelper.Sin(x);
  480. }
  481. if (y != 0.0f)
  482. {
  483. cy = MathHelper.Cos(y);
  484. sy = MathHelper.Sin(y);
  485. }
  486. if (z != 0.0f)
  487. {
  488. cz = MathHelper.Cos(z);
  489. sz = MathHelper.Sin(z);
  490. }
  491. return new Matrix(
  492. cy * cz, cy * sz, -sy, 0.0f,
  493. (sx * sy * cz) + (cx * -sz), (sx * sy * sz) + (cx * cz), sx * cy, 0.0f,
  494. (cx * sy * cz) + (sx * sz), (cx * sy * sz) + (-sx * cz), cx * cy, 0.0f,
  495. 0.0f, 0.0f, 0.0f, 1.0f);
  496. }
  497. #endregion
  498. #region CreateRotationZY (Static)
  499. /// <summary>
  500. /// Rotate around Z axis, then around Y axis.
  501. /// (equals rotY * rotZ)
  502. /// </summary>
  503. /// <param name="y">Degrees to rotate around the Y axis</param>
  504. /// <param name="z">Degrees to rotate around the Z axis</param>
  505. /// <returns>New matrix with the given rotation</returns>
  506. public static Matrix CreateRotationZY(float y, float z)
  507. {
  508. float cy = 1;
  509. float sy = 0;
  510. float cz = 1;
  511. float sz = 0;
  512. // We only calculate sin/cos if given input is not zero
  513. if (y != 0.0f)
  514. {
  515. cy = MathHelper.Cos(y);
  516. sy = MathHelper.Sin(y);
  517. }
  518. if (z != 0.0f)
  519. {
  520. cz = MathHelper.Cos(z);
  521. sz = MathHelper.Sin(z);
  522. }
  523. return new Matrix(
  524. cy * cz, cy * sz, -sy, 0.0f,
  525. -sz, cz, 0.0f, 0.0f,
  526. sy * cz, sy * sz, cy, 0.0f,
  527. 0.0f, 0.0f, 0.0f, 1.0f);
  528. }
  529. #endregion
  530. #region FromYawPitchRoll (Static)
  531. /// <summary>
  532. /// From yaw pitch roll (yaw = Y, pitch = X, roll = Z)
  533. /// http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm
  534. /// It is important to know which axis is meant with Yaw, Pitch and Roll:
  535. /// http://www.spotimage.com/dimap/spec/dictionary/Spot_Scene/Illustrations/YAW.gif
  536. /// <para />
  537. /// Note: This method calculates Y * X * Z where
  538. /// Y = value.X = yaw
  539. /// X = value.Y = pitch
  540. /// Z = value.Z = roll
  541. /// </summary>
  542. public static Matrix FromYawPitchRoll(Vector value)
  543. {
  544. return FromYawPitchRoll(value.X, value.Y, value.Z);
  545. }
  546. /// <summary>
  547. /// From yaw pitch roll (yaw = Y, pitch = X, roll = Z)
  548. /// It is important to know which axis is meant with Yaw, Pitch and Roll:
  549. /// http://www.spotimage.com/dimap/spec/dictionary/Spot_Scene/Illustrations/YAW.gif
  550. /// <para />
  551. /// Note: This method calculates Y * X * Z where
  552. /// Y = yaw
  553. /// X = pitch
  554. /// Z = roll
  555. /// </summary>
  556. public static Matrix FromYawPitchRoll(float yaw, float pitch, float roll)
  557. {
  558. //Check performance difference again:
  559. float cy = MathHelper.Cos(yaw);
  560. float sy = MathHelper.Sin(yaw);
  561. float cp = MathHelper.Cos(pitch);
  562. float sp = MathHelper.Sin(pitch);
  563. float cr = MathHelper.Cos(roll);
  564. float sr = MathHelper.Sin(roll);
  565. return new Matrix(
  566. cy * cr - sr * sy * sp, cy * sr + sy * sp * cr, -sy * cp, 0.0f,
  567. -sr * cp, cp * cr, sp, 0.0f,
  568. sy * cr + sp * cy * sr, sy * sr - sp * cy * cr, cy * cp, 0.0f,
  569. 0.0f, 0.0f, 0.0f, 1.0f);
  570. }
  571. #endregion
  572. #region CreateTranslation (Static)
  573. /// <summary>
  574. /// Create translation matrix
  575. /// </summary>
  576. /// <param name="position">Position</param>
  577. /// <returns>Identity matrix with the translation (M41, M42, M43)</returns>
  578. public static Matrix CreateTranslation(Vector position)
  579. {
  580. return new Matrix(
  581. 1f, 0f, 0f, 0f,
  582. 0f, 1f, 0f, 0f,
  583. 0f, 0f, 1f, 0f,
  584. position.X, position.Y, position.Z, 1.0f);
  585. }
  586. /// <summary>
  587. /// Create translation matrix
  588. /// </summary>
  589. /// <param name="x">x</param>
  590. /// <param name="y">y</param>
  591. /// <param name="z">z</param>
  592. /// <returns>Identity matrix with the translation (M41, M42, M43)</returns>
  593. public static Matrix CreateTranslation(float x, float y, float z)
  594. {
  595. return new Matrix(
  596. 1f, 0f, 0f, 0f,
  597. 0f, 1f, 0f, 0f,
  598. 0f, 0f, 1f, 0f,
  599. x, y, z, 1.0f);
  600. }
  601. #endregion
  602. #region CreateScaleAndTranslation (Static)
  603. /// <summary>
  604. /// Create scale and translation, basically just does CreateScale and
  605. /// CreateTranslation, but much more efficient.
  606. /// </summary>
  607. /// <param name="scale">Scale for the new matrix</param>
  608. /// <param name="position">Position for the matrix translation.</param>
  609. /// <returns>New matrix with the given scale and translation.</returns>
  610. public static Matrix CreateScaleAndTranslation(float scale,
  611. Vector position)
  612. {
  613. return new Matrix(
  614. scale, 0f, 0f, 0f,
  615. 0f, scale, 0f, 0f,
  616. 0f, 0f, scale, 0f,
  617. position.X, position.Y, position.Z, 1f);
  618. }
  619. #endregion
  620. #region CreateLookAt (Static)
  621. /// <summary>
  622. /// Creates a right-handed look at matrix for a camera.
  623. /// </summary>
  624. /// <param name="cameraPosition">camera position</param>
  625. /// <param name="cameraTarget">camera target</param>
  626. /// <param name="cameraUpVector">camera up vector</param>
  627. /// <returns>New look at matrix</returns>
  628. public static Matrix CreateLookAt(Vector cameraPosition,
  629. Vector cameraTarget, Vector cameraUpVector)
  630. {
  631. //Check performance difference again:
  632. // Slightly faster in XNA (5%), but overall all these implementations
  633. // are roughly the same.
  634. // Note: All Create view implementations are slow, there are slighly
  635. // faster on XNA, but overall not much of a difference between all
  636. // platforms and frameworks (see below in MatrixPerformance class).
  637. // Simplified and optimized formula to create look matrix
  638. Vector dir = Vector.Normalize(cameraPosition - cameraTarget);
  639. Vector up = Vector.Normalize(Vector.Cross(cameraUpVector, dir));
  640. // Switch up around if cameraUpVector is the same as dir!
  641. if (up.LengthSquared == 0)
  642. {
  643. up = Vector.UnitY;
  644. }
  645. Vector right = Vector.Cross(dir, up);
  646. return new Matrix(
  647. up.X, right.X, dir.X, 0f,
  648. up.Y, right.Y, dir.Y, 0f,
  649. up.Z, right.Z, dir.Z, 0f,
  650. -Vector.Dot(up, cameraPosition),
  651. -Vector.Dot(right, cameraPosition),
  652. -Vector.Dot(dir, cameraPosition), 1f);
  653. }
  654. #endregion
  655. #region CreateFromAxisAngle (Static)
  656. /// <summary>
  657. /// Create from axis angle (in degrees)
  658. /// </summary>
  659. /// <param name="angle">Angle in degrees</param>
  660. /// <param name="axis">Axis to rotate around</param>
  661. /// <returns>Rotated matrix around axis for rotations</returns>
  662. public static Matrix CreateFromAxisAngle(Vector axis, float angle)
  663. {
  664. // Note: Variables in this method need to be beautifulized!
  665. //Check performance difference again:
  666. Matrix matrix = new Matrix();
  667. float x = axis.X;
  668. float y = axis.Y;
  669. float z = axis.Z;
  670. float num2 = MathHelper.Sin(angle);
  671. float num = MathHelper.Cos(angle);
  672. float num11 = x * x;
  673. float num10 = y * y;
  674. float num9 = z * z;
  675. float num8 = x * y;
  676. float num7 = x * z;
  677. float num6 = y * z;
  678. matrix.M11 = num11 + (num * (1f - num11));
  679. matrix.M12 = (num8 - (num * num8)) + (num2 * z);
  680. matrix.M13 = (num7 - (num * num7)) - (num2 * y);
  681. matrix.M14 = 0f;
  682. matrix.M21 = (num8 - (num * num8)) - (num2 * z);
  683. matrix.M22 = num10 + (num * (1f - num10));
  684. matrix.M23 = (num6 - (num * num6)) + (num2 * x);
  685. matrix.M24 = 0f;
  686. matrix.M31 = (num7 - (num * num7)) + (num2 * y);
  687. matrix.M32 = (num6 - (num * num6)) - (num2 * x);
  688. matrix.M33 = num9 + (num * (1f - num9));
  689. matrix.M34 = 0f;
  690. matrix.M41 = 0f;
  691. matrix.M42 = 0f;
  692. matrix.M43 = 0f;
  693. matrix.M44 = 1f;
  694. return matrix;
  695. }
  696. /// <summary>
  697. /// Create from axis angle (in degrees)
  698. /// </summary>
  699. /// <param name="angle">Angle in degrees</param>
  700. /// <param name="axis">Axis to rotate around</param>
  701. /// <param name="result">Rotated matrix around axis for rotations</param>
  702. public static void CreateFromAxisAngle(ref Vector axis, float angle,
  703. ref Matrix result)
  704. {
  705. float x = axis.X;
  706. float y = axis.Y;
  707. float z = axis.Z;
  708. float num2 = MathHelper.Sin(angle);
  709. float num = MathHelper.Cos(angle);
  710. float num11 = x * x;
  711. float num10 = y * y;
  712. float num9 = z * z;
  713. float num8 = x * y;
  714. float num7 = x * z;
  715. float num6 = y * z;
  716. result.M11 = num11 + (num * (1f - num11));
  717. result.M12 = (num8 - (num * num8)) + (num2 * z);
  718. result.M13 = (num7 - (num * num7)) - (num2 * y);
  719. result.M14 = 0f;
  720. result.M21 = (num8 - (num * num8)) - (num2 * z);
  721. result.M22 = num10 + (num * (1f - num10));
  722. result.M23 = (num6 - (num * num6)) + (num2 * x);
  723. result.M24 = 0f;
  724. result.M31 = (num7 - (num * num7)) + (num2 * y);
  725. result.M32 = (num6 - (num * num6)) - (num2 * x);
  726. result.M33 = num9 + (num * (1f - num9));
  727. result.M34 = 0f;
  728. result.M41 = 0f;
  729. result.M42 = 0f;
  730. result.M43 = 0f;
  731. result.M44 = 1f;
  732. }
  733. #endregion
  734. #region CreateOrthographic (Static)
  735. /// <summary>
  736. /// Create orthographic
  737. /// </summary>
  738. /// <param name="bottom">bottom</param>
  739. /// <param name="farPlane">farPlane</param>
  740. /// <param name="left">left</param>
  741. /// <param name="nearPlane">near plane</param>
  742. /// <param name="right">right</param>
  743. /// <param name="top">top</param>
  744. /// <returns>New Orthographic matrix</returns>
  745. public static Matrix CreateOrthographic(float left, float right,
  746. float bottom, float top, float nearPlane, float farPlane)
  747. {
  748. //Check performance difference again:
  749. Matrix matrix = new Matrix();
  750. matrix.M11 = 2f / (right - left);
  751. matrix.M12 = matrix.M13 = matrix.M14 = 0f;
  752. matrix.M22 = 2f / (top - bottom);
  753. matrix.M21 = matrix.M23 = matrix.M24 = 0f;
  754. matrix.M33 = 1f / (nearPlane - farPlane);
  755. matrix.M31 = matrix.M32 = matrix.M34 = 0f;
  756. matrix.M41 = (left + right) / (left - right);
  757. matrix.M42 = (top + bottom) / (bottom - top);
  758. matrix.M43 = nearPlane / (nearPlane - farPlane);
  759. matrix.M44 = 1f;
  760. return matrix;
  761. }
  762. #endregion
  763. #region CreatePerspective (Static)
  764. /// <summary>
  765. /// Creates a right-handed perspective field of view matrix for a camera.
  766. /// </summary>
  767. /// <param name="fieldOfView">Field of view (Warning: In radians)</param>
  768. /// <param name="aspectRatio">Aspect ratio</param>
  769. /// <param name="nearPlaneDistance">Near plane distance</param>
  770. /// <param name="farPlaneDistance">Far plane distance</param>
  771. /// <returns>Matrix</returns>
  772. public static Matrix CreatePerspective(float fieldOfView,
  773. float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
  774. {
  775. //Check performance difference again:
  776. // Slightly faster in Delta (10%), but overall all this implementations
  777. // are ruffly the same. Same as the following, just faster:
  778. //XnaMatrix.CreatePerspectiveFieldOfView(...)
  779. //TKMatrix.CreatePerspectiveFieldOfView(...)
  780. //SlimDX.Matrix.PerspectiveFovRH(...)
  781. float m22 = 1f / ((float)Math.Tan(fieldOfView * 0.5f));
  782. return new Matrix(
  783. m22 / aspectRatio, 0f, 0f, 0f,
  784. 0f, m22, 0f, 0f,
  785. 0f, 0f, farPlaneDistance / (nearPlaneDistance - farPlaneDistance), -1f,
  786. 0f, 0f, (nearPlaneDistance * farPlaneDistance) /
  787. (nearPlaneDistance - farPlaneDistance), 0f);
  788. }
  789. #endregion
  790. #region Multiply (Static)
  791. /// <summary>
  792. /// Ugly Matrix Multiply method (normally you would just use
  793. /// matrix1*matrix2 to multiply two matrices), but this one is a little
  794. /// faster because we don't need to copy over the matrix values and we can
  795. /// even provide a faster fallback on the xbox platform (using xna).
  796. /// Note: matrix1 or matrix2 can be the same as result, which results in
  797. /// even better performance for performance critical matrix multiply code.
  798. /// </summary>
  799. /// <param name="matrix1">matrix1</param>
  800. /// <param name="matrix2">matrix2</param>
  801. /// <param name="result">result</param>
  802. public static void Multiply(ref Matrix matrix1, ref Matrix matrix2,
  803. ref Matrix result)
  804. {
  805. //Check performance difference again:
  806. // Note: Values are stored in local variables to allow matrix1 or matrix2
  807. // and result be the same matrices (we won't overwrite M11-M44 while
  808. // calculating the result), which happens quite often in optimized code!
  809. float m11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 +
  810. matrix1.M13 * matrix2.M31 + matrix1.M14 * matrix2.M41;
  811. float m12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 +
  812. matrix1.M13 * matrix2.M32 + matrix1.M14 * matrix2.M42;
  813. float m13 = matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 +
  814. matrix1.M13 * matrix2.M33 + matrix1.M14 * matrix2.M43;
  815. float m14 = matrix1.M11 * matrix2.M14 + matrix1.M12 * matrix2.M24 +
  816. matrix1.M13 * matrix2.M34 + matrix1.M14 * matrix2.M44;
  817. float m21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 +
  818. matrix1.M23 * matrix2.M31 + matrix1.M24 * matrix2.M41;
  819. float m22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 +
  820. matrix1.M23 * matrix2.M32 + matrix1.M24 * matrix2.M42;
  821. float m23 = matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 +
  822. matrix1.M23 * matrix2.M33 + matrix1.M24 * matrix2.M43;
  823. float m24 = matrix1.M21 * matrix2.M14 + matrix1.M22 * matrix2.M24 +
  824. matrix1.M23 * matrix2.M34 + matrix1.M24 * matrix2.M44;
  825. float m31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 +
  826. matrix1.M33 * matrix2.M31 + matrix1.M34 * matrix2.M41;
  827. float m32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 +
  828. matrix1.M33 * matrix2.M32 + matrix1.M34 * matrix2.M42;
  829. float m33 = matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 +
  830. matrix1.M33 * matrix2.M33 + matrix1.M34 * matrix2.M43;
  831. float m34 = matrix1.M31 * matrix2.M14 + matrix1.M32 * matrix2.M24 +
  832. matrix1.M33 * matrix2.M34 + matrix1.M34 * matrix2.M44;
  833. float m41 = matrix1.M41 * matrix2.M11 + matrix1.M42 * matrix2.M21 +
  834. matrix1.M43 * matrix2.M31 + matrix1.M44 * matrix2.M41;
  835. float m42 = matrix1.M41 * matrix2.M12 + matrix1.M42 * matrix2.M22 +
  836. matrix1.M43 * matrix2.M32 + matrix1.M44 * matrix2.M42;
  837. float m43 = matrix1.M41 * matrix2.M13 + matrix1.M42 * matrix2.M23 +
  838. matrix1.M43 * matrix2.M33 + matrix1.M44 * matrix2.M43;
  839. float m44 = matrix1.M41 * matrix2.M14 + matrix1.M42 * matrix2.M24 +
  840. matrix1.M43 * matrix2.M34 + matrix1.M44 * matrix2.M44;
  841. result.M11 = m11;
  842. result.M12 = m12;
  843. result.M13 = m13;
  844. result.M14 = m14;
  845. result.M21 = m21;
  846. result.M22 = m22;
  847. result.M23 = m23;
  848. result.M24 = m24;
  849. result.M31 = m31;
  850. result.M32 = m32;
  851. result.M33 = m33;
  852. result.M34 = m34;
  853. result.M41 = m41;
  854. result.M42 = m42;
  855. result.M43 = m43;
  856. result.M44 = m44;
  857. }
  858. /// <summary>
  859. /// Ugly Matrix*Vector multiply method (basically transforming a vector
  860. /// with a matrix). Normally you would just use matrix*position to
  861. /// multiply, but this one is a little faster because we don't need to
  862. /// copy over the matrix values and we can even provide a faster fallback
  863. /// on the xbox platform (using xna).
  864. /// Note: position and result can be the same as result, which results in
  865. /// even better performance for performance critical matrix multiply code.
  866. /// </summary>
  867. /// <param name="matrix">matrix</param>
  868. /// <param name="position">position</param>
  869. /// <param name="result">result</param>
  870. public static void Multiply(ref Matrix matrix, ref Vector position,
  871. ref Vector result)
  872. {
  873. //Check performance difference again:
  874. float x = position.X * matrix.M11 + position.Y * matrix.M21 +
  875. position.Z * matrix.M31 + matrix.M41;
  876. float y = position.X * matrix.M12 + position.Y * matrix.M22 +
  877. position.Z * matrix.M32 + matrix.M42;
  878. float z = position.X * matrix.M13 + position.Y * matrix.M23 +
  879. position.Z * matrix.M33 + matrix.M43;
  880. result.X = x;
  881. result.Y = y;
  882. result.Z = z;
  883. }
  884. /// <summary>
  885. /// Multiply matrix with a scale factor. Note: This is the slow version.
  886. /// This method needs to copy 128 bytes around (2 matrices, each 64 bytes).
  887. /// Try to use the ref version instead.
  888. /// </summary>
  889. /// <param name="matrix">Matrix</param>
  890. /// <param name="scaleFactor">Scale factor</param>
  891. /// <returns>
  892. /// New matrix with each value multiplied with scaleFactor
  893. /// </returns>
  894. public static Matrix Multiply(Matrix matrix, float scaleFactor)
  895. {
  896. return new Matrix(
  897. matrix.M11 * scaleFactor, matrix.M12 * scaleFactor,
  898. matrix.M13 * scaleFactor, matrix.M14 * scaleFactor,
  899. matrix.M21 * scaleFactor, matrix.M22 * scaleFactor,
  900. matrix.M23 * scaleFactor, matrix.M24 * scaleFactor,
  901. matrix.M31 * scaleFactor, matrix.M32 * scaleFactor,
  902. matrix.M33 * scaleFactor, matrix.M34 * scaleFactor,
  903. matrix.M41 * scaleFactor, matrix.M42 * scaleFactor,
  904. matrix.M43 * scaleFactor, matrix.M44 * scaleFactor);
  905. }
  906. #endregion
  907. #region Equal (Static)
  908. /// <summary>
  909. /// Equality check. Optimized for speed via ref parameters, which
  910. /// are much faster than copying 128 bytes (2 matrices each 64 bytes).
  911. /// </summary>
  912. public static bool Equal(ref Matrix matrix1, ref Matrix matrix2)
  913. {
  914. // Note: The checks are sorted by the diagonal, which is most important
  915. // and usually the most different for 2 matrices (faster this way!)
  916. // Note: Calling XNA (and OpenTK or SlimDX or SharpDX too) here is
  917. // slower! So it is disabled.
  918. return
  919. matrix1.M11 == matrix2.M11 &&
  920. matrix1.M22 == matrix2.M22 &&
  921. matrix1.M33 == matrix2.M33 &&
  922. matrix1.M44 == matrix2.M44 &&
  923. // Now check the rest if the diagonal matrices were the same.
  924. matrix1.M12 == matrix2.M12 &&
  925. matrix1.M13 == matrix2.M13 &&
  926. matrix1.M14 == matrix2.M14 &&
  927. matrix1.M21 == matrix2.M21 &&
  928. matrix1.M23 == matrix2.M23 &&
  929. matrix1.M24 == matrix2.M24 &&
  930. matrix1.M31 == matrix2.M31 &&
  931. matrix1.M32 == matrix2.M32 &&
  932. matrix1.M34 == matrix2.M34 &&
  933. matrix1.M41 == matrix2.M41 &&
  934. matrix1.M42 == matrix2.M42 &&
  935. matrix1.M43 == matrix2.M43;
  936. }
  937. #endregion
  938. #region Unequal (Static)
  939. /// <summary>
  940. /// Inequality check. Optimized for speed via ref parameters, which
  941. /// are much faster than copying 128 bytes (2 matrices each 64 bytes).
  942. /// </summary>
  943. public static bool Unequal(ref Matrix matrix1, ref Matrix matrix2)
  944. {
  945. // Check if everything is equal, if not return true (this is the unequal
  946. // check), might look a bit strange, but it is fast because of early out.
  947. if (matrix1.M11 == matrix2.M11 &&
  948. matrix1.M12 == matrix2.M12 &&
  949. matrix1.M13 == matrix2.M13 &&
  950. matrix1.M14 == matrix2.M14 &&
  951. matrix1.M21 == matrix2.M21 &&
  952. matrix1.M22 == matrix2.M22 &&
  953. matrix1.M23 == matrix2.M23 &&
  954. matrix1.M24 == matrix2.M24 &&
  955. matrix1.M31 == matrix2.M31 &&
  956. matrix1.M32 == matrix2.M32 &&
  957. matrix1.M33 == matrix2.M33 &&
  958. matrix1.M34 == matrix2.M34 &&
  959. matrix1.M41 == matrix2.M41 &&
  960. matrix1.M42 == matrix2.M42 &&
  961. matrix1.M43 == matrix2.M43)
  962. {
  963. return (matrix1.M44 != matrix2.M44);
  964. }
  965. return true;
  966. }
  967. #endregion
  968. #region TranslationNearlyEqual (Static)
  969. /// <summary>
  970. /// Nearly equals (only checks the Translation of the matrices), two
  971. /// matrices are considered nearly equal if their translation distance
  972. /// is below MathHelper.Epsilon. Use the MatrixNearlyEqual method to
  973. /// compare two complete matrices (much slower than this check).
  974. /// </summary>
  975. /// <param name="matrix1">Matrix 1 to compare</param>
  976. /// <param name="matrix2">Matrix 2 to compare</param>
  977. /// <returns>True if the translations of the matrices are almost the
  978. /// same, false otherwise.</returns>
  979. public static bool TranslationNearlyEqual(ref Matrix matrix1,
  980. ref Matrix matrix2)
  981. {
  982. // Check to see if the absolute difference of each value is smaller than
  983. // the Nearly Equal value.
  984. return (matrix1.Translation - matrix2.Translation).LengthSquared <
  985. MathHelper.Epsilon * MathHelper.Epsilon;
  986. }
  987. #endregion
  988. #region MatrixNearlyEqual (Static)
  989. /// <summary>
  990. /// Matrix nearly equal helper method to compare two matrices that might
  991. /// not be 100% the same because of rounding errors, but they produce
  992. /// pretty much the same results.
  993. /// </summary>
  994. /// <param name="matrix1">Matrix 1 to compare</param>
  995. /// <param name="matrix2">Matrix 2 to compare</param>
  996. /// <returns>True if the matrices are almost the same</returns>
  997. public static bool MatrixNearlyEqual(ref Matrix mat1, ref Matrix mat2)
  998. {
  999. return
  1000. mat1.M11.NearlyEqual(mat2.M11) &&
  1001. mat1.M12.NearlyEqual(mat2.M12) &&
  1002. mat1.M13.NearlyEqual(mat2.M13) &&
  1003. mat1.M14.NearlyEqual(mat2.M14) &&
  1004. mat1.M21.NearlyEqual(mat2.M21) &&
  1005. mat1.M22.NearlyEqual(mat2.M22) &&
  1006. mat1.M23.NearlyEqual(mat2.M23) &&
  1007. mat1.M24.NearlyEqual(mat2.M24) &&
  1008. mat1.M31.NearlyEqual(mat2.M31) &&
  1009. mat1.M32.NearlyEqual(mat2.M32) &&
  1010. mat1.M33.NearlyEqual(mat2.M33) &&
  1011. mat1.M34.NearlyEqual(mat2.M34) &&
  1012. mat1.M41.NearlyEqual(mat2.M41) &&
  1013. mat1.M42.NearlyEqual(mat2.M42) &&
  1014. mat1.M43.NearlyEqual(mat2.M43) &&
  1015. mat1.M44.NearlyEqual(mat2.M44);
  1016. }
  1017. #endregion
  1018. #region FromQuaternion (Static)
  1019. /// <summary>
  1020. /// From quaternion
  1021. /// </summary>
  1022. public static Matrix FromQuaternion(Quaternion quaternion)
  1023. {
  1024. //Check performance difference again:
  1025. // Note: We can only be sure that this is faster on the Xbox, not used
  1026. // often anyway.
  1027. //Note: This could need some more comments, help, etc.
  1028. float qxx = quaternion.X * quaternion.X;
  1029. float qyy = quaternion.Y * quaternion.Y;
  1030. float qzz = quaternion.Z * quaternion.Z;
  1031. float qxy = quaternion.X * quaternion.Y;
  1032. float qzw = quaternion.Z * quaternion.W;
  1033. float qwx = quaternion.Z * quaternion.X;
  1034. float qyw = quaternion.Y * quaternion.W;
  1035. float qyz = quaternion.Y * quaternion.Z;
  1036. float qxw = quaternion.X * quaternion.W;
  1037. return new Matrix(
  1038. 1f - (2f * (qyy + qzz)), 2f * (qxy + qzw), 2f * (qwx - qyw), 0f,
  1039. 2f * (qxy - qzw), 1f - (2f * (qzz + qxx)), 2f * (qyz + qxw), 0f,
  1040. 2f * (qwx + qyw), 2f * (qyz - qxw), 1f - (2f * (qyy + qxx)), 0f,
  1041. 0f, 0f, 0f, 1f);
  1042. }
  1043. #endregion
  1044. #region FromString (Static)
  1045. /// <summary>
  1046. /// Convert a string to a Matrix. The expected format is
  1047. /// (M11, M12, M13, M14)
  1048. /// (M21, M22, M23, M24)
  1049. /// ...
  1050. /// </summary>
  1051. /// <param name="matrixString">The string containing the values in the
  1052. /// correct format.</param>
  1053. public static Matrix FromString(string matrixString)
  1054. {
  1055. // First remove the brackets
  1056. matrixString = matrixString.
  1057. Replace("(", "").
  1058. Replace(")", "");
  1059. // And split the string up into seperate values.
  1060. string[] matrixStrings = matrixString.SplitAndTrim(',');
  1061. //StringSplitOptions.RemoveEmptyEntries);
  1062. // Then check if the length is 16 for 16 values and return the new matrix.
  1063. // If the length is not 16 than return Matrix.Identity.
  1064. if (matrixStrings.Length == 16)
  1065. {
  1066. return new Matrix(
  1067. // First row
  1068. matrixStrings[0].FromInvariantString(1.0f),
  1069. matrixStrings[1].FromInvariantString(0.0f),
  1070. matrixStrings[2].FromInvariantString(0.0f),
  1071. matrixStrings[3].FromInvariantString(0.0f),
  1072. // Second row
  1073. matrixStrings[4].FromInvariantString(0.0f),
  1074. matrixStrings[5].FromInvariantString(1.0f),
  1075. matrixStrings[6].FromInvariantString(0.0f),
  1076. matrixStrings[7].FromInvariantString(0.0f),
  1077. // Third row
  1078. matrixStrings[8].FromInvariantString(0.0f),
  1079. matrixStrings[9].FromInvariantString(0.0f),
  1080. matrixStrings[10].FromInvariantString(1.0f),
  1081. matrixStrings[11].FromInvariantString(0.0f),
  1082. // Forth row
  1083. matrixStrings[12].FromInvariantString(0.0f),
  1084. matrixStrings[13].FromInvariantString(0.0f),
  1085. matrixStrings[14].FromInvariantString(0.0f),
  1086. matrixStrings[15].FromInvariantString(1.0f));
  1087. }
  1088. Log.Warning("Unable to convert matrixString=" + matrixString +
  1089. " because it has not exactly 16 float values!");
  1090. return Identity;
  1091. }
  1092. #endregion
  1093. #region Identity (Static)
  1094. /// <summary>
  1095. /// Returns a new identity matrix (no rotation, translation or scaling)!
  1096. /// Note: Not readonly to allow passing it by ref, but this should never
  1097. /// be set!
  1098. /// </summary>
  1099. public static Matrix Identity = new Matrix(
  1100. 1, 0, 0, 0,
  1101. 0, 1, 0, 0,
  1102. 0, 0, 1, 0,
  1103. 0, 0, 0, 1);
  1104. #endregion
  1105. #region Framework Union Defines (Public)
  1106. #endregion
  1107. #region M11 (Public)
  1108. /// <summary>
  1109. /// 1st row - 1st column value of the Matrix.
  1110. /// </summary>
  1111. [FieldOffset(0)]
  1112. public float M11;
  1113. #endregion
  1114. #region M12 (Public)
  1115. /// <summary>
  1116. /// 1st row - 2nd column value of the Matrix.
  1117. /// </summary>
  1118. [FieldOffset(4)]
  1119. public float M12;
  1120. #endregion
  1121. #region M13 (Public)
  1122. /// <summary>
  1123. /// 1st row - 3rd column value of the Matrix.
  1124. /// </summary>
  1125. [FieldOffset(8)]
  1126. public float M13;
  1127. #endregion
  1128. #region M14 (Public)
  1129. /// <summary>
  1130. /// 1st row - 4th column value of the Matrix.
  1131. /// </summary>
  1132. [FieldOffset(12)]
  1133. public float M14;
  1134. #endregion
  1135. #region M21 (Public)
  1136. /// <summary>
  1137. /// 2nd row - 1st column value of the Matrix.
  1138. /// </summary>
  1139. [FieldOffset(16)]
  1140. public float M21;
  1141. #endregion
  1142. #region M22 (Public)
  1143. /// <summary>
  1144. /// 2nd row - 2nd column value of the Matrix.
  1145. /// </summary>
  1146. [FieldOffset(20)]
  1147. public float M22;
  1148. #endregion
  1149. #region M23 (Public)
  1150. /// <summary>
  1151. /// 2nd row - 3nd column value of the Matrix.
  1152. /// </summary>
  1153. [FieldOffset(24)]
  1154. public float M23;
  1155. #endregion
  1156. #region M24 (Public)
  1157. /// <summary>
  1158. /// 2nd row - 4nd column value of the Matrix.
  1159. /// </summary>
  1160. [FieldOffset(28)]
  1161. public float M24;
  1162. #endregion
  1163. #region M31 (Public)
  1164. /// <summary>
  1165. /// 3rd row - 1st column value of the Matrix.
  1166. /// </summary>
  1167. [FieldOffset(32)]
  1168. public float M31;
  1169. #endregion
  1170. #region M32 (Public)
  1171. /// <summary>
  1172. /// 3rd row - 2nd column value of the Matrix.
  1173. /// </summary>
  1174. [FieldOffset(36)]
  1175. public float M32;
  1176. #endregion
  1177. #region M33 (Public)
  1178. /// <summary>
  1179. /// 3rd row - 3rd column value of the Matrix.
  1180. /// </summary>
  1181. [FieldOffset(40)]
  1182. public float M33;
  1183. #endregion
  1184. #region M34 (Public)
  1185. /// <summary>
  1186. /// 3rd row - 4th column value of the Matrix.
  1187. /// </summary>
  1188. [FieldOffset(44)]
  1189. public float M34;
  1190. #endregion
  1191. #region M41 (Public)
  1192. /// <summary>
  1193. /// 4th row - 1st column value of the Matrix.
  1194. /// </summary>
  1195. [FieldOffset(48)]
  1196. public float M41;
  1197. #endregion
  1198. #region M42 (Public)
  1199. /// <summary>
  1200. /// 4th row - 2nd column value of the Matrix.
  1201. /// </summary>
  1202. [FieldOffset(52)]
  1203. public float M42;
  1204. #endregion
  1205. #region M43 (Public)
  1206. /// <summary>
  1207. /// 4th row - 3rd column value of the Matrix.
  1208. /// </summary>
  1209. [FieldOffset(56)]
  1210. public float M43;
  1211. #endregion
  1212. #region M44 (Public)
  1213. /// <summary>
  1214. /// 4th row - 4th column value of the Matrix.
  1215. /// </summary>
  1216. [FieldOffset(60)]
  1217. public float M44;
  1218. #endregion
  1219. #region Translation (Public)
  1220. /// <summary>
  1221. /// The translation amount representing by the matrix.
  1222. /// This vector shares the same data as M41, M42, M43, see above!
  1223. /// </summary>
  1224. [FieldOffset(48)]
  1225. public Vector Translation;
  1226. #endregion
  1227. #region Scaling (Public)
  1228. /// <summary>
  1229. /// The scaling amount representing by the matrix.
  1230. /// </summary>
  1231. public Vector Scaling
  1232. {
  1233. get
  1234. {
  1235. return new Vector(M11, M22, M33);
  1236. }
  1237. set
  1238. {
  1239. M11 = value.X;
  1240. M22 = value.Y;
  1241. M33 = value.Z;
  1242. }
  1243. }
  1244. #endregion
  1245. #region Right (Public)
  1246. /// <summary>
  1247. /// Right vector of the matrix (M11, M12, M13)
  1248. /// </summary>
  1249. [FieldOffset(0)]
  1250. public Vector Right;
  1251. #endregion
  1252. #region Up (Public)
  1253. /// <summary>
  1254. /// Up vector of the matrix (M21, M22, M23)
  1255. /// </summary>
  1256. [FieldOffset(16)]
  1257. public Vector Up;
  1258. #endregion
  1259. #region Front (Public)
  1260. /// <summary>
  1261. /// Front vector of the matrix (M31, M32, M33)
  1262. /// </summary>
  1263. [FieldOffset(32)]
  1264. public Vector Front;
  1265. #endregion
  1266. #region Determinant (Public)
  1267. /// <summary>
  1268. /// Returns the determinant of the matrix. Uses optimized code paths
  1269. /// because XNAs implementation is twice as fast as ours, OpenTK is
  1270. /// slightly faster (see MatrixPerformance class).
  1271. /// </summary>
  1272. public float Determinant
  1273. {
  1274. get
  1275. {
  1276. //Check performance difference again:
  1277. // Ugly hacky code that is actually lots faster than our clean
  1278. // implementation below (see link on how it works basically).
  1279. float m44x33m43x34 = (M44 * M33) - (M43 * M34);
  1280. float m32x44m42x34 = (M32 * M44) - (M42 * M34);
  1281. float m32x43m42x33 = (M32 * M43) - (M42 * M33);
  1282. float m31x44m41x34 = (M31 * M44) - (M41 * M34);
  1283. float m31x43m41x33 = (M31 * M43) - (M41 * M33);
  1284. float m31x42m41x32 = (M31 * M42) - (M41 * M32);
  1285. return (((((((M22 * m44x33m43x34) - (M23 * m32x44m42x34)) +
  1286. (M24 * m32x43m42x33)) * M11) - ((((M21 * m44x33m43x34) -
  1287. (M23 * m31x44m41x34)) +
  1288. (M24 * m31x43m41x33)) * M12)) +
  1289. ((((M21 * m32x44m42x34) - (M22 * m31x44m41x34)) +
  1290. (M24 * m31x42m41x32)) * M13)) - ((((M21 * m32x43m42x33) -
  1291. (M22 * m31x43m41x33)) +
  1292. (M23 * m31x42m41x32)) * M14));
  1293. }
  1294. }
  1295. #endregion
  1296. #region Inverse (Public)
  1297. /// <summary>
  1298. /// Returns the inverse of the current matrix, which can be…

Large files files are truncated, but you can click here to view the full file