| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Globalization;
- using System.Runtime.InteropServices;
- using System.Runtime.Intrinsics;
- using System.Runtime.Intrinsics.X86;
- namespace System.Numerics
- {
- /// <summary>
- /// A structure encapsulating a 4x4 matrix.
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- public struct Matrix4x4 : IEquatable<Matrix4x4>
- {
- private const float BillboardEpsilon = 1e-4f;
- private const float BillboardMinAngle = 1.0f - (0.1f * (MathF.PI / 180.0f)); // 0.1 degrees
- private const float DecomposeEpsilon = 0.0001f;
- #region Public Fields
- /// <summary>
- /// Value at row 1, column 1 of the matrix.
- /// </summary>
- public float M11;
- /// <summary>
- /// Value at row 1, column 2 of the matrix.
- /// </summary>
- public float M12;
- /// <summary>
- /// Value at row 1, column 3 of the matrix.
- /// </summary>
- public float M13;
- /// <summary>
- /// Value at row 1, column 4 of the matrix.
- /// </summary>
- public float M14;
- /// <summary>
- /// Value at row 2, column 1 of the matrix.
- /// </summary>
- public float M21;
- /// <summary>
- /// Value at row 2, column 2 of the matrix.
- /// </summary>
- public float M22;
- /// <summary>
- /// Value at row 2, column 3 of the matrix.
- /// </summary>
- public float M23;
- /// <summary>
- /// Value at row 2, column 4 of the matrix.
- /// </summary>
- public float M24;
- /// <summary>
- /// Value at row 3, column 1 of the matrix.
- /// </summary>
- public float M31;
- /// <summary>
- /// Value at row 3, column 2 of the matrix.
- /// </summary>
- public float M32;
- /// <summary>
- /// Value at row 3, column 3 of the matrix.
- /// </summary>
- public float M33;
- /// <summary>
- /// Value at row 3, column 4 of the matrix.
- /// </summary>
- public float M34;
- /// <summary>
- /// Value at row 4, column 1 of the matrix.
- /// </summary>
- public float M41;
- /// <summary>
- /// Value at row 4, column 2 of the matrix.
- /// </summary>
- public float M42;
- /// <summary>
- /// Value at row 4, column 3 of the matrix.
- /// </summary>
- public float M43;
- /// <summary>
- /// Value at row 4, column 4 of the matrix.
- /// </summary>
- public float M44;
- #endregion Public Fields
- private static readonly Matrix4x4 _identity = new Matrix4x4
- (
- 1f, 0f, 0f, 0f,
- 0f, 1f, 0f, 0f,
- 0f, 0f, 1f, 0f,
- 0f, 0f, 0f, 1f
- );
- /// <summary>
- /// Returns the multiplicative identity matrix.
- /// </summary>
- public static Matrix4x4 Identity
- {
- get { return _identity; }
- }
- /// <summary>
- /// Returns whether the matrix is the identity matrix.
- /// </summary>
- public readonly bool IsIdentity
- {
- get
- {
- return M11 == 1f && M22 == 1f && M33 == 1f && M44 == 1f && // Check diagonal element first for early out.
- M12 == 0f && M13 == 0f && M14 == 0f &&
- M21 == 0f && M23 == 0f && M24 == 0f &&
- M31 == 0f && M32 == 0f && M34 == 0f &&
- M41 == 0f && M42 == 0f && M43 == 0f;
- }
- }
- /// <summary>
- /// Gets or sets the translation component of this matrix.
- /// </summary>
- public Vector3 Translation
- {
- readonly get
- {
- return new Vector3(M41, M42, M43);
- }
- set
- {
- M41 = value.X;
- M42 = value.Y;
- M43 = value.Z;
- }
- }
- /// <summary>
- /// Constructs a Matrix4x4 from the given components.
- /// </summary>
- public Matrix4x4(float m11, float m12, float m13, float m14,
- float m21, float m22, float m23, float m24,
- float m31, float m32, float m33, float m34,
- float m41, float m42, float m43, float m44)
- {
- this.M11 = m11;
- this.M12 = m12;
- this.M13 = m13;
- this.M14 = m14;
- this.M21 = m21;
- this.M22 = m22;
- this.M23 = m23;
- this.M24 = m24;
- this.M31 = m31;
- this.M32 = m32;
- this.M33 = m33;
- this.M34 = m34;
- this.M41 = m41;
- this.M42 = m42;
- this.M43 = m43;
- this.M44 = m44;
- }
- /// <summary>
- /// Constructs a Matrix4x4 from the given Matrix3x2.
- /// </summary>
- /// <param name="value">The source Matrix3x2.</param>
- public Matrix4x4(Matrix3x2 value)
- {
- M11 = value.M11;
- M12 = value.M12;
- M13 = 0f;
- M14 = 0f;
- M21 = value.M21;
- M22 = value.M22;
- M23 = 0f;
- M24 = 0f;
- M31 = 0f;
- M32 = 0f;
- M33 = 1f;
- M34 = 0f;
- M41 = value.M31;
- M42 = value.M32;
- M43 = 0f;
- M44 = 1f;
- }
- /// <summary>
- /// Creates a spherical billboard that rotates around a specified object position.
- /// </summary>
- /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
- /// <param name="cameraPosition">Position of the camera.</param>
- /// <param name="cameraUpVector">The up vector of the camera.</param>
- /// <param name="cameraForwardVector">The forward vector of the camera.</param>
- /// <returns>The created billboard matrix</returns>
- public static Matrix4x4 CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 cameraUpVector, Vector3 cameraForwardVector)
- {
- Vector3 zaxis = new Vector3(
- objectPosition.X - cameraPosition.X,
- objectPosition.Y - cameraPosition.Y,
- objectPosition.Z - cameraPosition.Z);
- float norm = zaxis.LengthSquared();
- if (norm < BillboardEpsilon)
- {
- zaxis = -cameraForwardVector;
- }
- else
- {
- zaxis = Vector3.Multiply(zaxis, 1.0f / MathF.Sqrt(norm));
- }
- Vector3 xaxis = Vector3.Normalize(Vector3.Cross(cameraUpVector, zaxis));
- Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
- Matrix4x4 result;
- result.M11 = xaxis.X;
- result.M12 = xaxis.Y;
- result.M13 = xaxis.Z;
- result.M14 = 0.0f;
- result.M21 = yaxis.X;
- result.M22 = yaxis.Y;
- result.M23 = yaxis.Z;
- result.M24 = 0.0f;
- result.M31 = zaxis.X;
- result.M32 = zaxis.Y;
- result.M33 = zaxis.Z;
- result.M34 = 0.0f;
- result.M41 = objectPosition.X;
- result.M42 = objectPosition.Y;
- result.M43 = objectPosition.Z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a cylindrical billboard that rotates around a specified axis.
- /// </summary>
- /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
- /// <param name="cameraPosition">Position of the camera.</param>
- /// <param name="rotateAxis">Axis to rotate the billboard around.</param>
- /// <param name="cameraForwardVector">Forward vector of the camera.</param>
- /// <param name="objectForwardVector">Forward vector of the object.</param>
- /// <returns>The created billboard matrix.</returns>
- public static Matrix4x4 CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition, Vector3 rotateAxis, Vector3 cameraForwardVector, Vector3 objectForwardVector)
- {
- // Treat the case when object and camera positions are too close.
- Vector3 faceDir = new Vector3(
- objectPosition.X - cameraPosition.X,
- objectPosition.Y - cameraPosition.Y,
- objectPosition.Z - cameraPosition.Z);
- float norm = faceDir.LengthSquared();
- if (norm < BillboardEpsilon)
- {
- faceDir = -cameraForwardVector;
- }
- else
- {
- faceDir = Vector3.Multiply(faceDir, (1.0f / MathF.Sqrt(norm)));
- }
- Vector3 yaxis = rotateAxis;
- Vector3 xaxis;
- Vector3 zaxis;
- // Treat the case when angle between faceDir and rotateAxis is too close to 0.
- float dot = Vector3.Dot(rotateAxis, faceDir);
- if (MathF.Abs(dot) > BillboardMinAngle)
- {
- zaxis = objectForwardVector;
- // Make sure passed values are useful for compute.
- dot = Vector3.Dot(rotateAxis, zaxis);
- if (MathF.Abs(dot) > BillboardMinAngle)
- {
- zaxis = (MathF.Abs(rotateAxis.Z) > BillboardMinAngle) ? new Vector3(1, 0, 0) : new Vector3(0, 0, -1);
- }
- xaxis = Vector3.Normalize(Vector3.Cross(rotateAxis, zaxis));
- zaxis = Vector3.Normalize(Vector3.Cross(xaxis, rotateAxis));
- }
- else
- {
- xaxis = Vector3.Normalize(Vector3.Cross(rotateAxis, faceDir));
- zaxis = Vector3.Normalize(Vector3.Cross(xaxis, yaxis));
- }
- Matrix4x4 result;
- result.M11 = xaxis.X;
- result.M12 = xaxis.Y;
- result.M13 = xaxis.Z;
- result.M14 = 0.0f;
- result.M21 = yaxis.X;
- result.M22 = yaxis.Y;
- result.M23 = yaxis.Z;
- result.M24 = 0.0f;
- result.M31 = zaxis.X;
- result.M32 = zaxis.Y;
- result.M33 = zaxis.Z;
- result.M34 = 0.0f;
- result.M41 = objectPosition.X;
- result.M42 = objectPosition.Y;
- result.M43 = objectPosition.Z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a translation matrix.
- /// </summary>
- /// <param name="position">The amount to translate in each axis.</param>
- /// <returns>The translation matrix.</returns>
- public static Matrix4x4 CreateTranslation(Vector3 position)
- {
- Matrix4x4 result;
- result.M11 = 1.0f;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = 1.0f;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = 1.0f;
- result.M34 = 0.0f;
- result.M41 = position.X;
- result.M42 = position.Y;
- result.M43 = position.Z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a translation matrix.
- /// </summary>
- /// <param name="xPosition">The amount to translate on the X-axis.</param>
- /// <param name="yPosition">The amount to translate on the Y-axis.</param>
- /// <param name="zPosition">The amount to translate on the Z-axis.</param>
- /// <returns>The translation matrix.</returns>
- public static Matrix4x4 CreateTranslation(float xPosition, float yPosition, float zPosition)
- {
- Matrix4x4 result;
- result.M11 = 1.0f;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = 1.0f;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = 1.0f;
- result.M34 = 0.0f;
- result.M41 = xPosition;
- result.M42 = yPosition;
- result.M43 = zPosition;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a scaling matrix.
- /// </summary>
- /// <param name="xScale">Value to scale by on the X-axis.</param>
- /// <param name="yScale">Value to scale by on the Y-axis.</param>
- /// <param name="zScale">Value to scale by on the Z-axis.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(float xScale, float yScale, float zScale)
- {
- Matrix4x4 result;
- result.M11 = xScale;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = yScale;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = zScale;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a scaling matrix with a center point.
- /// </summary>
- /// <param name="xScale">Value to scale by on the X-axis.</param>
- /// <param name="yScale">Value to scale by on the Y-axis.</param>
- /// <param name="zScale">Value to scale by on the Z-axis.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(float xScale, float yScale, float zScale, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float tx = centerPoint.X * (1 - xScale);
- float ty = centerPoint.Y * (1 - yScale);
- float tz = centerPoint.Z * (1 - zScale);
- result.M11 = xScale;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = yScale;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = zScale;
- result.M34 = 0.0f;
- result.M41 = tx;
- result.M42 = ty;
- result.M43 = tz;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a scaling matrix.
- /// </summary>
- /// <param name="scales">The vector containing the amount to scale by on each axis.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(Vector3 scales)
- {
- Matrix4x4 result;
- result.M11 = scales.X;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = scales.Y;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = scales.Z;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a scaling matrix with a center point.
- /// </summary>
- /// <param name="scales">The vector containing the amount to scale by on each axis.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(Vector3 scales, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float tx = centerPoint.X * (1 - scales.X);
- float ty = centerPoint.Y * (1 - scales.Y);
- float tz = centerPoint.Z * (1 - scales.Z);
- result.M11 = scales.X;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = scales.Y;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = scales.Z;
- result.M34 = 0.0f;
- result.M41 = tx;
- result.M42 = ty;
- result.M43 = tz;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a uniform scaling matrix that scales equally on each axis.
- /// </summary>
- /// <param name="scale">The uniform scaling factor.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(float scale)
- {
- Matrix4x4 result;
- result.M11 = scale;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = scale;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = scale;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a uniform scaling matrix that scales equally on each axis with a center point.
- /// </summary>
- /// <param name="scale">The uniform scaling factor.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The scaling matrix.</returns>
- public static Matrix4x4 CreateScale(float scale, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float tx = centerPoint.X * (1 - scale);
- float ty = centerPoint.Y * (1 - scale);
- float tz = centerPoint.Z * (1 - scale);
- result.M11 = scale;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = scale;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = scale;
- result.M34 = 0.0f;
- result.M41 = tx;
- result.M42 = ty;
- result.M43 = tz;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the X-axis.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the X-axis.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationX(float radians)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- // [ 1 0 0 0 ]
- // [ 0 c s 0 ]
- // [ 0 -s c 0 ]
- // [ 0 0 0 1 ]
- result.M11 = 1.0f;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = c;
- result.M23 = s;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = -s;
- result.M33 = c;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the X-axis, from a center point.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the X-axis.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationX(float radians, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- float y = centerPoint.Y * (1 - c) + centerPoint.Z * s;
- float z = centerPoint.Z * (1 - c) - centerPoint.Y * s;
- // [ 1 0 0 0 ]
- // [ 0 c s 0 ]
- // [ 0 -s c 0 ]
- // [ 0 y z 1 ]
- result.M11 = 1.0f;
- result.M12 = 0.0f;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = c;
- result.M23 = s;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = -s;
- result.M33 = c;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = y;
- result.M43 = z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the Y-axis.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the Y-axis.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationY(float radians)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- // [ c 0 -s 0 ]
- // [ 0 1 0 0 ]
- // [ s 0 c 0 ]
- // [ 0 0 0 1 ]
- result.M11 = c;
- result.M12 = 0.0f;
- result.M13 = -s;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = 1.0f;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = s;
- result.M32 = 0.0f;
- result.M33 = c;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the Y-axis, from a center point.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the Y-axis.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationY(float radians, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- float x = centerPoint.X * (1 - c) - centerPoint.Z * s;
- float z = centerPoint.Z * (1 - c) + centerPoint.X * s;
- // [ c 0 -s 0 ]
- // [ 0 1 0 0 ]
- // [ s 0 c 0 ]
- // [ x 0 z 1 ]
- result.M11 = c;
- result.M12 = 0.0f;
- result.M13 = -s;
- result.M14 = 0.0f;
- result.M21 = 0.0f;
- result.M22 = 1.0f;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = s;
- result.M32 = 0.0f;
- result.M33 = c;
- result.M34 = 0.0f;
- result.M41 = x;
- result.M42 = 0.0f;
- result.M43 = z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the Z-axis.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the Z-axis.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationZ(float radians)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- // [ c s 0 0 ]
- // [ -s c 0 0 ]
- // [ 0 0 1 0 ]
- // [ 0 0 0 1 ]
- result.M11 = c;
- result.M12 = s;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = -s;
- result.M22 = c;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = 1.0f;
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix for rotating points around the Z-axis, from a center point.
- /// </summary>
- /// <param name="radians">The amount, in radians, by which to rotate around the Z-axis.</param>
- /// <param name="centerPoint">The center point.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateRotationZ(float radians, Vector3 centerPoint)
- {
- Matrix4x4 result;
- float c = MathF.Cos(radians);
- float s = MathF.Sin(radians);
- float x = centerPoint.X * (1 - c) + centerPoint.Y * s;
- float y = centerPoint.Y * (1 - c) - centerPoint.X * s;
- // [ c s 0 0 ]
- // [ -s c 0 0 ]
- // [ 0 0 1 0 ]
- // [ x y 0 1 ]
- result.M11 = c;
- result.M12 = s;
- result.M13 = 0.0f;
- result.M14 = 0.0f;
- result.M21 = -s;
- result.M22 = c;
- result.M23 = 0.0f;
- result.M24 = 0.0f;
- result.M31 = 0.0f;
- result.M32 = 0.0f;
- result.M33 = 1.0f;
- result.M34 = 0.0f;
- result.M41 = x;
- result.M42 = y;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a matrix that rotates around an arbitrary vector.
- /// </summary>
- /// <param name="axis">The axis to rotate around.</param>
- /// <param name="angle">The angle to rotate around the given axis, in radians.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateFromAxisAngle(Vector3 axis, float angle)
- {
- // a: angle
- // x, y, z: unit vector for axis.
- //
- // Rotation matrix M can compute by using below equation.
- //
- // T T
- // M = uu + (cos a)( I-uu ) + (sin a)S
- //
- // Where:
- //
- // u = ( x, y, z )
- //
- // [ 0 -z y ]
- // S = [ z 0 -x ]
- // [ -y x 0 ]
- //
- // [ 1 0 0 ]
- // I = [ 0 1 0 ]
- // [ 0 0 1 ]
- //
- //
- // [ xx+cosa*(1-xx) yx-cosa*yx-sina*z zx-cosa*xz+sina*y ]
- // M = [ xy-cosa*yx+sina*z yy+cosa(1-yy) yz-cosa*yz-sina*x ]
- // [ zx-cosa*zx-sina*y zy-cosa*zy+sina*x zz+cosa*(1-zz) ]
- //
- float x = axis.X, y = axis.Y, z = axis.Z;
- float sa = MathF.Sin(angle), ca = MathF.Cos(angle);
- float xx = x * x, yy = y * y, zz = z * z;
- float xy = x * y, xz = x * z, yz = y * z;
- Matrix4x4 result;
- result.M11 = xx + ca * (1.0f - xx);
- result.M12 = xy - ca * xy + sa * z;
- result.M13 = xz - ca * xz - sa * y;
- result.M14 = 0.0f;
- result.M21 = xy - ca * xy - sa * z;
- result.M22 = yy + ca * (1.0f - yy);
- result.M23 = yz - ca * yz + sa * x;
- result.M24 = 0.0f;
- result.M31 = xz - ca * xz + sa * y;
- result.M32 = yz - ca * yz - sa * x;
- result.M33 = zz + ca * (1.0f - zz);
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances.
- /// </summary>
- /// <param name="fieldOfView">Field of view in the y direction, in radians.</param>
- /// <param name="aspectRatio">Aspect ratio, defined as view space width divided by height.</param>
- /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
- /// <param name="farPlaneDistance">Distance to the far view plane.</param>
- /// <returns>The perspective projection matrix.</returns>
- public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance)
- {
- if (fieldOfView <= 0.0f || fieldOfView >= MathF.PI)
- throw new ArgumentOutOfRangeException(nameof(fieldOfView));
- if (nearPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- if (farPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
- if (nearPlaneDistance >= farPlaneDistance)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- float yScale = 1.0f / MathF.Tan(fieldOfView * 0.5f);
- float xScale = yScale / aspectRatio;
- Matrix4x4 result;
- result.M11 = xScale;
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = yScale;
- result.M21 = result.M23 = result.M24 = 0.0f;
- result.M31 = result.M32 = 0.0f;
- var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
- result.M33 = negFarRange;
- result.M34 = -1.0f;
- result.M41 = result.M42 = result.M44 = 0.0f;
- result.M43 = nearPlaneDistance * negFarRange;
- return result;
- }
- /// <summary>
- /// Creates a perspective projection matrix from the given view volume dimensions.
- /// </summary>
- /// <param name="width">Width of the view volume at the near view plane.</param>
- /// <param name="height">Height of the view volume at the near view plane.</param>
- /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
- /// <param name="farPlaneDistance">Distance to the far view plane.</param>
- /// <returns>The perspective projection matrix.</returns>
- public static Matrix4x4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance)
- {
- if (nearPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- if (farPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
- if (nearPlaneDistance >= farPlaneDistance)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- Matrix4x4 result;
- result.M11 = 2.0f * nearPlaneDistance / width;
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = 2.0f * nearPlaneDistance / height;
- result.M21 = result.M23 = result.M24 = 0.0f;
- var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
- result.M33 = negFarRange;
- result.M31 = result.M32 = 0.0f;
- result.M34 = -1.0f;
- result.M41 = result.M42 = result.M44 = 0.0f;
- result.M43 = nearPlaneDistance * negFarRange;
- return result;
- }
- /// <summary>
- /// Creates a customized, perspective projection matrix.
- /// </summary>
- /// <param name="left">Minimum x-value of the view volume at the near view plane.</param>
- /// <param name="right">Maximum x-value of the view volume at the near view plane.</param>
- /// <param name="bottom">Minimum y-value of the view volume at the near view plane.</param>
- /// <param name="top">Maximum y-value of the view volume at the near view plane.</param>
- /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
- /// <param name="farPlaneDistance">Distance to of the far view plane.</param>
- /// <returns>The perspective projection matrix.</returns>
- public static Matrix4x4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance)
- {
- if (nearPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- if (farPlaneDistance <= 0.0f)
- throw new ArgumentOutOfRangeException(nameof(farPlaneDistance));
- if (nearPlaneDistance >= farPlaneDistance)
- throw new ArgumentOutOfRangeException(nameof(nearPlaneDistance));
- Matrix4x4 result;
- result.M11 = 2.0f * nearPlaneDistance / (right - left);
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = 2.0f * nearPlaneDistance / (top - bottom);
- result.M21 = result.M23 = result.M24 = 0.0f;
- result.M31 = (left + right) / (right - left);
- result.M32 = (top + bottom) / (top - bottom);
- var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance);
- result.M33 = negFarRange;
- result.M34 = -1.0f;
- result.M43 = nearPlaneDistance * negFarRange;
- result.M41 = result.M42 = result.M44 = 0.0f;
- return result;
- }
- /// <summary>
- /// Creates an orthographic perspective matrix from the given view volume dimensions.
- /// </summary>
- /// <param name="width">Width of the view volume.</param>
- /// <param name="height">Height of the view volume.</param>
- /// <param name="zNearPlane">Minimum Z-value of the view volume.</param>
- /// <param name="zFarPlane">Maximum Z-value of the view volume.</param>
- /// <returns>The orthographic projection matrix.</returns>
- public static Matrix4x4 CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane)
- {
- Matrix4x4 result;
- result.M11 = 2.0f / width;
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = 2.0f / height;
- result.M21 = result.M23 = result.M24 = 0.0f;
- result.M33 = 1.0f / (zNearPlane - zFarPlane);
- result.M31 = result.M32 = result.M34 = 0.0f;
- result.M41 = result.M42 = 0.0f;
- result.M43 = zNearPlane / (zNearPlane - zFarPlane);
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Builds a customized, orthographic projection matrix.
- /// </summary>
- /// <param name="left">Minimum X-value of the view volume.</param>
- /// <param name="right">Maximum X-value of the view volume.</param>
- /// <param name="bottom">Minimum Y-value of the view volume.</param>
- /// <param name="top">Maximum Y-value of the view volume.</param>
- /// <param name="zNearPlane">Minimum Z-value of the view volume.</param>
- /// <param name="zFarPlane">Maximum Z-value of the view volume.</param>
- /// <returns>The orthographic projection matrix.</returns>
- public static Matrix4x4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane)
- {
- Matrix4x4 result;
- result.M11 = 2.0f / (right - left);
- result.M12 = result.M13 = result.M14 = 0.0f;
- result.M22 = 2.0f / (top - bottom);
- result.M21 = result.M23 = result.M24 = 0.0f;
- result.M33 = 1.0f / (zNearPlane - zFarPlane);
- result.M31 = result.M32 = result.M34 = 0.0f;
- result.M41 = (left + right) / (left - right);
- result.M42 = (top + bottom) / (bottom - top);
- result.M43 = zNearPlane / (zNearPlane - zFarPlane);
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a view matrix.
- /// </summary>
- /// <param name="cameraPosition">The position of the camera.</param>
- /// <param name="cameraTarget">The target towards which the camera is pointing.</param>
- /// <param name="cameraUpVector">The direction that is "up" from the camera's point of view.</param>
- /// <returns>The view matrix.</returns>
- public static Matrix4x4 CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
- {
- Vector3 zaxis = Vector3.Normalize(cameraPosition - cameraTarget);
- Vector3 xaxis = Vector3.Normalize(Vector3.Cross(cameraUpVector, zaxis));
- Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
- Matrix4x4 result;
- result.M11 = xaxis.X;
- result.M12 = yaxis.X;
- result.M13 = zaxis.X;
- result.M14 = 0.0f;
- result.M21 = xaxis.Y;
- result.M22 = yaxis.Y;
- result.M23 = zaxis.Y;
- result.M24 = 0.0f;
- result.M31 = xaxis.Z;
- result.M32 = yaxis.Z;
- result.M33 = zaxis.Z;
- result.M34 = 0.0f;
- result.M41 = -Vector3.Dot(xaxis, cameraPosition);
- result.M42 = -Vector3.Dot(yaxis, cameraPosition);
- result.M43 = -Vector3.Dot(zaxis, cameraPosition);
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a world matrix with the specified parameters.
- /// </summary>
- /// <param name="position">The position of the object; used in translation operations.</param>
- /// <param name="forward">Forward direction of the object.</param>
- /// <param name="up">Upward direction of the object; usually [0, 1, 0].</param>
- /// <returns>The world matrix.</returns>
- public static Matrix4x4 CreateWorld(Vector3 position, Vector3 forward, Vector3 up)
- {
- Vector3 zaxis = Vector3.Normalize(-forward);
- Vector3 xaxis = Vector3.Normalize(Vector3.Cross(up, zaxis));
- Vector3 yaxis = Vector3.Cross(zaxis, xaxis);
- Matrix4x4 result;
- result.M11 = xaxis.X;
- result.M12 = xaxis.Y;
- result.M13 = xaxis.Z;
- result.M14 = 0.0f;
- result.M21 = yaxis.X;
- result.M22 = yaxis.Y;
- result.M23 = yaxis.Z;
- result.M24 = 0.0f;
- result.M31 = zaxis.X;
- result.M32 = zaxis.Y;
- result.M33 = zaxis.Z;
- result.M34 = 0.0f;
- result.M41 = position.X;
- result.M42 = position.Y;
- result.M43 = position.Z;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a rotation matrix from the given Quaternion rotation value.
- /// </summary>
- /// <param name="quaternion">The source Quaternion.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateFromQuaternion(Quaternion quaternion)
- {
- Matrix4x4 result;
- float xx = quaternion.X * quaternion.X;
- float yy = quaternion.Y * quaternion.Y;
- float zz = quaternion.Z * quaternion.Z;
- float xy = quaternion.X * quaternion.Y;
- float wz = quaternion.Z * quaternion.W;
- float xz = quaternion.Z * quaternion.X;
- float wy = quaternion.Y * quaternion.W;
- float yz = quaternion.Y * quaternion.Z;
- float wx = quaternion.X * quaternion.W;
- result.M11 = 1.0f - 2.0f * (yy + zz);
- result.M12 = 2.0f * (xy + wz);
- result.M13 = 2.0f * (xz - wy);
- result.M14 = 0.0f;
- result.M21 = 2.0f * (xy - wz);
- result.M22 = 1.0f - 2.0f * (zz + xx);
- result.M23 = 2.0f * (yz + wx);
- result.M24 = 0.0f;
- result.M31 = 2.0f * (xz + wy);
- result.M32 = 2.0f * (yz - wx);
- result.M33 = 1.0f - 2.0f * (yy + xx);
- result.M34 = 0.0f;
- result.M41 = 0.0f;
- result.M42 = 0.0f;
- result.M43 = 0.0f;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Creates a rotation matrix from the specified yaw, pitch, and roll.
- /// </summary>
- /// <param name="yaw">Angle of rotation, in radians, around the Y-axis.</param>
- /// <param name="pitch">Angle of rotation, in radians, around the X-axis.</param>
- /// <param name="roll">Angle of rotation, in radians, around the Z-axis.</param>
- /// <returns>The rotation matrix.</returns>
- public static Matrix4x4 CreateFromYawPitchRoll(float yaw, float pitch, float roll)
- {
- Quaternion q = Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll);
- return Matrix4x4.CreateFromQuaternion(q);
- }
- /// <summary>
- /// Creates a Matrix that flattens geometry into a specified Plane as if casting a shadow from a specified light source.
- /// </summary>
- /// <param name="lightDirection">The direction from which the light that will cast the shadow is coming.</param>
- /// <param name="plane">The Plane onto which the new matrix should flatten geometry so as to cast a shadow.</param>
- /// <returns>A new Matrix that can be used to flatten geometry onto the specified plane from the specified direction.</returns>
- public static Matrix4x4 CreateShadow(Vector3 lightDirection, Plane plane)
- {
- Plane p = Plane.Normalize(plane);
- float dot = p.Normal.X * lightDirection.X + p.Normal.Y * lightDirection.Y + p.Normal.Z * lightDirection.Z;
- float a = -p.Normal.X;
- float b = -p.Normal.Y;
- float c = -p.Normal.Z;
- float d = -p.D;
- Matrix4x4 result;
- result.M11 = a * lightDirection.X + dot;
- result.M21 = b * lightDirection.X;
- result.M31 = c * lightDirection.X;
- result.M41 = d * lightDirection.X;
- result.M12 = a * lightDirection.Y;
- result.M22 = b * lightDirection.Y + dot;
- result.M32 = c * lightDirection.Y;
- result.M42 = d * lightDirection.Y;
- result.M13 = a * lightDirection.Z;
- result.M23 = b * lightDirection.Z;
- result.M33 = c * lightDirection.Z + dot;
- result.M43 = d * lightDirection.Z;
- result.M14 = 0.0f;
- result.M24 = 0.0f;
- result.M34 = 0.0f;
- result.M44 = dot;
- return result;
- }
- /// <summary>
- /// Creates a Matrix that reflects the coordinate system about a specified Plane.
- /// </summary>
- /// <param name="value">The Plane about which to create a reflection.</param>
- /// <returns>A new matrix expressing the reflection.</returns>
- public static Matrix4x4 CreateReflection(Plane value)
- {
- value = Plane.Normalize(value);
- float a = value.Normal.X;
- float b = value.Normal.Y;
- float c = value.Normal.Z;
- float fa = -2.0f * a;
- float fb = -2.0f * b;
- float fc = -2.0f * c;
- Matrix4x4 result;
- result.M11 = fa * a + 1.0f;
- result.M12 = fb * a;
- result.M13 = fc * a;
- result.M14 = 0.0f;
- result.M21 = fa * b;
- result.M22 = fb * b + 1.0f;
- result.M23 = fc * b;
- result.M24 = 0.0f;
- result.M31 = fa * c;
- result.M32 = fb * c;
- result.M33 = fc * c + 1.0f;
- result.M34 = 0.0f;
- result.M41 = fa * value.D;
- result.M42 = fb * value.D;
- result.M43 = fc * value.D;
- result.M44 = 1.0f;
- return result;
- }
- /// <summary>
- /// Calculates the determinant of the matrix.
- /// </summary>
- /// <returns>The determinant of the matrix.</returns>
- public readonly float GetDeterminant()
- {
- // | a b c d | | f g h | | e g h | | e f h | | e f g |
- // | e f g h | = a | j k l | - b | i k l | + c | i j l | - d | i j k |
- // | i j k l | | n o p | | m o p | | m n p | | m n o |
- // | m n o p |
- //
- // | f g h |
- // a | j k l | = a ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
- // | n o p |
- //
- // | e g h |
- // b | i k l | = b ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
- // | m o p |
- //
- // | e f h |
- // c | i j l | = c ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
- // | m n p |
- //
- // | e f g |
- // d | i j k | = d ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
- // | m n o |
- //
- // Cost of operation
- // 17 adds and 28 muls.
- //
- // add: 6 + 8 + 3 = 17
- // mul: 12 + 16 = 28
- float a = M11, b = M12, c = M13, d = M14;
- float e = M21, f = M22, g = M23, h = M24;
- float i = M31, j = M32, k = M33, l = M34;
- float m = M41, n = M42, o = M43, p = M44;
- float kp_lo = k * p - l * o;
- float jp_ln = j * p - l * n;
- float jo_kn = j * o - k * n;
- float ip_lm = i * p - l * m;
- float io_km = i * o - k * m;
- float in_jm = i * n - j * m;
- return a * (f * kp_lo - g * jp_ln + h * jo_kn) -
- b * (e * kp_lo - g * ip_lm + h * io_km) +
- c * (e * jp_ln - f * ip_lm + h * in_jm) -
- d * (e * jo_kn - f * io_km + g * in_jm);
- }
- /// <summary>
- /// Attempts to calculate the inverse of the given matrix. If successful, result will contain the inverted matrix.
- /// </summary>
- /// <param name="matrix">The source matrix to invert.</param>
- /// <param name="result">If successful, contains the inverted matrix.</param>
- /// <returns>True if the source matrix could be inverted; False otherwise.</returns>
- public static bool Invert(Matrix4x4 matrix, out Matrix4x4 result)
- {
- // -1
- // If you have matrix M, inverse Matrix M can compute
- //
- // -1 1
- // M = --------- A
- // det(M)
- //
- // A is adjugate (adjoint) of M, where,
- //
- // T
- // A = C
- //
- // C is Cofactor matrix of M, where,
- // i + j
- // C = (-1) * det(M )
- // ij ij
- //
- // [ a b c d ]
- // M = [ e f g h ]
- // [ i j k l ]
- // [ m n o p ]
- //
- // First Row
- // 2 | f g h |
- // C = (-1) | j k l | = + ( f ( kp - lo ) - g ( jp - ln ) + h ( jo - kn ) )
- // 11 | n o p |
- //
- // 3 | e g h |
- // C = (-1) | i k l | = - ( e ( kp - lo ) - g ( ip - lm ) + h ( io - km ) )
- // 12 | m o p |
- //
- // 4 | e f h |
- // C = (-1) | i j l | = + ( e ( jp - ln ) - f ( ip - lm ) + h ( in - jm ) )
- // 13 | m n p |
- //
- // 5 | e f g |
- // C = (-1) | i j k | = - ( e ( jo - kn ) - f ( io - km ) + g ( in - jm ) )
- // 14 | m n o |
- //
- // Second Row
- // 3 | b c d |
- // C = (-1) | j k l | = - ( b ( kp - lo ) - c ( jp - ln ) + d ( jo - kn ) )
- // 21 | n o p |
- //
- // 4 | a c d |
- // C = (-1) | i k l | = + ( a ( kp - lo ) - c ( ip - lm ) + d ( io - km ) )
- // 22 | m o p |
- //
- // 5 | a b d |
- // C = (-1) | i j l | = - ( a ( jp - ln ) - b ( ip - lm ) + d ( in - jm ) )
- // 23 | m n p |
- //
- // 6 | a b c |
- // C = (-1) | i j k | = + ( a ( jo - kn ) - b ( io - km ) + c ( in - jm ) )
- // 24 | m n o |
- //
- // Third Row
- // 4 | b c d |
- // C = (-1) | f g h | = + ( b ( gp - ho ) - c ( fp - hn ) + d ( fo - gn ) )
- // 31 | n o p |
- //
- // 5 | a c d |
- // C = (-1) | e g h | = - ( a ( gp - ho ) - c ( ep - hm ) + d ( eo - gm ) )
- // 32 | m o p |
- //
- // 6 | a b d |
- // C = (-1) | e f h | = + ( a ( fp - hn ) - b ( ep - hm ) + d ( en - fm ) )
- // 33 | m n p |
- //
- // 7 | a b c |
- // C = (-1) | e f g | = - ( a ( fo - gn ) - b ( eo - gm ) + c ( en - fm ) )
- // 34 | m n o |
- //
- // Fourth Row
- // 5 | b c d |
- // C = (-1) | f g h | = - ( b ( gl - hk ) - c ( fl - hj ) + d ( fk - gj ) )
- // 41 | j k l |
- //
- // 6 | a c d |
- // C = (-1) | e g h | = + ( a ( gl - hk ) - c ( el - hi ) + d ( ek - gi ) )
- // 42 | i k l |
- //
- // 7 | a b d |
- // C = (-1) | e f h | = - ( a ( fl - hj ) - b ( el - hi ) + d ( ej - fi ) )
- // 43 | i j l |
- //
- // 8 | a b c |
- // C = (-1) | e f g | = + ( a ( fk - gj ) - b ( ek - gi ) + c ( ej - fi ) )
- // 44 | i j k |
- //
- // Cost of operation
- // 53 adds, 104 muls, and 1 div.
- float a = matrix.M11, b = matrix.M12, c = matrix.M13, d = matrix.M14;
- float e = matrix.M21, f = matrix.M22, g = matrix.M23, h = matrix.M24;
- float i = matrix.M31, j = matrix.M32, k = matrix.M33, l = matrix.M34;
- float m = matrix.M41, n = matrix.M42, o = matrix.M43, p = matrix.M44;
- float kp_lo = k * p - l * o;
- float jp_ln = j * p - l * n;
- float jo_kn = j * o - k * n;
- float ip_lm = i * p - l * m;
- float io_km = i * o - k * m;
- float in_jm = i * n - j * m;
- float a11 = +(f * kp_lo - g * jp_ln + h * jo_kn);
- float a12 = -(e * kp_lo - g * ip_lm + h * io_km);
- float a13 = +(e * jp_ln - f * ip_lm + h * in_jm);
- float a14 = -(e * jo_kn - f * io_km + g * in_jm);
- float det = a * a11 + b * a12 + c * a13 + d * a14;
- if (MathF.Abs(det) < float.Epsilon)
- {
- result = new Matrix4x4(float.NaN, float.NaN, float.NaN, float.NaN,
- float.NaN, float.NaN, float.NaN, float.NaN,
- float.NaN, float.NaN, float.NaN, float.NaN,
- float.NaN, float.NaN, float.NaN, float.NaN);
- return false;
- }
- float invDet = 1.0f / det;
- result.M11 = a11 * invDet;
- result.M21 = a12 * invDet;
- result.M31 = a13 * invDet;
- result.M41 = a14 * invDet;
- result.M12 = -(b * kp_lo - c * jp_ln + d * jo_kn) * invDet;
- result.M22 = +(a * kp_lo - c * ip_lm + d * io_km) * invDet;
- result.M32 = -(a * jp_ln - b * ip_lm + d * in_jm) * invDet;
- result.M42 = +(a * jo_kn - b * io_km + c * in_jm) * invDet;
- float gp_ho = g * p - h * o;
- float fp_hn = f * p - h * n;
- float fo_gn = f * o - g * n;
- float ep_hm = e * p - h * m;
- float eo_gm = e * o - g * m;
- float en_fm = e * n - f * m;
- result.M13 = +(b * gp_ho - c * fp_hn + d * fo_gn) * invDet;
- result.M23 = -(a * gp_ho - c * ep_hm + d * eo_gm) * invDet;
- result.M33 = +(a * fp_hn - b * ep_hm + d * en_fm) * invDet;
- result.M43 = -(a * fo_gn - b * eo_gm + c * en_fm) * invDet;
- float gl_hk = g * l - h * k;
- float fl_hj = f * l - h * j;
- float fk_gj = f * k - g * j;
- float el_hi = e * l - h * i;
- float ek_gi = e * k - g * i;
- float ej_fi = e * j - f * i;
- result.M14 = -(b * gl_hk - c * fl_hj + d * fk_gj) * invDet;
- result.M24 = +(a * gl_hk - c * el_hi + d * ek_gi) * invDet;
- result.M34 = -(a * fl_hj - b * el_hi + d * ej_fi) * invDet;
- result.M44 = +(a * fk_gj - b * ek_gi + c * ej_fi) * invDet;
- return true;
- }
- private struct CanonicalBasis
- {
- public Vector3 Row0;
- public Vector3 Row1;
- public Vector3 Row2;
- };
- private struct VectorBasis
- {
- public unsafe Vector3* Element0;
- public unsafe Vector3* Element1;
- public unsafe Vector3* Element2;
- }
- /// <summary>
- /// Attempts to extract the scale, translation, and rotation components from the given scale/rotation/translation matrix.
- /// If successful, the out parameters will contained the extracted values.
- /// </summary>
- /// <param name="matrix">The source matrix.</param>
- /// <param name="scale">The scaling component of the transformation matrix.</param>
- /// <param name="rotation">The rotation component of the transformation matrix.</param>
- /// <param name="translation">The translation component of the transformation matrix</param>
- /// <returns>True if the source matrix was successfully decomposed; False otherwise.</returns>
- public static bool Decompose(Matrix4x4 matrix, out Vector3 scale, out Quaternion rotation, out Vector3 translation)
- {
- bool result = true;
- unsafe
- {
- fixed (Vector3* scaleBase = &scale)
- {
- float* pfScales = (float*)scaleBase;
- float det;
- VectorBasis vectorBasis;
- Vector3** pVectorBasis = (Vector3**)&vectorBasis;
- Matrix4x4 matTemp = Matrix4x4.Identity;
- CanonicalBasis canonicalBasis = default;
- Vector3* pCanonicalBasis = &canonicalBasis.Row0;
- canonicalBasis.Row0 = new Vector3(1.0f, 0.0f, 0.0f);
- canonicalBasis.Row1 = new Vector3(0.0f, 1.0f, 0.0f);
- canonicalBasis.Row2 = new Vector3(0.0f, 0.0f, 1.0f);
- translation = new Vector3(
- matrix.M41,
- matrix.M42,
- matrix.M43);
- pVectorBasis[0] = (Vector3*)&matTemp.M11;
- pVectorBasis[1] = (Vector3*)&matTemp.M21;
- pVectorBasis[2] = (Vector3*)&matTemp.M31;
- *(pVectorBasis[0]) = new Vector3(matrix.M11, matrix.M12, matrix.M13);
- *(pVectorBasis[1]) = new Vector3(matrix.M21, matrix.M22, matrix.M23);
- *(pVectorBasis[2]) = new Vector3(matrix.M31, matrix.M32, matrix.M33);
- scale.X = pVectorBasis[0]->Length();
- scale.Y = pVectorBasis[1]->Length();
- scale.Z = pVectorBasis[2]->Length();
- uint a, b, c;
- #region Ranking
- float x = pfScales[0], y = pfScales[1], z = pfScales[2];
- if (x < y)
- {
- if (y < z)
- {
- a = 2;
- b = 1;
- c = 0;
- }
- else
- {
- a = 1;
- if (x < z)
- {
- b = 2;
- c = 0;
- }
- else
- {
- b = 0;
- c = 2;
- }
- }
- }
- else
- {
- if (x < z)
- {
- a = 2;
- b = 0;
- c = 1;
- }
- else
- {
- a = 0;
- if (y < z)
- {
- b = 2;
- c = 1;
- }
- else
- {
- b = 1;
- c = 2;
- }
- }
- }
- #endregion
- if (pfScales[a] < DecomposeEpsilon)
- {
- *(pVectorBasis[a]) = pCanonicalBasis[a];
- }
- *pVectorBasis[a] = Vector3.Normalize(*pVectorBasis[a]);
- if (pfScales[b] < DecomposeEpsilon)
- {
- uint cc;
- float fAbsX, fAbsY, fAbsZ;
- fAbsX = MathF.Abs(pVectorBasis[a]->X);
- fAbsY = MathF.Abs(pVectorBasis[a]->Y);
- fAbsZ = MathF.Abs(pVectorBasis[a]->Z);
- #region Ranking
- if (fAbsX < fAbsY)
- {
- if (fAbsY < fAbsZ)
- {
- cc = 0;
- }
- else
- {
- if (fAbsX < fAbsZ)
- {
- cc = 0;
- }
- else
- {
- cc = 2;
- }
- }
- }
- else
- {
- if (fAbsX < fAbsZ)
- {
- cc = 1;
- }
- else
- {
- if (fAbsY < fAbsZ)
- {
- cc = 1;
- }
- else
- {
- cc = 2;
- }
- }
- }
- #endregion
- *pVectorBasis[b] = Vector3.Cross(*pVectorBasis[a], *(pCanonicalBasis + cc));
- }
- *pVectorBasis[b] = Vector3.Normalize(*pVectorBasis[b]);
- if (pfScales[c] < DecomposeEpsilon)
- {
- *pVectorBasis[c] = Vector3.Cross(*pVectorBasis[a], *pVectorBasis[b]);
- }
- *pVectorBasis[c] = Vector3.Normalize(*pVectorBasis[c]);
- det = matTemp.GetDeterminant();
- // use Kramer's rule to check for handedness of coordinate system
- if (det < 0.0f)
- {
- // switch coordinate system by negating the scale and inverting the basis vector on the x-axis
- pfScales[a] = -pfScales[a];
- *pVectorBasis[a] = -(*pVectorBasis[a]);
- det = -det;
- }
- det -= 1.0f;
- det *= det;
- if ((DecomposeEpsilon < det))
- {
- // Non-SRT matrix encountered
- rotation = Quaternion.Identity;
- result = false;
- }
- else
- {
- // generate the quaternion from the matrix
- rotation = Quaternion.CreateFromRotationMatrix(matTemp);
- }
- }
- }
- return result;
- }
- /// <summary>
- /// Transforms the given matrix by applying the given Quaternion rotation.
- /// </summary>
- /// <param name="value">The source matrix to transform.</param>
- /// <param name="rotation">The rotation to apply.</param>
- /// <returns>The transformed matrix.</returns>
- public static Matrix4x4 Transform(Matrix4x4 value, Quaternion rotation)
- {
- // Compute rotation matrix.
- float x2 = rotation.X + rotation.X;
- float y2 = rotation.Y + rotation.Y;
- float z2 = rotation.Z + rotation.Z;
- float wx2 = rotation.W * x2;
- float wy2 = rotation.W * y2;
- float wz2 = rotation.W * z2;
- float xx2 = rotation.X * x2;
- float xy2 = rotation.X * y2;
- float xz2 = rotation.X * z2;
- float yy2 = rotation.Y * y2;
- float yz2 = rotation.Y * z2;
- float zz2 = rotation.Z * z2;
- float q11 = 1.0f - yy2 - zz2;
- float q21 = xy2 - wz2;
- float q31 = xz2 + wy2;
- float q12 = xy2 + wz2;
- float q22 = 1.0f - xx2 - zz2;
- float q32 = yz2 - wx2;
- float q13 = xz2 - wy2;
- float q23 = yz2 + wx2;
- float q33 = 1.0f - xx2 - yy2;
- Matrix4x4 result;
- // First row
- result.M11 = value.M11 * q11 + value.M12 * q21 + value.M13 * q31;
- result.M12 = value.M11 * q12 + value.M12 * q22 + value.M13 * q32;
- result.M13 = value.M11 * q13 + value.M12 * q23 + value.M13 * q33;
- result.M14 = value.M14;
- // Second row
- result.M21 = value.M21 * q11 + value.M22 * q21 + value.M23 * q31;
- result.M22 = value.M21 * q12 + value.M22 * q22 + value.M23 * q32;
- result.M23 = value.M21 * q13 + value.M22 * q23 + value.M23 * q33;
- result.M24 = value.M24;
- // Third row
- result.M31 = value.M31 * q11 + value.M32 * q21 + value.M33 * q31;
- result.M32 = value.M31 * q12 + value.M32 * q22 + value.M33 * q32;
- result.M33 = value.M31 * q13 + value.M32 * q23 + value.M33 * q33;
- result.M34 = value.M34;
- // Fourth row
- result.M41 = value.M41 * q11 + value.M42 * q21 + value.M43 * q31;
- result.M42 = value.M41 * q12 + value.M42 * q22 + value.M43 * q32;
- result.M43 = value.M41 * q13 + value.M42 * q23 + value.M43 * q33;
- result.M44 = value.M44;
- return result;
- }
- /// <summary>
- /// Transposes the rows and columns of a matrix.
- /// </summary>
- /// <param name="matrix">The source matrix.</param>
- /// <returns>The transposed matrix.</returns>
- public static unsafe Matrix4x4 Transpose(Matrix4x4 matrix)
- {
- if (Sse.IsSupported)
- {
- var row1 = Sse.LoadVector128(&matrix.M11);
- var row2 = Sse.LoadVector128(&matrix.M21);
- var row3 = Sse.LoadVector128(&matrix.M31);
- var row4 = Sse.LoadVector128(&matrix.M41);
- var l12 = Sse.UnpackLow(row1, row2);
- var l34 = Sse.UnpackLow(row3, row4);
- var h12 = Sse.UnpackHigh(row1, row2);
- var h34 = Sse.UnpackHigh(row3, row4);
- Sse.Store(&matrix.M11, Sse.MoveLowToHigh(l12, l34));
- Sse.Store(&matrix.M21, Sse.MoveHighToLow(l34, l12));
- Sse.Store(&matrix.M31, Sse.MoveLowToHigh(h12, h34));
- Sse.Store(&matrix.M41, Sse.MoveHighToLow(h34, h12));
- return matrix;
- }
- Matrix4x4 result;
- result.M11 = matrix.M11;
- result.M12 = matrix.M21;
- result.M13 = matrix.M31;
- result.M14 = matrix.M41;
- result.M21 = matrix.M12;
- result.M22 = matrix.M22;
- result.M23 = matrix.M32;
- result.M24 = matrix.M42;
- result.M31 = matrix.M13;
- result.M32 = matrix.M23;
- result.M33 = matrix.M33;
- result.M34 = matrix.M43;
- result.M41 = matrix.M14;
- result.M42 = matrix.M24;
- result.M43 = matrix.M34;
- result.M44 = matrix.M44;
- return result;
- }
- /// <summary>
- /// Linearly interpolates between the corresponding values of two matrices.
- /// </summary>
- /// <param name="matrix1">The first source matrix.</param>
- /// <param name="matrix2">The second source matrix.</param>
- /// <param name="amount">The relative weight of the second source matrix.</param>
- /// <returns>The interpolated matrix.</returns>
- public static unsafe Matrix4x4 Lerp(Matrix4x4 matrix1, Matrix4x4 matrix2, float amount)
- {
- if (Sse.IsSupported)
- {
- Vector128<float> amountVec = Vector128.Create(amount);
- Sse.Store(&matrix1.M11, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M11), Sse.LoadVector128(&matrix2.M11), amountVec));
- Sse.Store(&matrix1.M21, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M21), Sse.LoadVector128(&matrix2.M21), amountVec));
- Sse.Store(&matrix1.M31, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M31), Sse.LoadVector128(&matrix2.M31), amountVec));
- Sse.Store(&matrix1.M41, VectorMath.Lerp(Sse.LoadVector128(&matrix1.M41), Sse.LoadVector128(&matrix2.M41), amountVec));
- return matrix1;
- }
- Matrix4x4 result;
- // First row
- result.M11 = matrix1.M11 + (matrix2.M11 - matrix1.M11) * amount;
- result.M12 = matrix1.M12 + (matrix2.M12 - matrix1.M12) * amount;
- result.M13 = matrix1.M13 + (matrix2.M13 - matrix1.M13) * amount;
- result.M14 = matrix1.M14 + (matrix2.M14 - matrix1.M14) * amount;
- // Second row
- result.M21 = matrix1.M21 + (matrix2.M21 - matrix1.M21) * amount;
- result.M22 = matrix1.M22 + (matrix2.M22 - matrix1.M22) * amount;
- result.M23 = matrix1.M23 + (matrix2.M23 - matrix1.M23) * amount;
- result.M24 = matrix1.M24 + (matrix2.M24 - matrix1.M24) * amount;
- // Third row
- result.M31 = matrix1.M31 + (matrix2.M31 - matrix1.M31) * amount;
- result.M32 = matrix1.M32 + (matrix2.M32 - matrix1.M32) * amount;
- result.M33 = matrix1.M33 + (matrix2.M33 - matrix1.M33) * amount;
- result.M34 = matrix1.M34 + (matrix2.M34 - matrix1.M34) * amount;
- // Fourth row
- result.M41 = matrix1.M41 + (matrix2.M41 - matrix1.M41) * amount;
- result.M42 = matrix1.M42 + (matrix2.M42 - matrix1.M42) * amount;
- result.M43 = matrix1.M43 + (matrix2.M43 - matrix1.M43) * amount;
- result.M44 = matrix1.M44 + (matrix2.M44 - matrix1.M44) * amount;
- return result;
- }
- /// <summary>
- /// Returns a new matrix with the negated elements of the given matrix.
- /// </summary>
- /// <param name="value">The source matrix.</param>
- /// <returns>The negated matrix.</returns>
- public static Matrix4x4 Negate(Matrix4x4 value) => -value;
- /// <summary>
- /// Adds two matrices together.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The resulting matrix.</returns>
- public static Matrix4x4 Add(Matrix4x4 value1, Matrix4x4 value2) => value1 + value2;
- /// <summary>
- /// Subtracts the second matrix from the first.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The result of the subtraction.</returns>
- public static Matrix4x4 Subtract(Matrix4x4 value1, Matrix4x4 value2) => value1 - value2;
- /// <summary>
- /// Multiplies a matrix by another matrix.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The result of the multiplication.</returns>
- public static Matrix4x4 Multiply(Matrix4x4 value1, Matrix4x4 value2) => value1 * value2;
- /// <summary>
- /// Multiplies a matrix by a scalar value.
- /// </summary>
- /// <param name="value1">The source matrix.</param>
- /// <param name="value2">The scaling factor.</param>
- /// <returns>The scaled matrix.</returns>
- public static Matrix4x4 Multiply(Matrix4x4 value1, float value2) => value1 * value2;
- /// <summary>
- /// Returns a new matrix with the negated elements of the given matrix.
- /// </summary>
- /// <param name="value">The source matrix.</param>
- /// <returns>The negated matrix.</returns>
- public static unsafe Matrix4x4 operator -(Matrix4x4 value)
- {
- if (Sse.IsSupported)
- {
- Vector128<float> zero = Vector128<float>.Zero;
- Sse.Store(&value.M11, Sse.Subtract(zero, Sse.LoadVector128(&value.M11)));
- Sse.Store(&value.M21, Sse.Subtract(zero, Sse.LoadVector128(&value.M21)));
- Sse.Store(&value.M31, Sse.Subtract(zero, Sse.LoadVector128(&value.M31)));
- Sse.Store(&value.M41, Sse.Subtract(zero, Sse.LoadVector128(&value.M41)));
- return value;
- }
- Matrix4x4 m;
- m.M11 = -value.M11;
- m.M12 = -value.M12;
- m.M13 = -value.M13;
- m.M14 = -value.M14;
- m.M21 = -value.M21;
- m.M22 = -value.M22;
- m.M23 = -value.M23;
- m.M24 = -value.M24;
- m.M31 = -value.M31;
- m.M32 = -value.M32;
- m.M33 = -value.M33;
- m.M34 = -value.M34;
- m.M41 = -value.M41;
- m.M42 = -value.M42;
- m.M43 = -value.M43;
- m.M44 = -value.M44;
- return m;
- }
- /// <summary>
- /// Adds two matrices together.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The resulting matrix.</returns>
- public static unsafe Matrix4x4 operator +(Matrix4x4 value1, Matrix4x4 value2)
- {
- if (Sse.IsSupported)
- {
- Sse.Store(&value1.M11, Sse.Add(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)));
- Sse.Store(&value1.M21, Sse.Add(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)));
- Sse.Store(&value1.M31, Sse.Add(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)));
- Sse.Store(&value1.M41, Sse.Add(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41)));
- return value1;
- }
- Matrix4x4 m;
- m.M11 = value1.M11 + value2.M11;
- m.M12 = value1.M12 + value2.M12;
- m.M13 = value1.M13 + value2.M13;
- m.M14 = value1.M14 + value2.M14;
- m.M21 = value1.M21 + value2.M21;
- m.M22 = value1.M22 + value2.M22;
- m.M23 = value1.M23 + value2.M23;
- m.M24 = value1.M24 + value2.M24;
- m.M31 = value1.M31 + value2.M31;
- m.M32 = value1.M32 + value2.M32;
- m.M33 = value1.M33 + value2.M33;
- m.M34 = value1.M34 + value2.M34;
- m.M41 = value1.M41 + value2.M41;
- m.M42 = value1.M42 + value2.M42;
- m.M43 = value1.M43 + value2.M43;
- m.M44 = value1.M44 + value2.M44;
- return m;
- }
- /// <summary>
- /// Subtracts the second matrix from the first.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The result of the subtraction.</returns>
- public static unsafe Matrix4x4 operator -(Matrix4x4 value1, Matrix4x4 value2)
- {
- if (Sse.IsSupported)
- {
- Sse.Store(&value1.M11, Sse.Subtract(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)));
- Sse.Store(&value1.M21, Sse.Subtract(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)));
- Sse.Store(&value1.M31, Sse.Subtract(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)));
- Sse.Store(&value1.M41, Sse.Subtract(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41)));
- return value1;
- }
- Matrix4x4 m;
- m.M11 = value1.M11 - value2.M11;
- m.M12 = value1.M12 - value2.M12;
- m.M13 = value1.M13 - value2.M13;
- m.M14 = value1.M14 - value2.M14;
- m.M21 = value1.M21 - value2.M21;
- m.M22 = value1.M22 - value2.M22;
- m.M23 = value1.M23 - value2.M23;
- m.M24 = value1.M24 - value2.M24;
- m.M31 = value1.M31 - value2.M31;
- m.M32 = value1.M32 - value2.M32;
- m.M33 = value1.M33 - value2.M33;
- m.M34 = value1.M34 - value2.M34;
- m.M41 = value1.M41 - value2.M41;
- m.M42 = value1.M42 - value2.M42;
- m.M43 = value1.M43 - value2.M43;
- m.M44 = value1.M44 - value2.M44;
- return m;
- }
- /// <summary>
- /// Multiplies a matrix by another matrix.
- /// </summary>
- /// <param name="value1">The first source matrix.</param>
- /// <param name="value2">The second source matrix.</param>
- /// <returns>The result of the multiplication.</returns>
- public static unsafe Matrix4x4 operator *(Matrix4x4 value1, Matrix4x4 value2)
- {
- if (Sse.IsSupported)
- {
- var row = Sse.LoadVector128(&value1.M11);
- Sse.Store(&value1.M11,
- Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
- Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
- Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
- Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
- // 0x00 is _MM_SHUFFLE(0,0,0,0), 0x55 is _MM_SHUFFLE(1,1,1,1), etc.
- // TODO: Replace with a method once it's added to the API.
- row = Sse.LoadVector128(&value1.M21);
- Sse.Store(&value1.M21,
- Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
- Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
- Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
- Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
- row = Sse.LoadVector128(&value1.M31);
- Sse.Store(&value1.M31,
- Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
- Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
- Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
- Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
- row = Sse.LoadVector128(&value1.M41);
- Sse.Store(&value1.M41,
- Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)),
- Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))),
- Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0xAA), Sse.LoadVector128(&value2.M31)),
- Sse.Multiply(Sse.Shuffle(row, row, 0xFF), Sse.LoadVector128(&value2.M41)))));
- return value1;
- }
- Matrix4x4 m;
- // First row
- m.M11 = value1.M11 * value2.M11 + value1.M12 * value2.M21 + value1.M13 * value2.M31 + value1.M14 * value2.M41;
- m.M12 = value1.M11 * value2.M12 + value1.M12 * value2.M22 + value1.M13 * value2.M32 + value1.M14 * value2.M42;
- m.M13 = value1.M11 * value2.M13 + value1.M12 * value2.M23 + value1.M13 * value2.M33 + value1.M14 * value2.M43;
- m.M14 = value1.M11 * value2.M14 + value1.M12 * value2.M24 + value1.M13 * value2.M34 + value1.M14 * value2.M44;
- // Second row
- m.M21 = value1.M21 * value2.M11 + value1.M22 * value2.M21 + value1.M23 * value2.M31 + value1.M24 * value2.M41;
- m.M22 = value1.M21 * value2.M12 + value1.M22 * value2.M22 + value1.M23 * value2.M32 + value1.M24 * value2.M42;
- m.M23 = value1.M21 * value2.M13 + value1.M22 * value2.M23 + value1.M23 * value2.M33 + value1.M24 * value2.M43;
- m.M24 = value1.M21 * value2.M14 + value1.M22 * value2.M24 + value1.M23 * value2.M34 + value1.M24 * value2.M44;
- // Third row
- m.M31 = value1.M31 * value2.M11 + value1.M32 * value2.M21 + value1.M33 * value2.M31 + value1.M34 * value2.M41;
- m.M32 = value1.M31 * value2.M12 + value1.M32 * value2.M22 + value1.M33 * value2.M32 + value1.M34 * value2.M42;
- m.M33 = value1.M31 * value2.M13 + value1.M32 * value2.M23 + value1.M33 * value2.M33 + value1.M34 * value2.M43;
- m.M34 = value1.M31 * value2.M14 + value1.M32 * value2.M24 + value1.M33 * value2.M34 + value1.M34 * value2.M44;
- // Fourth row
- m.M41 = value1.M41 * value2.M11 + value1.M42 * value2.M21 + value1.M43 * value2.M31 + value1.M44 * value2.M41;
- m.M42 = value1.M41 * value2.M12 + value1.M42 * value2.M22 + value1.M43 * value2.M32 + value1.M44 * value2.M42;
- m.M43 = value1.M41 * value2.M13 + value1.M42 * value2.M23 + value1.M43 * value2.M33 + value1.M44 * value2.M43;
- m.M44 = value1.M41 * value2.M14 + value1.M42 * value2.M24 + value1.M43 * value2.M34 + value1.M44 * value2.M44;
- return m;
- }
- /// <summary>
- /// Multiplies a matrix by a scalar value.
- /// </summary>
- /// <param name="value1">The source matrix.</param>
- /// <param name="value2">The scaling factor.</param>
- /// <returns>The scaled matrix.</returns>
- public static unsafe Matrix4x4 operator *(Matrix4x4 value1, float value2)
- {
- if (Sse.IsSupported)
- {
- Vector128<float> value2Vec = Vector128.Create(value2);
- Sse.Store(&value1.M11, Sse.Multiply(Sse.LoadVector128(&value1.M11), value2Vec));
- Sse.Store(&value1.M21, Sse.Multiply(Sse.LoadVector128(&value1.M21), value2Vec));
- Sse.Store(&value1.M31, Sse.Multiply(Sse.LoadVector128(&value1.M31), value2Vec));
- Sse.Store(&value1.M41, Sse.Multiply(Sse.LoadVector128(&value1.M41), value2Vec));
- return value1;
- }
- Matrix4x4 m;
- m.M11 = value1.M11 * value2;
- m.M12 = value1.M12 * value2;
- m.M13 = value1.M13 * value2;
- m.M14 = value1.M14 * value2;
- m.M21 = value1.M21 * value2;
- m.M22 = value1.M22 * value2;
- m.M23 = value1.M23 * value2;
- m.M24 = value1.M24 * value2;
- m.M31 = value1.M31 * value2;
- m.M32 = value1.M32 * value2;
- m.M33 = value1.M33 * value2;
- m.M34 = value1.M34 * value2;
- m.M41 = value1.M41 * value2;
- m.M42 = value1.M42 * value2;
- m.M43 = value1.M43 * value2;
- m.M44 = value1.M44 * value2;
- return m;
- }
- /// <summary>
- /// Returns a boolean indicating whether the given two matrices are equal.
- /// </summary>
- /// <param name="value1">The first matrix to compare.</param>
- /// <param name="value2">The second matrix to compare.</param>
- /// <returns>True if the given matrices are equal; False otherwise.</returns>
- public static unsafe bool operator ==(Matrix4x4 value1, Matrix4x4 value2)
- {
- if (Sse.IsSupported)
- {
- return
- VectorMath.Equal(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)) &&
- VectorMath.Equal(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)) &&
- VectorMath.Equal(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)) &&
- VectorMath.Equal(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41));
- }
- return (value1.M11 == value2.M11 && value1.M22 == value2.M22 && value1.M33 == value2.M33 && value1.M44 == value2.M44 && // Check diagonal element first for early out.
- value1.M12 == value2.M12 && value1.M13 == value2.M13 && value1.M14 == value2.M14 && value1.M21 == value2.M21 &&
- value1.M23 == value2.M23 && value1.M24 == value2.M24 && value1.M31 == value2.M31 && value1.M32 == value2.M32 &&
- value1.M34 == value2.M34 && value1.M41 == value2.M41 && value1.M42 == value2.M42 && value1.M43 == value2.M43);
- }
- /// <summary>
- /// Returns a boolean indicating whether the given two matrices are not equal.
- /// </summary>
- /// <param name="value1">The first matrix to compare.</param>
- /// <param name="value2">The second matrix to compare.</param>
- /// <returns>True if the given matrices are not equal; False if they are equal.</returns>
- public static unsafe bool operator !=(Matrix4x4 value1, Matrix4x4 value2)
- {
- if (Sse.IsSupported)
- {
- return
- VectorMath.NotEqual(Sse.LoadVector128(&value1.M11), Sse.LoadVector128(&value2.M11)) ||
- VectorMath.NotEqual(Sse.LoadVector128(&value1.M21), Sse.LoadVector128(&value2.M21)) ||
- VectorMath.NotEqual(Sse.LoadVector128(&value1.M31), Sse.LoadVector128(&value2.M31)) ||
- VectorMath.NotEqual(Sse.LoadVector128(&value1.M41), Sse.LoadVector128(&value2.M41));
- }
- return (value1.M11 != value2.M11 || value1.M12 != value2.M12 || value1.M13 != value2.M13 || value1.M14 != value2.M14 ||
- value1.M21 != value2.M21 || value1.M22 != value2.M22 || value1.M23 != value2.M23 || value1.M24 != value2.M24 ||
- value1.M31 != value2.M31 || value1.M32 != value2.M32 || value1.M33 != value2.M33 || value1.M34 != value2.M34 ||
- value1.M41 != value2.M41 || value1.M42 != value2.M42 || value1.M43 != value2.M43 || value1.M44 != value2.M44);
- }
- /// <summary>
- /// Returns a boolean indicating whether this matrix instance is equal to the other given matrix.
- /// </summary>
- /// <param name="other">The matrix to compare this instance to.</param>
- /// <returns>True if the matrices are equal; False otherwise.</returns>
- public readonly bool Equals(Matrix4x4 other) => this == other;
- /// <summary>
- /// Returns a boolean indicating whether the given Object is equal to this matrix instance.
- /// </summary>
- /// <param name="obj">The Object to compare against.</param>
- /// <returns>True if the Object is equal to this matrix; False otherwise.</returns>
- public override readonly bool Equals(object? obj) => (obj is Matrix4x4 other) && (this == other);
- /// <summary>
- /// Returns a String representing this matrix instance.
- /// </summary>
- /// <returns>The string representation.</returns>
- public override readonly string ToString()
- {
- 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}}} }}",
- M11, M12, M13, M14,
- M21, M22, M23, M24,
- M31, M32, M33, M34,
- M41, M42, M43, M44);
- }
- /// <summary>
- /// Returns the hash code for this instance.
- /// </summary>
- /// <returns>The hash code.</returns>
- public override readonly int GetHashCode()
- {
- unchecked
- {
- return M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() +
- M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() +
- M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode() +
- M41.GetHashCode() + M42.GetHashCode() + M43.GetHashCode() + M44.GetHashCode();
- }
- }
- }
- }
|