Matrix4x4.cs 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Globalization;
  5. using System.Runtime.InteropServices;
  6. using System.Runtime.Intrinsics;
  7. using System.Runtime.Intrinsics.X86;
  8. namespace System.Numerics
  9. {
  10. /// <summary>
  11. /// A structure encapsulating a 4x4 matrix.
  12. /// </summary>
  13. [StructLayout(LayoutKind.Sequential)]
  14. public struct Matrix4x4 : IEquatable<Matrix4x4>
  15. {
  16. private const float BillboardEpsilon = 1e-4f;
  17. private const float BillboardMinAngle = 1.0f - (0.1f * (MathF.PI / 180.0f)); // 0.1 degrees
  18. private const float DecomposeEpsilon = 0.0001f;
  19. #region Public Fields
  20. /// <summary>
  21. /// Value at row 1, column 1 of the matrix.
  22. /// </summary>
  23. public float M11;
  24. /// <summary>
  25. /// Value at row 1, column 2 of the matrix.
  26. /// </summary>
  27. public float M12;
  28. /// <summary>
  29. /// Value at row 1, column 3 of the matrix.
  30. /// </summary>
  31. public float M13;
  32. /// <summary>
  33. /// Value at row 1, column 4 of the matrix.
  34. /// </summary>
  35. public float M14;
  36. /// <summary>
  37. /// Value at row 2, column 1 of the matrix.
  38. /// </summary>
  39. public float M21;
  40. /// <summary>
  41. /// Value at row 2, column 2 of the matrix.
  42. /// </summary>
  43. public float M22;
  44. /// <summary>
  45. /// Value at row 2, column 3 of the matrix.
  46. /// </summary>
  47. public float M23;
  48. /// <summary>
  49. /// Value at row 2, column 4 of the matrix.
  50. /// </summary>
  51. public float M24;
  52. /// <summary>
  53. /// Value at row 3, column 1 of the matrix.
  54. /// </summary>
  55. public float M31;
  56. /// <summary>
  57. /// Value at row 3, column 2 of the matrix.
  58. /// </summary>
  59. public float M32;
  60. /// <summary>
  61. /// Value at row 3, column 3 of the matrix.
  62. /// </summary>
  63. public float M33;
  64. /// <summary>
  65. /// Value at row 3, column 4 of the matrix.
  66. /// </summary>
  67. public float M34;
  68. /// <summary>
  69. /// Value at row 4, column 1 of the matrix.
  70. /// </summary>
  71. public float M41;
  72. /// <summary>
  73. /// Value at row 4, column 2 of the matrix.
  74. /// </summary>
  75. public float M42;
  76. /// <summary>
  77. /// Value at row 4, column 3 of the matrix.
  78. /// </summary>
  79. public float M43;
  80. /// <summary>
  81. /// Value at row 4, column 4 of the matrix.
  82. /// </summary>
  83. public float M44;
  84. #endregion Public Fields
  85. private static readonly Matrix4x4 _identity = new Matrix4x4
  86. (
  87. 1f, 0f, 0f, 0f,
  88. 0f, 1f, 0f, 0f,
  89. 0f, 0f, 1f, 0f,
  90. 0f, 0f, 0f, 1f
  91. );
  92. /// <summary>
  93. /// Returns the multiplicative identity matrix.
  94. /// </summary>
  95. public static Matrix4x4 Identity
  96. {
  97. get { return _identity; }
  98. }
  99. /// <summary>
  100. /// Returns whether the matrix is the identity matrix.
  101. /// </summary>
  102. public readonly bool IsIdentity
  103. {
  104. get
  105. {
  106. return M11 == 1f && M22 == 1f && M33 == 1f && M44 == 1f && // Check diagonal element first for early out.
  107. M12 == 0f && M13 == 0f && M14 == 0f &&
  108. M21 == 0f && M23 == 0f && M24 == 0f &&
  109. M31 == 0f && M32 == 0f && M34 == 0f &&
  110. M41 == 0f && M42 == 0f && M43 == 0f;
  111. }
  112. }
  113. /// <summary>
  114. /// Gets or sets the translation component of this matrix.
  115. /// </summary>
  116. public Vector3 Translation
  117. {
  118. readonly get
  119. {
  120. return new Vector3(M41, M42, M43);
  121. }
  122. set
  123. {
  124. M41 = value.X;
  125. M42 = value.Y;
  126. M43 = value.Z;
  127. }
  128. }
  129. /// <summary>
  130. /// Constructs a Matrix4x4 from the given components.
  131. /// </summary>
  132. public Matrix4x4(float m11, float m12, float m13, float m14,
  133. float m21, float m22, float m23, float m24,
  134. float m31, float m32, float m33, float m34,
  135. float m41, float m42, float m43, float m44)
  136. {
  137. this.M11 = m11;
  138. this.M12 = m12;
  139. this.M13 = m13;
  140. this.M14 = m14;
  141. this.M21 = m21;
  142. this.M22 = m22;
  143. this.M23 = m23;
  144. this.M24 = m24;
  145. this.M31 = m31;
  146. this.M32 = m32;
  147. this.M33 = m33;
  148. this.M34 = m34;
  149. this.M41 = m41;
  150. this.M42 = m42;
  151. this.M43 = m43;
  152. this.M44 = m44;
  153. }
  154. /// <summary>
  155. /// Constructs a Matrix4x4 from the given Matrix3x2.
  156. /// </summary>
  157. /// <param name="value">The source Matrix3x2.</param>
  158. public Matrix4x4(Matrix3x2 value)
  159. {
  160. M11 = value.M11;
  161. M12 = value.M12;
  162. M13 = 0f;
  163. M14 = 0f;
  164. M21 = value.M21;
  165. M22 = value.M22;
  166. M23 = 0f;
  167. M24 = 0f;
  168. M31 = 0f;
  169. M32 = 0f;
  170. M33 = 1f;
  171. M34 = 0f;
  172. M41 = value.M31;
  173. M42 = value.M32;
  174. M43 = 0f;
  175. M44 = 1f;
  176. }
  177. /// <summary>
  178. /// Creates a spherical billboard that rotates around a specified object position.
  179. /// </summary>
  180. /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
  181. /// <param name="cameraPosition">Position of the camera.</param>
  182. /// <param name="cameraUpVector">The up vector of the camera.</param>
  183. /// <param name="cameraForwardVector">The forward vector of the camera.</param>
  184. /// <returns>The created billboard matrix</returns>
  185. public static Matrix4x4 CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 cameraUpVector, Vector3 cameraForwardVector)
  186. {
  187. Vector3 zaxis = new Vector3(
  188. objectPosition.X - cameraPosition.X,
  189. objectPosition.Y - cameraPosition.Y,
  190. objectPosition.Z - cameraPosition.Z);
  191. float norm = zaxis.LengthSquared();
  192. if (norm < BillboardEpsilon)
  193. {
  194. zaxis = -cameraForwardVector;
  195. }
  196. else
  197. {
  198. zaxis = Vector3.Multiply(zaxis, 1.0f / MathF.Sqrt(norm));
  199. }
  200. Vector3 xaxis = Vector3.Normalize(Vector3.Cross(cameraUpVector, zaxis));
  201. Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
  202. Matrix4x4 result;
  203. result.M11 = xaxis.X;
  204. result.M12 = xaxis.Y;
  205. result.M13 = xaxis.Z;
  206. result.M14 = 0.0f;
  207. result.M21 = yaxis.X;
  208. result.M22 = yaxis.Y;
  209. result.M23 = yaxis.Z;
  210. result.M24 = 0.0f;
  211. result.M31 = zaxis.X;
  212. result.M32 = zaxis.Y;
  213. result.M33 = zaxis.Z;
  214. result.M34 = 0.0f;
  215. result.M41 = objectPosition.X;
  216. result.M42 = objectPosition.Y;
  217. result.M43 = objectPosition.Z;
  218. result.M44 = 1.0f;
  219. return result;
  220. }
  221. /// <summary>
  222. /// Creates a cylindrical billboard that rotates around a specified axis.
  223. /// </summary>
  224. /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
  225. /// <param name="cameraPosition">Position of the camera.</param>
  226. /// <param name="rotateAxis">Axis to rotate the billboard around.</param>
  227. /// <param name="cameraForwardVector">Forward vector of the camera.</param>
  228. /// <param name="objectForwardVector">Forward vector of the object.</param>
  229. /// <returns>The created billboard matrix.</returns>
  230. public static Matrix4x4 CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector)
  231. {
  232. // Treat the case when object and camera positions are too close.
  233. Vector3 faceDir = new Vector3(
  234. objectPosition.X - cameraPosition.X,
  235. objectPosition.Y - cameraPosition.Y,
  236. objectPosition.Z - cameraPosition.Z);
  237. float norm = faceDir.LengthSquared();
  238. if (norm < BillboardEpsilon)
  239. {
  240. faceDir = -cameraForwardVector;
  241. }
  242. else
  243. {
  244. faceDir = Vector3.Multiply(faceDir, (1.0f / MathF.Sqrt(norm)));
  245. }
  246. Vector3 yaxis = rotateAxis;
  247. Vector3 xaxis;
  248. Vector3 zaxis;
  249. // Treat the case when angle between faceDir and rotateAxis is too close to 0.
  250. float dot = Vector3.Dot(rotateAxis, faceDir);
  251. if (MathF.Abs(dot) > BillboardMinAngle)
  252. {
  253. zaxis = objectForwardVector;
  254. // Make sure passed values are useful for compute.
  255. dot = Vector3.Dot(rotateAxis, zaxis);
  256. if (MathF.Abs(dot) > BillboardMinAngle)
  257. {
  258. zaxis = (MathF.Abs(rotateAxis.Z) > BillboardMinAngle) ? new Vector3(1, 0, 0) : new Vector3(0, 0, -1);
  259. }
  260. xaxis = Vector3.Normalize(Vector3.Cross(rotateAxis, zaxis));
  261. zaxis = Vector3.Normalize(Vector3.Cross(xaxis, rotateAxis));
  262. }
  263. else
  264. {
  265. xaxis = Vector3.Normalize(Vector3.Cross(rotateAxis, faceDir));
  266. zaxis = Vector3.Normalize(Vector3.Cross(xaxis, yaxis));
  267. }
  268. Matrix4x4 result;
  269. result.M11 = xaxis.X;
  270. result.M12 = xaxis.Y;
  271. result.M13 = xaxis.Z;
  272. result.M14 = 0.0f;
  273. result.M21 = yaxis.X;
  274. result.M22 = yaxis.Y;
  275. result.M23 = yaxis.Z;
  276. result.M24 = 0.0f;
  277. result.M31 = zaxis.X;
  278. result.M32 = zaxis.Y;
  279. result.M33 = zaxis.Z;
  280. result.M34 = 0.0f;
  281. result.M41 = objectPosition.X;
  282. result.M42 = objectPosition.Y;
  283. result.M43 = objectPosition.Z;
  284. result.M44 = 1.0f;
  285. return result;
  286. }
  287. /// <summary>
  288. /// Creates a translation matrix.
  289. /// </summary>
  290. /// <param name="position">The amount to translate in each axis.</param>
  291. /// <returns>The translation matrix.</returns>
  292. public static Matrix4x4 CreateTranslation(Vector3 position)
  293. {
  294. Matrix4x4 result;
  295. result.M11 = 1.0f;
  296. result.M12 = 0.0f;
  297. result.M13 = 0.0f;
  298. result.M14 = 0.0f;
  299. result.M21 = 0.0f;
  300. result.M22 = 1.0f;
  301. result.M23 = 0.0f;
  302. result.M24 = 0.0f;
  303. result.M31 = 0.0f;
  304. result.M32 = 0.0f;
  305. result.M33 = 1.0f;
  306. result.M34 = 0.0f;
  307. result.M41 = position.X;
  308. result.M42 = position.Y;
  309. result.M43 = position.Z;
  310. result.M44 = 1.0f;
  311. return result;
  312. }
  313. /// <summary>
  314. /// Creates a translation matrix.
  315. /// </summary>
  316. /// <param name="xPosition">The amount to translate on the X-axis.</param>
  317. /// <param name="yPosition">The amount to translate on the Y-axis.</param>
  318. /// <param name="zPosition">The amount to translate on the Z-axis.</param>
  319. /// <returns>The translation matrix.</returns>
  320. public static Matrix4x4 CreateTranslation(float xPosition, float yPosition, float zPosition)
  321. {
  322. Matrix4x4 result;
  323. result.M11 = 1.0f;
  324. result.M12 = 0.0f;
  325. result.M13 = 0.0f;
  326. result.M14 = 0.0f;
  327. result.M21 = 0.0f;
  328. result.M22 = 1.0f;
  329. result.M23 = 0.0f;
  330. result.M24 = 0.0f;
  331. result.M31 = 0.0f;
  332. result.M32 = 0.0f;
  333. result.M33 = 1.0f;
  334. result.M34 = 0.0f;
  335. result.M41 = xPosition;
  336. result.M42 = yPosition;
  337. result.M43 = zPosition;
  338. result.M44 = 1.0f;
  339. return result;
  340. }
  341. /// <summary>
  342. /// Creates a scaling matrix.
  343. /// </summary>
  344. /// <param name="xScale">Value to scale by on the X-axis.</param>
  345. /// <param name="yScale">Value to scale by on the Y-axis.</param>
  346. /// <param name="zScale">Value to scale by on the Z-axis.</param>
  347. /// <returns>The scaling matrix.</returns>
  348. public static Matrix4x4 CreateScale(float xScale, float yScale, float zScale)
  349. {
  350. Matrix4x4 result;
  351. result.M11 = xScale;
  352. result.M12 = 0.0f;
  353. result.M13 = 0.0f;
  354. result.M14 = 0.0f;
  355. result.M21 = 0.0f;
  356. result.M22 = yScale;
  357. result.M23 = 0.0f;
  358. result.M24 = 0.0f;
  359. result.M31 = 0.0f;
  360. result.M32 = 0.0f;
  361. result.M33 = zScale;
  362. result.M34 = 0.0f;
  363. result.M41 = 0.0f;
  364. result.M42 = 0.0f;
  365. result.M43 = 0.0f;
  366. result.M44 = 1.0f;
  367. return result;
  368. }
  369. /// <summary>
  370. /// Creates a scaling matrix with a center point.
  371. /// </summary>
  372. /// <param name="xScale">Value to scale by on the X-axis.</param>
  373. /// <param name="yScale">Value to scale by on the Y-axis.</param>
  374. /// <param name="zScale">Value to scale by on the Z-axis.</param>
  375. /// <param name="centerPoint">The center point.</param>
  376. /// <returns>The scaling matrix.</returns>
  377. public static Matrix4x4 CreateScale(float xScale, float yScale, float zScale, Vector3 centerPoint)
  378. {
  379. Matrix4x4 result;
  380. float tx = centerPoint.X * (1 - xScale);
  381. float ty = centerPoint.Y * (1 - yScale);
  382. float tz = centerPoint.Z * (1 - zScale);
  383. result.M11 = xScale;
  384. result.M12 = 0.0f;
  385. result.M13 = 0.0f;
  386. result.M14 = 0.0f;
  387. result.M21 = 0.0f;
  388. result.M22 = yScale;
  389. result.M23 = 0.0f;
  390. result.M24 = 0.0f;
  391. result.M31 = 0.0f;
  392. result.M32 = 0.0f;
  393. result.M33 = zScale;
  394. result.M34 = 0.0f;
  395. result.M41 = tx;
  396. result.M42 = ty;
  397. result.M43 = tz;
  398. result.M44 = 1.0f;
  399. return result;
  400. }
  401. /// <summary>
  402. /// Creates a scaling matrix.
  403. /// </summary>
  404. /// <param name="scales">The vector containing the amount to scale by on each axis.</param>
  405. /// <returns>The scaling matrix.</returns>
  406. public static Matrix4x4 CreateScale(Vector3 scales)
  407. {
  408. Matrix4x4 result;
  409. result.M11 = scales.X;
  410. result.M12 = 0.0f;
  411. result.M13 = 0.0f;
  412. result.M14 = 0.0f;
  413. result.M21 = 0.0f;
  414. result.M22 = scales.Y;
  415. result.M23 = 0.0f;
  416. result.M24 = 0.0f;
  417. result.M31 = 0.0f;
  418. result.M32 = 0.0f;
  419. result.M33 = scales.Z;
  420. result.M34 = 0.0f;
  421. result.M41 = 0.0f;
  422. result.M42 = 0.0f;
  423. result.M43 = 0.0f;
  424. result.M44 = 1.0f;
  425. return result;
  426. }
  427. /// <summary>
  428. /// Creates a scaling matrix with a center point.
  429. /// </summary>
  430. /// <param name="scales">The vector containing the amount to scale by on each axis.</param>
  431. /// <param name="centerPoint">The center point.</param>
  432. /// <returns>The scaling matrix.</returns>
  433. public static Matrix4x4 CreateScale(Vector3 scales, Vector3 centerPoint)
  434. {
  435. Matrix4x4 result;
  436. float tx = centerPoint.X * (1 - scales.X);
  437. float ty = centerPoint.Y * (1 - scales.Y);
  438. float tz = centerPoint.Z * (1 - scales.Z);
  439. result.M11 = scales.X;
  440. result.M12 = 0.0f;
  441. result.M13 = 0.0f;
  442. result.M14 = 0.0f;
  443. result.M21 = 0.0f;
  444. result.M22 = scales.Y;
  445. result.M23 = 0.0f;
  446. result.M24 = 0.0f;
  447. result.M31 = 0.0f;
  448. result.M32 = 0.0f;
  449. result.M33 = scales.Z;
  450. result.M34 = 0.0f;
  451. result.M41 = tx;
  452. result.M42 = ty;
  453. result.M43 = tz;
  454. result.M44 = 1.0f;
  455. return result;
  456. }
  457. /// <summary>
  458. /// Creates a uniform scaling matrix that scales equally on each axis.
  459. /// </summary>
  460. /// <param name="scale">The uniform scaling factor.</param>
  461. /// <returns>The scaling matrix.</returns>
  462. public static Matrix4x4 CreateScale(float scale)
  463. {
  464. Matrix4x4 result;
  465. result.M11 = scale;
  466. result.M12 = 0.0f;
  467. result.M13 = 0.0f;
  468. result.M14 = 0.0f;
  469. result.M21 = 0.0f;
  470. result.M22 = scale;
  471. result.M23 = 0.0f;
  472. result.M24 = 0.0f;
  473. result.M31 = 0.0f;
  474. result.M32 = 0.0f;
  475. result.M33 = scale;
  476. result.M34 = 0.0f;
  477. result.M41 = 0.0f;
  478. result.M42 = 0.0f;
  479. result.M43 = 0.0f;
  480. result.M44 = 1.0f;
  481. return result;
  482. }
  483. /// <summary>
  484. /// Creates a uniform scaling matrix that scales equally on each axis with a center point.
  485. /// </summary>
  486. /// <param name="scale">The uniform scaling factor.</param>
  487. /// <param name="centerPoint">The center point.</param>
  488. /// <returns>The scaling matrix.</returns>
  489. public static Matrix4x4 CreateScale(float scale, Vector3 centerPoint)
  490. {
  491. Matrix4x4 result;
  492. float tx = centerPoint.X * (1 - scale);
  493. float ty = centerPoint.Y * (1 - scale);
  494. float tz = centerPoint.Z * (1 - scale);
  495. result.M11 = scale;
  496. result.M12 = 0.0f;
  497. result.M13 = 0.0f;
  498. result.M14 = 0.0f;
  499. result.M21 = 0.0f;
  500. result.M22 = scale;
  501. result.M23 = 0.0f;
  502. result.M24 = 0.0f;
  503. result.M31 = 0.0f;
  504. result.M32 = 0.0f;
  505. result.M33 = scale;
  506. result.M34 = 0.0f;
  507. result.M41 = tx;
  508. result.M42 = ty;
  509. result.M43 = tz;
  510. result.M44 = 1.0f;
  511. return result;
  512. }
  513. /// <summary>
  514. /// Creates a matrix for rotating points around the X-axis.
  515. /// </summary>
  516. /// <param name="radians">The amount, in radians, by which to rotate around the X-axis.</param>
  517. /// <returns>The rotation matrix.</returns>
  518. public static Matrix4x4 CreateRotationX(float radians)
  519. {
  520. Matrix4x4 result;
  521. float c = MathF.Cos(radians);
  522. float s = MathF.Sin(radians);
  523. // [ 1 0 0 0 ]
  524. // [ 0 c s 0 ]
  525. // [ 0 -s c 0 ]
  526. // [ 0 0 0 1 ]
  527. result.M11 = 1.0f;
  528. result.M12 = 0.0f;
  529. result.M13 = 0.0f;
  530. result.M14 = 0.0f;
  531. result.M21 = 0.0f;
  532. result.M22 = c;
  533. result.M23 = s;
  534. result.M24 = 0.0f;
  535. result.M31 = 0.0f;
  536. result.M32 = -s;
  537. result.M33 = c;
  538. result.M34 = 0.0f;
  539. result.M41 = 0.0f;
  540. result.M42 = 0.0f;
  541. result.M43 = 0.0f;
  542. result.M44 = 1.0f;
  543. return result;
  544. }
  545. /// <summary>
  546. /// Creates a matrix for rotating points around the X-axis, from a center point.
  547. /// </summary>
  548. /// <param name="radians">The amount, in radians, by which to rotate around the X-axis.</param>
  549. /// <param name="centerPoint">The center point.</param>
  550. /// <returns>The rotation matrix.</returns>
  551. public static Matrix4x4 CreateRotationX(float radians, Vector3 centerPoint)
  552. {
  553. Matrix4x4 result;
  554. float c = MathF.Cos(radians);
  555. float s = MathF.Sin(radians);
  556. float y = centerPoint.Y * (1 - c) + centerPoint.Z * s;
  557. float z = centerPoint.Z * (1 - c) - centerPoint.Y * s;
  558. // [ 1 0 0 0 ]
  559. // [ 0 c s 0 ]
  560. // [ 0 -s c 0 ]
  561. // [ 0 y z 1 ]
  562. result.M11 = 1.0f;
  563. result.M12 = 0.0f;
  564. result.M13 = 0.0f;
  565. result.M14 = 0.0f;
  566. result.M21 = 0.0f;
  567. result.M22 = c;
  568. result.M23 = s;
  569. result.M24 = 0.0f;
  570. result.M31 = 0.0f;
  571. result.M32 = -s;
  572. result.M33 = c;
  573. result.M34 = 0.0f;
  574. result.M41 = 0.0f;
  575. result.M42 = y;
  576. result.M43 = z;
  577. result.M44 = 1.0f;
  578. return result;
  579. }
  580. /// <summary>
  581. /// Creates a matrix for rotating points around the Y-axis.
  582. /// </summary>
  583. /// <param name="radians">The amount, in radians, by which to rotate around the Y-axis.</param>
  584. /// <returns>The rotation matrix.</returns>
  585. public static Matrix4x4 CreateRotationY(float radians)
  586. {
  587. Matrix4x4 result;
  588. float c = MathF.Cos(radians);
  589. float s = MathF.Sin(radians);
  590. // [ c 0 -s 0 ]
  591. // [ 0 1 0 0 ]
  592. // [ s 0 c 0 ]
  593. // [ 0 0 0 1 ]
  594. result.M11 = c;
  595. result.M12 = 0.0f;
  596. result.M13 = -s;
  597. result.M14 = 0.0f;
  598. result.M21 = 0.0f;
  599. result.M22 = 1.0f;
  600. result.M23 = 0.0f;
  601. result.M24 = 0.0f;
  602. result.M31 = s;
  603. result.M32 = 0.0f;
  604. result.M33 = c;
  605. result.M34 = 0.0f;
  606. result.M41 = 0.0f;
  607. result.M42 = 0.0f;
  608. result.M43 = 0.0f;
  609. result.M44 = 1.0f;
  610. return result;
  611. }
  612. /// <summary>
  613. /// Creates a matrix for rotating points around the Y-axis, from a center point.
  614. /// </summary>
  615. /// <param name="radians">The amount, in radians, by which to rotate around the Y-axis.</param>
  616. /// <param name="centerPoint">The center point.</param>
  617. /// <returns>The rotation matrix.</returns>
  618. public static Matrix4x4 CreateRotationY(float radians, Vector3 centerPoint)
  619. {
  620. Matrix4x4 result;
  621. float c = MathF.Cos(radians);
  622. float s = MathF.Sin(radians);
  623. float x = centerPoint.X * (1 - c) - centerPoint.Z * s;
  624. float z = centerPoint.Z * (1 - c) + centerPoint.X * s;
  625. // [ c 0 -s 0 ]
  626. // [ 0 1 0 0 ]
  627. // [ s 0 c 0 ]
  628. // [ x 0 z 1 ]
  629. result.M11 = c;
  630. result.M12 = 0.0f;
  631. result.M13 = -s;
  632. result.M14 = 0.0f;
  633. result.M21 = 0.0f;
  634. result.M22 = 1.0f;
  635. result.M23 = 0.0f;
  636. result.M24 = 0.0f;
  637. result.M31 = s;
  638. result.M32 = 0.0f;
  639. result.M33 = c;
  640. result.M34 = 0.0f;
  641. result.M41 = x;
  642. result.M42 = 0.0f;
  643. result.M43 = z;
  644. result.M44 = 1.0f;
  645. return result;
  646. }
  647. /// <summary>
  648. /// Creates a matrix for rotating points around the Z-axis.
  649. /// </summary>
  650. /// <param name="radians">The amount, in radians, by which to rotate around the Z-axis.</param>
  651. /// <returns>The rotation matrix.</returns>
  652. public static Matrix4x4 CreateRotationZ(float radians)
  653. {
  654. Matrix4x4 result;
  655. float c = MathF.Cos(radians);
  656. float s = MathF.Sin(radians);
  657. // [ c s 0 0 ]
  658. // [ -s c 0 0 ]
  659. // [ 0 0 1 0 ]
  660. // [ 0 0 0 1 ]
  661. result.M11 = c;
  662. result.M12 = s;
  663. result.M13 = 0.0f;
  664. result.M14 = 0.0f;
  665. result.M21 = -s;
  666. result.M22 = c;
  667. result.M23 = 0.0f;
  668. result.M24 = 0.0f;
  669. result.M31 = 0.0f;
  670. result.M32 = 0.0f;
  671. result.M33 = 1.0f;
  672. result.M34 = 0.0f;
  673. result.M41 = 0.0f;
  674. result.M42 = 0.0f;
  675. result.M43 = 0.0f;
  676. result.M44 = 1.0f;
  677. return result;
  678. }
  679. /// <summary>
  680. /// Creates a matrix for rotating points around the Z-axis, from a center point.
  681. /// </summary>
  682. /// <param name="radians">The amount, in radians, by which to rotate around the Z-axis.</param>
  683. /// <param name="centerPoint">The center point.</param>
  684. /// <returns>The rotation matrix.</returns>
  685. public static Matrix4x4 CreateRotationZ(float radians, Vector3 centerPoint)
  686. {
  687. Matrix4x4 result;
  688. float c = MathF.Cos(radians);
  689. float s = MathF.Sin(radians);
  690. float x = centerPoint.X * (1 - c) + centerPoint.Y * s;
  691. float y = centerPoint.Y * (1 - c) - centerPoint.X * s;
  692. // [ c s 0 0 ]
  693. // [ -s c 0 0 ]
  694. // [ 0 0 1 0 ]
  695. // [ x y 0 1 ]
  696. result.M11 = c;
  697. result.M12 = s;
  698. result.M13 = 0.0f;
  699. result.M14 = 0.0f;
  700. result.M21 = -s;
  701. result.M22 = c;
  702. result.M23 = 0.0f;
  703. result.M24 = 0.0f;
  704. result.M31 = 0.0f;
  705. result.M32 = 0.0f;
  706. result.M33 = 1.0f;
  707. result.M34 = 0.0f;
  708. result.M41 = x;
  709. result.M42 = y;
  710. result.M43 = 0.0f;
  711. result.M44 = 1.0f;
  712. return result;
  713. }
  714. /// <summary>
  715. /// Creates a matrix that rotates around an arbitrary vector.
  716. /// </summary>
  717. /// <param name="axis">The axis to rotate around.</param>
  718. /// <param name="angle">The angle to rotate around the given axis, in radians.</param>
  719. /// <returns>The rotation matrix.</returns>
  720. public static Matrix4x4 CreateFromAxisAngle(Vector3 axis, float angle)
  721. {
  722. // a: angle
  723. // x, y, z: unit vector for axis.
  724. //
  725. // Rotation matrix M can compute by using below equation.
  726. //
  727. // T T
  728. // M = uu + (cos a)( I-uu ) + (sin a)S
  729. //
  730. // Where:
  731. //
  732. // u = ( x, y, z )
  733. //
  734. // [ 0 -z y ]
  735. // S = [ z 0 -x ]
  736. // [ -y x 0 ]
  737. //
  738. // [ 1 0 0 ]
  739. // I = [ 0 1 0 ]
  740. // [ 0 0 1 ]
  741. //
  742. //
  743. // [ xx+cosa*(1-xx) yx-cosa*yx-sina*z zx-cosa*xz+sina*y ]
  744. // M = [ xy-cosa*yx+sina*z yy+cosa(1-yy) yz-cosa*yz-sina*x ]
  745. // [ zx-cosa*zx-sina*y zy-cosa*zy+sina*x zz+cosa*(1-zz) ]
  746. //
  747. float x = axis.X, y = axis.Y, z = axis.Z;
  748. float sa = MathF.Sin(angle), ca = MathF.Cos(angle);
  749. float xx = x * x, yy = y * y, zz = z * z;
  750. float xy = x * y, xz = x * z, yz = y * z;
  751. Matrix4x4 result;
  752. result.M11 = xx + ca * (1.0f - xx);
  753. result.M12 = xy - ca * xy + sa * z;
  754. result.M13 = xz - ca * xz - sa * y;
  755. result.M14 = 0.0f;
  756. result.M21 = xy - ca * xy - sa * z;
  757. result.M22 = yy + ca * (1.0f - yy);
  758. result.M23 = yz - ca * yz + sa * x;
  759. result.M24 = 0.0f;
  760. result.M31 = xz - ca * xz + sa * y;
  761. result.M32 = yz - ca * yz - sa * x;
  762. result.M33 = zz + ca * (1.0f - zz);
  763. result.M34 = 0.0f;
  764. result.M41 = 0.0f;
  765. result.M42 = 0.0f;
  766. result.M43 = 0.0f;
  767. result.M44 = 1.0f;
  768. return result;
  769. }
  770. /// <summary>
  771. /// Creates a perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances.
  772. /// </summary>
  773. /// <param name="fieldOfView">Field of view in the y direction, in radians.</param>
  774. /// <param name="aspectRatio">Aspect ratio, defined as view space width divided by height.</param>
  775. /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
  776. /// <param name="farPlaneDistance">Distance to the far view plane.</param>
  777. /// <returns>The perspective projection matrix.</returns>
  778. public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
  779. {
  780. if (fieldOfView <= 0.0f || fieldOfView >= MathF.PI)
  781. throw new ArgumentOutOfRangeException(nameof(fieldOfView));
  782. if (nearPlaneDistance <= 0.0f)
  783. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  784. if (farPlaneDistance <= 0.0f)
  785. throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
  786. if (nearPlaneDistance >= farPlaneDistance)
  787. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  788. float yScale = 1.0f / MathF.Tan(fieldOfView * 0.5f);
  789. float xScale = yScale / aspectRatio;
  790. Matrix4x4 result;
  791. result.M11 = xScale;
  792. result.M12 = result.M13 = result.M14 = 0.0f;
  793. result.M22 = yScale;
  794. result.M21 = result.M23 = result.M24 = 0.0f;
  795. result.M31 = result.M32 = 0.0f;
  796. var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
  797. result.M33 = negFarRange;
  798. result.M34 = -1.0f;
  799. result.M41 = result.M42 = result.M44 = 0.0f;
  800. result.M43 = nearPlaneDistance * negFarRange;
  801. return result;
  802. }
  803. /// <summary>
  804. /// Creates a perspective projection matrix from the given view volume dimensions.
  805. /// </summary>
  806. /// <param name="width">Width of the view volume at the near view plane.</param>
  807. /// <param name="height">Height of the view volume at the near view plane.</param>
  808. /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
  809. /// <param name="farPlaneDistance">Distance to the far view plane.</param>
  810. /// <returns>The perspective projection matrix.</returns>
  811. public static Matrix4x4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance)
  812. {
  813. if (nearPlaneDistance <= 0.0f)
  814. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  815. if (farPlaneDistance <= 0.0f)
  816. throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
  817. if (nearPlaneDistance >= farPlaneDistance)
  818. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  819. Matrix4x4 result;
  820. result.M11 = 2.0f * nearPlaneDistance / width;
  821. result.M12 = result.M13 = result.M14 = 0.0f;
  822. result.M22 = 2.0f * nearPlaneDistance / height;
  823. result.M21 = result.M23 = result.M24 = 0.0f;
  824. var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
  825. result.M33 = negFarRange;
  826. result.M31 = result.M32 = 0.0f;
  827. result.M34 = -1.0f;
  828. result.M41 = result.M42 = result.M44 = 0.0f;
  829. result.M43 = nearPlaneDistance * negFarRange;
  830. return result;
  831. }
  832. /// <summary>
  833. /// Creates a customized, perspective projection matrix.
  834. /// </summary>
  835. /// <param name="left">Minimum x-value of the view volume at the near view plane.</param>
  836. /// <param name="right">Maximum x-value of the view volume at the near view plane.</param>
  837. /// <param name="bottom">Minimum y-value of the view volume at the near view plane.</param>
  838. /// <param name="top">Maximum y-value of the view volume at the near view plane.</param>
  839. /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
  840. /// <param name="farPlaneDistance">Distance to of the far view plane.</param>
  841. /// <returns>The perspective projection matrix.</returns>
  842. public static Matrix4x4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance)
  843. {
  844. if (nearPlaneDistance <= 0.0f)
  845. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  846. if (farPlaneDistance <= 0.0f)
  847. throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
  848. if (nearPlaneDistance >= farPlaneDistance)
  849. throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
  850. Matrix4x4 result;
  851. result.M11 = 2.0f * nearPlaneDistance / (right - left);
  852. result.M12 = result.M13 = result.M14 = 0.0f;
  853. result.M22 = 2.0f * nearPlaneDistance / (top - bottom);
  854. result.M21 = result.M23 = result.M24 = 0.0f;
  855. result.M31 = (left + right) / (right - left);
  856. result.M32 = (top + bottom) / (top - bottom);
  857. var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
  858. result.M33 = negFarRange;
  859. result.M34 = -1.0f;
  860. result.M43 = nearPlaneDistance * negFarRange;
  861. result.M41 = result.M42 = result.M44 = 0.0f;
  862. return result;
  863. }
  864. /// <summary>
  865. /// Creates an orthographic perspective matrix from the given view volume dimensions.
  866. /// </summary>
  867. /// <param name="width">Width of the view volume.</param>
  868. /// <param name="height">Height of the view volume.</param>
  869. /// <param name="zNearPlane">Minimum Z-value of the view volume.</param>
  870. /// <param name="zFarPlane">Maximum Z-value of the view volume.</param>
  871. /// <returns>The orthographic projection matrix.</returns>
  872. public static Matrix4x4 CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane)
  873. {
  874. Matrix4x4 result;
  875. result.M11 = 2.0f / width;
  876. result.M12 = result.M13 = result.M14 = 0.0f;
  877. result.M22 = 2.0f / height;
  878. result.M21 = result.M23 = result.M24 = 0.0f;
  879. result.M33 = 1.0f / (zNearPlane - zFarPlane);
  880. result.M31 = result.M32 = result.M34 = 0.0f;
  881. result.M41 = result.M42 = 0.0f;
  882. result.M43 = zNearPlane / (zNearPlane - zFarPlane);
  883. result.M44 = 1.0f;
  884. return result;
  885. }
  886. /// <summary>
  887. /// Builds a customized, orthographic projection matrix.
  888. /// </summary>
  889. /// <param name="left">Minimum X-value of the view volume.</param>
  890. /// <param name="right">Maximum X-value of the view volume.</param>
  891. /// <param name="bottom">Minimum Y-value of the view volume.</param>
  892. /// <param name="top">Maximum Y-value of the view volume.</param>
  893. /// <param name="zNearPlane">Minimum Z-value of the view volume.</param>
  894. /// <param name="zFarPlane">Maximum Z-value of the view volume.</param>
  895. /// <returns>The orthographic projection matrix.</returns>
  896. public static Matrix4x4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane)
  897. {
  898. Matrix4x4 result;
  899. result.M11 = 2.0f / (right - left);
  900. result.M12 = result.M13 = result.M14 = 0.0f;
  901. result.M22 = 2.0f / (top - bottom);
  902. result.M21 = result.M23 = result.M24 = 0.0f;
  903. result.M33 = 1.0f / (zNearPlane - zFarPlane);
  904. result.M31 = result.M32 = result.M34 = 0.0f;
  905. result.M41 = (left + right) / (left - right);
  906. result.M42 = (top + bottom) / (bottom - top);
  907. result.M43 = zNearPlane / (zNearPlane - zFarPlane);
  908. result.M44 = 1.0f;
  909. return result;
  910. }
  911. /// <summary>
  912. /// Creates a view matrix.
  913. /// </summary>
  914. /// <param name="cameraPosition">The position of the camera.</param>
  915. /// <param name="cameraTarget">The target towards which the camera is pointing.</param>
  916. /// <param name="cameraUpVector">The direction that is "up" from the camera's point of view.</param>
  917. /// <returns>The view matrix.</returns>
  918. public static Matrix4x4 CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
  919. {
  920. Vector3 zaxis = Vector3.Normalize(cameraPosition - cameraTarget);
  921. Vector3 xaxis = Vector3.Normalize(Vector3.Cross(cameraUpVector, zaxis));
  922. Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
  923. Matrix4x4 result;
  924. result.M11 = xaxis.X;
  925. result.M12 = yaxis.X;
  926. result.M13 = zaxis.X;
  927. result.M14 = 0.0f;
  928. result.M21 = xaxis.Y;
  929. result.M22 = yaxis.Y;
  930. result.M23 = zaxis.Y;
  931. result.M24 = 0.0f;
  932. result.M31 = xaxis.Z;
  933. result.M32 = yaxis.Z;
  934. result.M33 = zaxis.Z;
  935. result.M34 = 0.0f;
  936. result.M41 = -Vector3.Dot(xaxis, cameraPosition);
  937. result.M42 = -Vector3.Dot(yaxis, cameraPosition);
  938. result.M43 = -Vector3.Dot(zaxis, cameraPosition);
  939. result.M44 = 1.0f;
  940. return result;
  941. }
  942. /// <summary>
  943. /// Creates a world matrix with the specified parameters.
  944. /// </summary>
  945. /// <param name="position">The position of the object; used in translation operations.</param>
  946. /// <param name="forward">Forward direction of the object.</param>
  947. /// <param name="up">Upward direction of the object; usually [0, 1, 0].</param>
  948. /// <returns>The world matrix.</returns>
  949. public static Matrix4x4 CreateWorld(Vector3 position, Vector3 forward, Vector3 up)
  950. {
  951. Vector3 zaxis = Vector3.Normalize(-forward);
  952. Vector3 xaxis = Vector3.Normalize(Vector3.Cross(up, zaxis));
  953. Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
  954. Matrix4x4 result;
  955. result.M11 = xaxis.X;
  956. result.M12 = xaxis.Y;
  957. result.M13 = xaxis.Z;
  958. result.M14 = 0.0f;
  959. result.M21 = yaxis.X;
  960. result.M22 = yaxis.Y;
  961. result.M23 = yaxis.Z;
  962. result.M24 = 0.0f;
  963. result.M31 = zaxis.X;
  964. result.M32 = zaxis.Y;
  965. result.M33 = zaxis.Z;
  966. result.M34 = 0.0f;
  967. result.M41 = position.X;
  968. result.M42 = position.Y;
  969. result.M43 = position.Z;
  970. result.M44 = 1.0f;
  971. return result;
  972. }
  973. /// <summary>
  974. /// Creates a rotation matrix from the given Quaternion rotation value.
  975. /// </summary>
  976. /// <param name="quaternion">The source Quaternion.</param>
  977. /// <returns>The rotation matrix.</returns>
  978. public static Matrix4x4 CreateFromQuaternion(Quaternion quaternion)
  979. {
  980. Matrix4x4 result;
  981. float xx = quaternion.X * quaternion.X;
  982. float yy = quaternion.Y * quaternion.Y;
  983. float zz = quaternion.Z * quaternion.Z;
  984. float xy = quaternion.X * quaternion.Y;
  985. float wz = quaternion.Z * quaternion.W;
  986. float xz = quaternion.Z * quaternion.X;
  987. float wy = quaternion.Y * quaternion.W;
  988. float yz = quaternion.Y * quaternion.Z;
  989. float wx = quaternion.X * quaternion.W;
  990. result.M11 = 1.0f - 2.0f * (yy + zz);
  991. result.M12 = 2.0f * (xy + wz);
  992. result.M13 = 2.0f * (xz - wy);
  993. result.M14 = 0.0f;
  994. result.M21 = 2.0f * (xy - wz);
  995. result.M22 = 1.0f - 2.0f * (zz + xx);
  996. result.M23 = 2.0f * (yz + wx);
  997. result.M24 = 0.0f;
  998. result.M31 = 2.0f * (xz + wy);
  999. result.M32 = 2.0f * (yz - wx);
  1000. result.M33 = 1.0f - 2.0f * (yy + xx);
  1001. result.M34 = 0.0f;
  1002. result.M41 = 0.0f;
  1003. result.M42 = 0.0f;
  1004. result.M43 = 0.0f;
  1005. result.M44 = 1.0f;
  1006. return result;
  1007. }
  1008. /// <summary>
  1009. /// Creates a rotation matrix from the specified yaw, pitch, and roll.
  1010. /// </summary>
  1011. /// <param name="yaw">Angle of rotation, in radians, around the Y-axis.</param>
  1012. /// <param name="pitch">Angle of rotation, in radians, around the X-axis.</param>
  1013. /// <param name="roll">Angle of rotation, in radians, around the Z-axis.</param>
  1014. /// <returns>The rotation matrix.</returns>
  1015. public static Matrix4x4 CreateFromYawPitchRoll(float yaw, float pitch, float roll)
  1016. {
  1017. Quaternion q = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll);
  1018. return Matrix4x4.CreateFromQuaternion(q);
  1019. }
  1020. /// <summary>
  1021. /// Creates a Matrix that flattens geometry into a specified Plane as if casting a shadow from a specified light source.
  1022. /// </summary>
  1023. /// <param name="lightDirection">The direction from which the light that will cast the shadow is coming.</param>
  1024. /// <param name="plane">The Plane onto which the new matrix should flatten geometry so as to cast a shadow.</param>
  1025. /// <returns>A new Matrix that can be used to flatten geometry onto the specified plane from the specified direction.</returns>
  1026. public static Matrix4x4 CreateShadow(Vector3 lightDirection, Plane plane)
  1027. {
  1028. Plane p = Plane.Normalize(plane);
  1029. float dot = p.Normal.X * lightDirection.X + p.Normal.Y * lightDirection.Y + p.Normal.Z * lightDirection.Z;
  1030. float a = -p.Normal.X;
  1031. float b = -p.Normal.Y;
  1032. float c = -p.Normal.Z;
  1033. float d = -p.D;
  1034. Matrix4x4 result;
  1035. result.M11 = a * lightDirection.X + dot;
  1036. result.M21 = b * lightDirection.X;
  1037. result.M31 = c * lightDirection.X;
  1038. result.M41 = d * lightDirection.X;
  1039. result.M12 = a * lightDirection.Y;
  1040. result.M22 = b * lightDirection.Y + dot;
  1041. result.M32 = c * lightDirection.Y;
  1042. result.M42 = d * lightDirection.Y;
  1043. result.M13 = a * lightDirection.Z;
  1044. result.M23 = b * lightDirection.Z;
  1045. result.M33 = c * lightDirection.Z + dot;
  1046. result.M43 = d * lightDirection.Z;
  1047. result.M14 = 0.0f;
  1048. result.M24 = 0.0f;
  1049. result.M34 = 0.0f;
  1050. result.M44 = dot;
  1051. return result;
  1052. }
  1053. /// <summary>
  1054. /// Creates a Matrix that reflects the coordinate system about a specified Plane.
  1055. /// </summary>
  1056. /// <param name="value">The Plane about which to create a reflection.</param>
  1057. /// <returns>A new matrix expressing the reflection.</returns>
  1058. public static Matrix4x4 CreateReflection(Plane value)
  1059. {
  1060. value = Plane.Normalize(value);
  1061. float a = value.Normal.X;
  1062. float b = value.Normal.Y;
  1063. float c = value.Normal.Z;
  1064. float fa = -2.0f * a;
  1065. float fb = -2.0f * b;
  1066. float fc = -2.0f * c;
  1067. Matrix4x4 result;
  1068. result.M11 = fa * a + 1.0f;
  1069. result.M12 = fb * a;
  1070. result.M13 = fc * a;
  1071. result.M14 = 0.0f;
  1072. result.M21 = fa * b;
  1073. result.M22 = fb * b + 1.0f;
  1074. result.M23 = fc * b;
  1075. result.M24 = 0.0f;
  1076. result.M31 = fa * c;
  1077. result.M32 = fb * c;
  1078. result.M33 = fc * c + 1.0f;
  1079. result.M34 = 0.0f;
  1080. result.M41 = fa * value.D;
  1081. result.M42 = fb * value.D;
  1082. result.M43 = fc * value.D;
  1083. result.M44 = 1.0f;
  1084. return result;
  1085. }
  1086. /// <summary>
  1087. /// Calculates the determinant of the matrix.
  1088. /// </summary>
  1089. /// <returns>The determinant of the matrix.</returns>
  1090. public readonly float GetDeterminant()
  1091. {
  1092. // | a b c d | | f g h | | e g h | | e f h | | e f g |
  1093. // | e f g h | = a | j k l | - b | i k l | + c | i j l | - d | i j k |
  1094. // | i j k l | | n o p | | m o p | | m n p | | m n o |
  1095. // | m n o p |
  1096. //
  1097. // | f g h |
  1098. // a | j k l | = a ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
  1099. // | n o p |
  1100. //
  1101. // | e g h |
  1102. // b | i k l | = b ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
  1103. // | m o p |
  1104. //
  1105. // | e f h |
  1106. // c | i j l | = c ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
  1107. // | m n p |
  1108. //
  1109. // | e f g |
  1110. // d | i j k | = d ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
  1111. // | m n o |
  1112. //
  1113. // Cost of operation
  1114. // 17 adds and 28 muls.
  1115. //
  1116. // add: 6 + 8 + 3 = 17
  1117. // mul: 12 + 16 = 28
  1118. float a = M11, b = M12, c = M13, d = M14;
  1119. float e = M21, f = M22, g = M23, h = M24;
  1120. float i = M31, j = M32, k = M33, l = M34;
  1121. float m = M41, n = M42, o = M43, p = M44;
  1122. float kp_lo = k * p - l * o;
  1123. float jp_ln = j * p - l * n;
  1124. float jo_kn = j * o - k * n;
  1125. float ip_lm = i * p - l * m;
  1126. float io_km = i * o - k * m;
  1127. float in_jm = i * n - j * m;
  1128. return a * (f * kp_lo - g * jp_ln + h * jo_kn) -
  1129. b * (e * kp_lo - g * ip_lm + h * io_km) +
  1130. c * (e * jp_ln - f * ip_lm + h * in_jm) -
  1131. d * (e * jo_kn - f * io_km + g * in_jm);
  1132. }
  1133. /// <summary>
  1134. /// Attempts to calculate the inverse of the given matrix. If successful, result will contain the inverted matrix.
  1135. /// </summary>
  1136. /// <param name="matrix">The source matrix to invert.</param>
  1137. /// <param name="result">If successful, contains the inverted matrix.</param>
  1138. /// <returns>True if the source matrix could be inverted; False otherwise.</returns>
  1139. public static bool Invert(Matrix4x4 matrix, out Matrix4x4 result)
  1140. {
  1141. // -1
  1142. // If you have matrix M, inverse Matrix M can compute
  1143. //
  1144. // -1 1
  1145. // M = --------- A
  1146. // det(M)
  1147. //
  1148. // A is adjugate (adjoint) of M, where,
  1149. //
  1150. // T
  1151. // A = C
  1152. //
  1153. // C is Cofactor matrix of M, where,
  1154. // i + j
  1155. // C = (-1) * det(M )
  1156. // ij ij
  1157. //
  1158. // [ a b c d ]
  1159. // M = [ e f g h ]
  1160. // [ i j k l ]
  1161. // [ m n o p ]
  1162. //
  1163. // First Row
  1164. // 2 | f g h |
  1165. // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
  1166. // 11 | n o p |
  1167. //
  1168. // 3 | e g h |
  1169. // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
  1170. // 12 | m o p |
  1171. //
  1172. // 4 | e f h |
  1173. // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
  1174. // 13 | m n p |
  1175. //
  1176. // 5 | e f g |
  1177. // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
  1178. // 14 | m n o |
  1179. //
  1180. // Second Row
  1181. // 3 | b c d |
  1182. // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) )
  1183. // 21 | n o p |
  1184. //
  1185. // 4 | a c d |
  1186. // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) )
  1187. // 22 | m o p |
  1188. //
  1189. // 5 | a b d |
  1190. // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) )
  1191. // 23 | m n p |
  1192. //
  1193. // 6 | a b c |
  1194. // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) )
  1195. // 24 | m n o |
  1196. //
  1197. // Third Row
  1198. // 4 | b c d |
  1199. // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) )
  1200. // 31 | n o p |
  1201. //
  1202. // 5 | a c d |
  1203. // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) )
  1204. // 32 | m o p |
  1205. //
  1206. // 6 | a b d |
  1207. // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) )
  1208. // 33 | m n p |
  1209. //
  1210. // 7 | a b c |
  1211. // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) )
  1212. // 34 | m n o |
  1213. //
  1214. // Fourth Row
  1215. // 5 | b c d |
  1216. // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) )
  1217. // 41 | j k l |
  1218. //
  1219. // 6 | a c d |
  1220. // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) )
  1221. // 42 | i k l |
  1222. //
  1223. // 7 | a b d |
  1224. // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) )
  1225. // 43 | i j l |
  1226. //
  1227. // 8 | a b c |
  1228. // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) )
  1229. // 44 | i j k |
  1230. //
  1231. // Cost of operation
  1232. // 53 adds, 104 muls, and 1 div.
  1233. float a = matrix.M11, b = matrix.M12, c = matrix.M13, d = matrix.M14;
  1234. float e = matrix.M21, f = matrix.M22, g = matrix.M23, h = matrix.M24;
  1235. float i = matrix.M31, j = matrix.M32, k = matrix.M33, l = matrix.M34;
  1236. float m = matrix.M41, n = matrix.M42, o = matrix.M43, p = matrix.M44;
  1237. float kp_lo = k * p - l * o;
  1238. float jp_ln = j * p - l * n;
  1239. float jo_kn = j * o - k * n;
  1240. float ip_lm = i * p - l * m;
  1241. float io_km = i * o - k * m;
  1242. float in_jm = i * n - j * m;
  1243. float a11 = +(f * kp_lo - g * jp_ln + h * jo_kn);
  1244. float a12 = -(e * kp_lo - g * ip_lm + h * io_km);
  1245. float a13 = +(e * jp_ln - f * ip_lm + h * in_jm);
  1246. float a14 = -(e * jo_kn - f * io_km + g * in_jm);
  1247. float det = a * a11 + b * a12 + c * a13 + d * a14;
  1248. if (MathF.Abs(det) < float.Epsilon)
  1249. {
  1250. result = new Matrix4x4(float.NaN, float.NaN, float.NaN, float.NaN,
  1251. float.NaN, float.NaN, float.NaN, float.NaN,
  1252. float.NaN, float.NaN, float.NaN, float.NaN,
  1253. float.NaN, float.NaN, float.NaN, float.NaN);
  1254. return false;
  1255. }
  1256. float invDet = 1.0f / det;
  1257. result.M11 = a11 * invDet;
  1258. result.M21 = a12 * invDet;
  1259. result.M31 = a13 * invDet;
  1260. result.M41 = a14 * invDet;
  1261. result.M12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet;
  1262. result.M22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet;
  1263. result.M32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet;
  1264. result.M42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet;
  1265. float gp_ho = g * p - h * o;
  1266. float fp_hn = f * p - h * n;
  1267. float fo_gn = f * o - g * n;
  1268. float ep_hm = e * p - h * m;
  1269. float eo_gm = e * o - g * m;
  1270. float en_fm = e * n - f * m;
  1271. result.M13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet;
  1272. result.M23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet;
  1273. result.M33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet;
  1274. result.M43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet;
  1275. float gl_hk = g * l - h * k;
  1276. float fl_hj = f * l - h * j;
  1277. float fk_gj = f * k - g * j;
  1278. float el_hi = e * l - h * i;
  1279. float ek_gi = e * k - g * i;
  1280. float ej_fi = e * j - f * i;
  1281. result.M14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet;
  1282. result.M24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet;
  1283. result.M34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet;
  1284. result.M44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet;
  1285. return true;
  1286. }
  1287. private struct CanonicalBasis
  1288. {
  1289. public Vector3 Row0;
  1290. public Vector3 Row1;
  1291. public Vector3 Row2;
  1292. };
  1293. private struct VectorBasis
  1294. {
  1295. public unsafe Vector3* Element0;
  1296. public unsafe Vector3* Element1;
  1297. public unsafe Vector3* Element2;
  1298. }
  1299. /// <summary>
  1300. /// Attempts to extract the scale, translation, and rotation components from the given scale/rotation/translation matrix.
  1301. /// If successful, the out parameters will contained the extracted values.
  1302. /// </summary>
  1303. /// <param name="matrix">The source matrix.</param>
  1304. /// <param name="scale">The scaling component of the transformation matrix.</param>
  1305. /// <param name="rotation">The rotation component of the transformation matrix.</param>
  1306. /// <param name="translation">The translation component of the transformation matrix</param>
  1307. /// <returns>True if the source matrix was successfully decomposed; False otherwise.</returns>
  1308. public static bool Decompose(Matrix4x4 matrix, out Vector3 scale, out Quaternion rotation, out Vector3 translation)
  1309. {
  1310. bool result = true;
  1311. unsafe
  1312. {
  1313. fixed (Vector3* scaleBase = &scale)
  1314. {
  1315. float* pfScales = (float*)scaleBase;
  1316. float det;
  1317. VectorBasis vectorBasis;
  1318. Vector3** pVectorBasis = (Vector3**)&vectorBasis;
  1319. Matrix4x4 matTemp = Matrix4x4.Identity;
  1320. CanonicalBasis canonicalBasis = default;
  1321. Vector3* pCanonicalBasis = &canonicalBasis.Row0;
  1322. canonicalBasis.Row0 = new Vector3(1.0f, 0.0f, 0.0f);
  1323. canonicalBasis.Row1 = new Vector3(0.0f, 1.0f, 0.0f);
  1324. canonicalBasis.Row2 = new Vector3(0.0f, 0.0f, 1.0f);
  1325. translation = new Vector3(
  1326. matrix.M41,
  1327. matrix.M42,
  1328. matrix.M43);
  1329. pVectorBasis[0] = (Vector3*)&matTemp.M11;
  1330. pVectorBasis[1] = (Vector3*)&matTemp.M21;
  1331. pVectorBasis[2] = (Vector3*)&matTemp.M31;
  1332. *(pVectorBasis[0]) = new Vector3(matrix.M11, matrix.M12, matrix.M13);
  1333. *(pVectorBasis[1]) = new Vector3(matrix.M21, matrix.M22, matrix.M23);
  1334. *(pVectorBasis[2]) = new Vector3(matrix.M31, matrix.M32, matrix.M33);
  1335. scale.X = pVectorBasis[0]->Length();
  1336. scale.Y = pVectorBasis[1]->Length();
  1337. scale.Z = pVectorBasis[2]->Length();
  1338. uint a, b, c;
  1339. #region Ranking
  1340. float x = pfScales[0], y = pfScales[1], z = pfScales[2];
  1341. if (x < y)
  1342. {
  1343. if (y < z)
  1344. {
  1345. a = 2;
  1346. b = 1;
  1347. c = 0;
  1348. }
  1349. else
  1350. {
  1351. a = 1;
  1352. if (x < z)
  1353. {
  1354. b = 2;
  1355. c = 0;
  1356. }
  1357. else
  1358. {
  1359. b = 0;
  1360. c = 2;
  1361. }
  1362. }
  1363. }
  1364. else
  1365. {
  1366. if (x < z)
  1367. {
  1368. a = 2;
  1369. b = 0;
  1370. c = 1;
  1371. }
  1372. else
  1373. {
  1374. a = 0;
  1375. if (y < z)
  1376. {
  1377. b = 2;
  1378. c = 1;
  1379. }
  1380. else
  1381. {
  1382. b = 1;
  1383. c = 2;
  1384. }
  1385. }
  1386. }
  1387. #endregion
  1388. if (pfScales[a] < DecomposeEpsilon)
  1389. {
  1390. *(pVectorBasis[a]) = pCanonicalBasis[a];
  1391. }
  1392. *pVectorBasis[a] = Vector3.Normalize(*pVectorBasis[a]);
  1393. if (pfScales[b] < DecomposeEpsilon)
  1394. {
  1395. uint cc;
  1396. float fAbsX, fAbsY, fAbsZ;
  1397. fAbsX = MathF.Abs(pVectorBasis[a]->X);
  1398. fAbsY = MathF.Abs(pVectorBasis[a]->Y);
  1399. fAbsZ = MathF.Abs(pVectorBasis[a]->Z);
  1400. #region Ranking
  1401. if (fAbsX < fAbsY)
  1402. {
  1403. if (fAbsY < fAbsZ)
  1404. {
  1405. cc = 0;
  1406. }
  1407. else
  1408. {
  1409. if (fAbsX < fAbsZ)
  1410. {
  1411. cc = 0;
  1412. }
  1413. else
  1414. {
  1415. cc = 2;
  1416. }
  1417. }
  1418. }
  1419. else
  1420. {
  1421. if (fAbsX < fAbsZ)
  1422. {
  1423. cc = 1;
  1424. }
  1425. else
  1426. {
  1427. if (fAbsY < fAbsZ)
  1428. {
  1429. cc = 1;
  1430. }
  1431. else
  1432. {
  1433. cc = 2;
  1434. }
  1435. }
  1436. }
  1437. #endregion
  1438. *pVectorBasis[b] = Vector3.Cross(*pVectorBasis[a], *(pCanonicalBasis + cc));
  1439. }
  1440. *pVectorBasis[b] = Vector3.Normalize(*pVectorBasis[b]);
  1441. if (pfScales[c] < DecomposeEpsilon)
  1442. {
  1443. *pVectorBasis[c] = Vector3.Cross(*pVectorBasis[a], *pVectorBasis[b]);
  1444. }
  1445. *pVectorBasis[c] = Vector3.Normalize(*pVectorBasis[c]);
  1446. det = matTemp.GetDeterminant();
  1447. // use Kramer's rule to check for handedness of coordinate system
  1448. if (det < 0.0f)
  1449. {
  1450. // switch coordinate system by negating the scale and inverting the basis vector on the x-axis
  1451. pfScales[a] = -pfScales[a];
  1452. *pVectorBasis[a] = -(*pVectorBasis[a]);
  1453. det = -det;
  1454. }
  1455. det -= 1.0f;
  1456. det *= det;
  1457. if ((DecomposeEpsilon < det))
  1458. {
  1459. // Non-SRT matrix encountered
  1460. rotation = Quaternion.Identity;
  1461. result = false;
  1462. }
  1463. else
  1464. {
  1465. // generate the quaternion from the matrix
  1466. rotation = Quaternion.CreateFromRotationMatrix(matTemp);
  1467. }
  1468. }
  1469. }
  1470. return result;
  1471. }
  1472. /// <summary>
  1473. /// Transforms the given matrix by applying the given Quaternion rotation.
  1474. /// </summary>
  1475. /// <param name="value">The source matrix to transform.</param>
  1476. /// <param name="rotation">The rotation to apply.</param>
  1477. /// <returns>The transformed matrix.</returns>
  1478. public static Matrix4x4 Transform(Matrix4x4 value, Quaternion rotation)
  1479. {
  1480. // Compute rotation matrix.
  1481. float x2 = rotation.X + rotation.X;
  1482. float y2 = rotation.Y + rotation.Y;
  1483. float z2 = rotation.Z + rotation.Z;
  1484. float wx2 = rotation.W * x2;
  1485. float wy2 = rotation.W * y2;
  1486. float wz2 = rotation.W * z2;
  1487. float xx2 = rotation.X * x2;
  1488. float xy2 = rotation.X * y2;
  1489. float xz2 = rotation.X * z2;
  1490. float yy2 = rotation.Y * y2;
  1491. float yz2 = rotation.Y * z2;
  1492. float zz2 = rotation.Z * z2;
  1493. float q11 = 1.0f - yy2 - zz2;
  1494. float q21 = xy2 - wz2;
  1495. float q31 = xz2 + wy2;
  1496. float q12 = xy2 + wz2;
  1497. float q22 = 1.0f - xx2 - zz2;
  1498. float q32 = yz2 - wx2;
  1499. float q13 = xz2 - wy2;
  1500. float q23 = yz2 + wx2;
  1501. float q33 = 1.0f - xx2 - yy2;
  1502. Matrix4x4 result;
  1503. // First row
  1504. result.M11 = value.M11 * q11 + value.M12 * q21 + value.M13 * q31;
  1505. result.M12 = value.M11 * q12 + value.M12 * q22 + value.M13 * q32;
  1506. result.M13 = value.M11 * q13 + value.M12 * q23 + value.M13 * q33;
  1507. result.M14 = value.M14;
  1508. // Second row
  1509. result.M21 = value.M21 * q11 + value.M22 * q21 + value.M23 * q31;
  1510. result.M22 = value.M21 * q12 + value.M22 * q22 + value.M23 * q32;
  1511. result.M23 = value.M21 * q13 + value.M22 * q23 + value.M23 * q33;
  1512. result.M24 = value.M24;
  1513. // Third row
  1514. result.M31 = value.M31 * q11 + value.M32 * q21 + value.M33 * q31;
  1515. result.M32 = value.M31 * q12 + value.M32 * q22 + value.M33 * q32;
  1516. result.M33 = value.M31 * q13 + value.M32 * q23 + value.M33 * q33;
  1517. result.M34 = value.M34;
  1518. // Fourth row
  1519. result.M41 = value.M41 * q11 + value.M42 * q21 + value.M43 * q31;
  1520. result.M42 = value.M41 * q12 + value.M42 * q22 + value.M43 * q32;
  1521. result.M43 = value.M41 * q13 + value.M42 * q23 + value.M43 * q33;
  1522. result.M44 = value.M44;
  1523. return result;
  1524. }
  1525. /// <summary>
  1526. /// Transposes the rows and columns of a matrix.
  1527. /// </summary>
  1528. /// <param name="matrix">The source matrix.</param>
  1529. /// <returns>The transposed matrix.</returns>
  1530. public static unsafe Matrix4x4 Transpose(Matrix4x4 matrix)
  1531. {
  1532. if (Sse.IsSupported)
  1533. {
  1534. var row1 = Sse.LoadVector128(&matrix.M11);
  1535. var row2 = Sse.LoadVector128(&matrix.M21);
  1536. var row3 = Sse.LoadVector128(&matrix.M31);
  1537. var row4 = Sse.LoadVector128(&matrix.M41);
  1538. var l12 = Sse.UnpackLow(row1, row2);
  1539. var l34 = Sse.UnpackLow(row3, row4);
  1540. var h12 = Sse.UnpackHigh(row1, row2);
  1541. var h34 = Sse.UnpackHigh(row3, row4);
  1542. Sse.Store(&matrix.M11, Sse.MoveLowToHigh(l12, l34));
  1543. Sse.Store(&matrix.M21, Sse.MoveHighToLow(l34, l12));
  1544. Sse.Store(&matrix.M31, Sse.MoveLowToHigh(h12, h34));
  1545. Sse.Store(&matrix.M41, Sse.MoveHighToLow(h34, h12));
  1546. return matrix;
  1547. }
  1548. Matrix4x4 result;
  1549. result.M11 = matrix.M11;
  1550. result.M12 = matrix.M21;
  1551. result.M13 = matrix.M31;
  1552. result.M14 = matrix.M41;
  1553. result.M21 = matrix.M12;
  1554. result.M22 = matrix.M22;
  1555. result.M23 = matrix.M32;
  1556. result.M24 = matrix.M42;
  1557. result.M31 = matrix.M13;
  1558. result.M32 = matrix.M23;
  1559. result.M33 = matrix.M33;
  1560. result.M34 = matrix.M43;
  1561. result.M41 = matrix.M14;
  1562. result.M42 = matrix.M24;
  1563. result.M43 = matrix.M34;
  1564. result.M44 = matrix.M44;
  1565. return result;
  1566. }
  1567. /// <summary>
  1568. /// Linearly interpolates between the corresponding values of two matrices.
  1569. /// </summary>
  1570. /// <param name="matrix1">The first source matrix.</param>
  1571. /// <param name="matrix2">The second source matrix.</param>
  1572. /// <param name="amount">The relative weight of the second source matrix.</param>
  1573. /// <returns>The interpolated matrix.</returns>
  1574. public static unsafe Matrix4x4 Lerp(Matrix4x4 matrix1, Matrix4x4 matrix2, float amount)
  1575. {
  1576. if (Sse.IsSupported)
  1577. {
  1578. Vector128<float> amountVec = Vector128.Create(amount);
  1579. Sse.Store(&matrix1.M11, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M11), Sse.LoadVector128(&matrix2.M11), amountVec));
  1580. Sse.Store(&matrix1.M21, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M21), Sse.LoadVector128(&matrix2.M21), amountVec));
  1581. Sse.Store(&matrix1.M31, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M31), Sse.LoadVector128(&matrix2.M31), amountVec));
  1582. Sse.Store(&matrix1.M41, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M41), Sse.LoadVector128(&matrix2.M41), amountVec));
  1583. return matrix1;
  1584. }
  1585. Matrix4x4 result;
  1586. // First row
  1587. result.M11 = matrix1.M11 + (matrix2.M11 - matrix1.M11) * amount;
  1588. result.M12 = matrix1.M12 + (matrix2.M12 - matrix1.M12) * amount;
  1589. result.M13 = matrix1.M13 + (matrix2.M13 - matrix1.M13) * amount;
  1590. result.M14 = matrix1.M14 + (matrix2.M14 - matrix1.M14) * amount;
  1591. // Second row
  1592. result.M21 = matrix1.M21 + (matrix2.M21 - matrix1.M21) * amount;
  1593. result.M22 = matrix1.M22 + (matrix2.M22 - matrix1.M22) * amount;
  1594. result.M23 = matrix1.M23 + (matrix2.M23 - matrix1.M23) * amount;
  1595. result.M24 = matrix1.M24 + (matrix2.M24 - matrix1.M24) * amount;
  1596. // Third row
  1597. result.M31 = matrix1.M31 + (matrix2.M31 - matrix1.M31) * amount;
  1598. result.M32 = matrix1.M32 + (matrix2.M32 - matrix1.M32) * amount;
  1599. result.M33 = matrix1.M33 + (matrix2.M33 - matrix1.M33) * amount;
  1600. result.M34 = matrix1.M34 + (matrix2.M34 - matrix1.M34) * amount;
  1601. // Fourth row
  1602. result.M41 = matrix1.M41 + (matrix2.M41 - matrix1.M41) * amount;
  1603. result.M42 = matrix1.M42 + (matrix2.M42 - matrix1.M42) * amount;
  1604. result.M43 = matrix1.M43 + (matrix2.M43 - matrix1.M43) * amount;
  1605. result.M44 = matrix1.M44 + (matrix2.M44 - matrix1.M44) * amount;
  1606. return result;
  1607. }
  1608. /// <summary>
  1609. /// Returns a new matrix with the negated elements of the given matrix.
  1610. /// </summary>
  1611. /// <param name="value">The source matrix.</param>
  1612. /// <returns>The negated matrix.</returns>
  1613. public static Matrix4x4 Negate(Matrix4x4 value) => -value;
  1614. /// <summary>
  1615. /// Adds two matrices together.
  1616. /// </summary>
  1617. /// <param name="value1">The first source matrix.</param>
  1618. /// <param name="value2">The second source matrix.</param>
  1619. /// <returns>The resulting matrix.</returns>
  1620. public static Matrix4x4 Add(Matrix4x4 value1, Matrix4x4 value2) => value1 + value2;
  1621. /// <summary>
  1622. /// Subtracts the second matrix from the first.
  1623. /// </summary>
  1624. /// <param name="value1">The first source matrix.</param>
  1625. /// <param name="value2">The second source matrix.</param>
  1626. /// <returns>The result of the subtraction.</returns>
  1627. public static Matrix4x4 Subtract(Matrix4x4 value1, Matrix4x4 value2) => value1 - value2;
  1628. /// <summary>
  1629. /// Multiplies a matrix by another matrix.
  1630. /// </summary>
  1631. /// <param name="value1">The first source matrix.</param>
  1632. /// <param name="value2">The second source matrix.</param>
  1633. /// <returns>The result of the multiplication.</returns>
  1634. public static Matrix4x4 Multiply(Matrix4x4 value1, Matrix4x4 value2) => value1 * value2;
  1635. /// <summary>
  1636. /// Multiplies a matrix by a scalar value.
  1637. /// </summary>
  1638. /// <param name="value1">The source matrix.</param>
  1639. /// <param name="value2">The scaling factor.</param>
  1640. /// <returns>The scaled matrix.</returns>
  1641. public static Matrix4x4 Multiply(Matrix4x4 value1, float value2) => value1 * value2;
  1642. /// <summary>
  1643. /// Returns a new matrix with the negated elements of the given matrix.
  1644. /// </summary>
  1645. /// <param name="value">The source matrix.</param>
  1646. /// <returns>The negated matrix.</returns>
  1647. public static unsafe Matrix4x4 operator -(Matrix4x4 value)
  1648. {
  1649. if (Sse.IsSupported)
  1650. {
  1651. Vector128<float> zero = Vector128<float>.Zero;
  1652. Sse.Store(&value.M11, Sse.Subtract(zero, Sse.LoadVector128(&value.M11)));
  1653. Sse.Store(&value.M21, Sse.Subtract(zero, Sse.LoadVector128(&value.M21)));
  1654. Sse.Store(&value.M31, Sse.Subtract(zero, Sse.LoadVector128(&value.M31)));
  1655. Sse.Store(&value.M41, Sse.Subtract(zero, Sse.LoadVector128(&value.M41)));
  1656. return value;
  1657. }
  1658. Matrix4x4 m;
  1659. m.M11 = -value.M11;
  1660. m.M12 = -value.M12;
  1661. m.M13 = -value.M13;
  1662. m.M14 = -value.M14;
  1663. m.M21 = -value.M21;
  1664. m.M22 = -value.M22;
  1665. m.M23 = -value.M23;
  1666. m.M24 = -value.M24;
  1667. m.M31 = -value.M31;
  1668. m.M32 = -value.M32;
  1669. m.M33 = -value.M33;
  1670. m.M34 = -value.M34;
  1671. m.M41 = -value.M41;
  1672. m.M42 = -value.M42;
  1673. m.M43 = -value.M43;
  1674. m.M44 = -value.M44;
  1675. return m;
  1676. }
  1677. /// <summary>
  1678. /// Adds two matrices together.
  1679. /// </summary>
  1680. /// <param name="value1">The first source matrix.</param>
  1681. /// <param name="value2">The second source matrix.</param>
  1682. /// <returns>The resulting matrix.</returns>
  1683. public static unsafe Matrix4x4 operator +(Matrix4x4 value1, Matrix4x4 value2)
  1684. {
  1685. if (Sse.IsSupported)
  1686. {
  1687. Sse.Store(&value1.M11, Sse.Add(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)));
  1688. Sse.Store(&value1.M21, Sse.Add(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)));
  1689. Sse.Store(&value1.M31, Sse.Add(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)));
  1690. Sse.Store(&value1.M41, Sse.Add(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41)));
  1691. return value1;
  1692. }
  1693. Matrix4x4 m;
  1694. m.M11 = value1.M11 + value2.M11;
  1695. m.M12 = value1.M12 + value2.M12;
  1696. m.M13 = value1.M13 + value2.M13;
  1697. m.M14 = value1.M14 + value2.M14;
  1698. m.M21 = value1.M21 + value2.M21;
  1699. m.M22 = value1.M22 + value2.M22;
  1700. m.M23 = value1.M23 + value2.M23;
  1701. m.M24 = value1.M24 + value2.M24;
  1702. m.M31 = value1.M31 + value2.M31;
  1703. m.M32 = value1.M32 + value2.M32;
  1704. m.M33 = value1.M33 + value2.M33;
  1705. m.M34 = value1.M34 + value2.M34;
  1706. m.M41 = value1.M41 + value2.M41;
  1707. m.M42 = value1.M42 + value2.M42;
  1708. m.M43 = value1.M43 + value2.M43;
  1709. m.M44 = value1.M44 + value2.M44;
  1710. return m;
  1711. }
  1712. /// <summary>
  1713. /// Subtracts the second matrix from the first.
  1714. /// </summary>
  1715. /// <param name="value1">The first source matrix.</param>
  1716. /// <param name="value2">The second source matrix.</param>
  1717. /// <returns>The result of the subtraction.</returns>
  1718. public static unsafe Matrix4x4 operator -(Matrix4x4 value1, Matrix4x4 value2)
  1719. {
  1720. if (Sse.IsSupported)
  1721. {
  1722. Sse.Store(&value1.M11, Sse.Subtract(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)));
  1723. Sse.Store(&value1.M21, Sse.Subtract(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)));
  1724. Sse.Store(&value1.M31, Sse.Subtract(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)));
  1725. Sse.Store(&value1.M41, Sse.Subtract(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41)));
  1726. return value1;
  1727. }
  1728. Matrix4x4 m;
  1729. m.M11 = value1.M11 - value2.M11;
  1730. m.M12 = value1.M12 - value2.M12;
  1731. m.M13 = value1.M13 - value2.M13;
  1732. m.M14 = value1.M14 - value2.M14;
  1733. m.M21 = value1.M21 - value2.M21;
  1734. m.M22 = value1.M22 - value2.M22;
  1735. m.M23 = value1.M23 - value2.M23;
  1736. m.M24 = value1.M24 - value2.M24;
  1737. m.M31 = value1.M31 - value2.M31;
  1738. m.M32 = value1.M32 - value2.M32;
  1739. m.M33 = value1.M33 - value2.M33;
  1740. m.M34 = value1.M34 - value2.M34;
  1741. m.M41 = value1.M41 - value2.M41;
  1742. m.M42 = value1.M42 - value2.M42;
  1743. m.M43 = value1.M43 - value2.M43;
  1744. m.M44 = value1.M44 - value2.M44;
  1745. return m;
  1746. }
  1747. /// <summary>
  1748. /// Multiplies a matrix by another matrix.
  1749. /// </summary>
  1750. /// <param name="value1">The first source matrix.</param>
  1751. /// <param name="value2">The second source matrix.</param>
  1752. /// <returns>The result of the multiplication.</returns>
  1753. public static unsafe Matrix4x4 operator *(Matrix4x4 value1, Matrix4x4 value2)
  1754. {
  1755. if (Sse.IsSupported)
  1756. {
  1757. var row = Sse.LoadVector128(&value1.M11);
  1758. Sse.Store(&value1.M11,
  1759. Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
  1760. Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
  1761. Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
  1762. Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
  1763. // 0x00 is _MM_SHUFFLE(0,0,0,0), 0x55 is _MM_SHUFFLE(1,1,1,1), etc.
  1764. // TODO: Replace with a method once it's added to the API.
  1765. row = Sse.LoadVector128(&value1.M21);
  1766. Sse.Store(&value1.M21,
  1767. Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
  1768. Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
  1769. Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
  1770. Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
  1771. row = Sse.LoadVector128(&value1.M31);
  1772. Sse.Store(&value1.M31,
  1773. Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
  1774. Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
  1775. Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
  1776. Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
  1777. row = Sse.LoadVector128(&value1.M41);
  1778. Sse.Store(&value1.M41,
  1779. Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
  1780. Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
  1781. Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
  1782. Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
  1783. return value1;
  1784. }
  1785. Matrix4x4 m;
  1786. // First row
  1787. m.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21 + value1.M13 * value2.M31 + value1.M14 * value2.M41;
  1788. m.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22 + value1.M13 * value2.M32 + value1.M14 * value2.M42;
  1789. m.M13 = value1.M11 * value2.M13 + value1.M12 * value2.M23 + value1.M13 * value2.M33 + value1.M14 * value2.M43;
  1790. m.M14 = value1.M11 * value2.M14 + value1.M12 * value2.M24 + value1.M13 * value2.M34 + value1.M14 * value2.M44;
  1791. // Second row
  1792. m.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21 + value1.M23 * value2.M31 + value1.M24 * value2.M41;
  1793. m.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22 + value1.M23 * value2.M32 + value1.M24 * value2.M42;
  1794. m.M23 = value1.M21 * value2.M13 + value1.M22 * value2.M23 + value1.M23 * value2.M33 + value1.M24 * value2.M43;
  1795. m.M24 = value1.M21 * value2.M14 + value1.M22 * value2.M24 + value1.M23 * value2.M34 + value1.M24 * value2.M44;
  1796. // Third row
  1797. m.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value1.M33 * value2.M31 + value1.M34 * value2.M41;
  1798. m.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value1.M33 * value2.M32 + value1.M34 * value2.M42;
  1799. m.M33 = value1.M31 * value2.M13 + value1.M32 * value2.M23 + value1.M33 * value2.M33 + value1.M34 * value2.M43;
  1800. m.M34 = value1.M31 * value2.M14 + value1.M32 * value2.M24 + value1.M33 * value2.M34 + value1.M34 * value2.M44;
  1801. // Fourth row
  1802. m.M41 = value1.M41 * value2.M11 + value1.M42 * value2.M21 + value1.M43 * value2.M31 + value1.M44 * value2.M41;
  1803. m.M42 = value1.M41 * value2.M12 + value1.M42 * value2.M22 + value1.M43 * value2.M32 + value1.M44 * value2.M42;
  1804. m.M43 = value1.M41 * value2.M13 + value1.M42 * value2.M23 + value1.M43 * value2.M33 + value1.M44 * value2.M43;
  1805. m.M44 = value1.M41 * value2.M14 + value1.M42 * value2.M24 + value1.M43 * value2.M34 + value1.M44 * value2.M44;
  1806. return m;
  1807. }
  1808. /// <summary>
  1809. /// Multiplies a matrix by a scalar value.
  1810. /// </summary>
  1811. /// <param name="value1">The source matrix.</param>
  1812. /// <param name="value2">The scaling factor.</param>
  1813. /// <returns>The scaled matrix.</returns>
  1814. public static unsafe Matrix4x4 operator *(Matrix4x4 value1, float value2)
  1815. {
  1816. if (Sse.IsSupported)
  1817. {
  1818. Vector128<float> value2Vec = Vector128.Create(value2);
  1819. Sse.Store(&value1.M11, Sse.Multiply(Sse.LoadVector128(&value1.M11), value2Vec));
  1820. Sse.Store(&value1.M21, Sse.Multiply(Sse.LoadVector128(&value1.M21), value2Vec));
  1821. Sse.Store(&value1.M31, Sse.Multiply(Sse.LoadVector128(&value1.M31), value2Vec));
  1822. Sse.Store(&value1.M41, Sse.Multiply(Sse.LoadVector128(&value1.M41), value2Vec));
  1823. return value1;
  1824. }
  1825. Matrix4x4 m;
  1826. m.M11 = value1.M11 * value2;
  1827. m.M12 = value1.M12 * value2;
  1828. m.M13 = value1.M13 * value2;
  1829. m.M14 = value1.M14 * value2;
  1830. m.M21 = value1.M21 * value2;
  1831. m.M22 = value1.M22 * value2;
  1832. m.M23 = value1.M23 * value2;
  1833. m.M24 = value1.M24 * value2;
  1834. m.M31 = value1.M31 * value2;
  1835. m.M32 = value1.M32 * value2;
  1836. m.M33 = value1.M33 * value2;
  1837. m.M34 = value1.M34 * value2;
  1838. m.M41 = value1.M41 * value2;
  1839. m.M42 = value1.M42 * value2;
  1840. m.M43 = value1.M43 * value2;
  1841. m.M44 = value1.M44 * value2;
  1842. return m;
  1843. }
  1844. /// <summary>
  1845. /// Returns a boolean indicating whether the given two matrices are equal.
  1846. /// </summary>
  1847. /// <param name="value1">The first matrix to compare.</param>
  1848. /// <param name="value2">The second matrix to compare.</param>
  1849. /// <returns>True if the given matrices are equal; False otherwise.</returns>
  1850. public static unsafe bool operator ==(Matrix4x4 value1, Matrix4x4 value2)
  1851. {
  1852. if (Sse.IsSupported)
  1853. {
  1854. return
  1855. VectorMath.Equal(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)) &&
  1856. VectorMath.Equal(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)) &&
  1857. VectorMath.Equal(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)) &&
  1858. VectorMath.Equal(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41));
  1859. }
  1860. return (value1.M11 == value2.M11 && value1.M22 == value2.M22 && value1.M33 == value2.M33 && value1.M44 == value2.M44 && // Check diagonal element first for early out.
  1861. value1.M12 == value2.M12 && value1.M13 == value2.M13 && value1.M14 == value2.M14 && value1.M21 == value2.M21 &&
  1862. value1.M23 == value2.M23 && value1.M24 == value2.M24 && value1.M31 == value2.M31 && value1.M32 == value2.M32 &&
  1863. value1.M34 == value2.M34 && value1.M41 == value2.M41 && value1.M42 == value2.M42 && value1.M43 == value2.M43);
  1864. }
  1865. /// <summary>
  1866. /// Returns a boolean indicating whether the given two matrices are not equal.
  1867. /// </summary>
  1868. /// <param name="value1">The first matrix to compare.</param>
  1869. /// <param name="value2">The second matrix to compare.</param>
  1870. /// <returns>True if the given matrices are not equal; False if they are equal.</returns>
  1871. public static unsafe bool operator !=(Matrix4x4 value1, Matrix4x4 value2)
  1872. {
  1873. if (Sse.IsSupported)
  1874. {
  1875. return
  1876. VectorMath.NotEqual(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)) ||
  1877. VectorMath.NotEqual(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)) ||
  1878. VectorMath.NotEqual(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)) ||
  1879. VectorMath.NotEqual(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41));
  1880. }
  1881. return (value1.M11 != value2.M11 || value1.M12 != value2.M12 || value1.M13 != value2.M13 || value1.M14 != value2.M14 ||
  1882. value1.M21 != value2.M21 || value1.M22 != value2.M22 || value1.M23 != value2.M23 || value1.M24 != value2.M24 ||
  1883. value1.M31 != value2.M31 || value1.M32 != value2.M32 || value1.M33 != value2.M33 || value1.M34 != value2.M34 ||
  1884. value1.M41 != value2.M41 || value1.M42 != value2.M42 || value1.M43 != value2.M43 || value1.M44 != value2.M44);
  1885. }
  1886. /// <summary>
  1887. /// Returns a boolean indicating whether this matrix instance is equal to the other given matrix.
  1888. /// </summary>
  1889. /// <param name="other">The matrix to compare this instance to.</param>
  1890. /// <returns>True if the matrices are equal; False otherwise.</returns>
  1891. public readonly bool Equals(Matrix4x4 other) => this == other;
  1892. /// <summary>
  1893. /// Returns a boolean indicating whether the given Object is equal to this matrix instance.
  1894. /// </summary>
  1895. /// <param name="obj">The Object to compare against.</param>
  1896. /// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
  1897. public override readonly bool Equals(object? obj) => (obj is Matrix4x4 other) && (this == other);
  1898. /// <summary>
  1899. /// Returns a String representing this matrix instance.
  1900. /// </summary>
  1901. /// <returns>The string representation.</returns>
  1902. public override readonly string ToString()
  1903. {
  1904. return string.Format(CultureInfo.CurrentCulture, "{{ {{M11:{0} M12:{1} M13:{2} M14:{3}}} {{M21:{4} M22:{5} M23:{6} M24:{7}}} {{M31:{8} M32:{9} M33:{10} M34:{11}}} {{M41:{12} M42:{13} M43:{14} M44:{15}}} }}",
  1905. M11, M12, M13, M14,
  1906. M21, M22, M23, M24,
  1907. M31, M32, M33, M34,
  1908. M41, M42, M43, M44);
  1909. }
  1910. /// <summary>
  1911. /// Returns the hash code for this instance.
  1912. /// </summary>
  1913. /// <returns>The hash code.</returns>
  1914. public override readonly int GetHashCode()
  1915. {
  1916. unchecked
  1917. {
  1918. return M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() +
  1919. M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() +
  1920. M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode() +
  1921. M41.GetHashCode() + M42.GetHashCode() + M43.GetHashCode() + M44.GetHashCode();
  1922. }
  1923. }
  1924. }
  1925. }