From 9f7da44355b3e7275901fa66c339fbdd74074313 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 14 Jul 2023 12:30:02 -0700 Subject: [PATCH] Expose the left-handed matrix creation APIs --- .../ref/System.Numerics.Vectors.cs | 9 + .../tests/Matrix4x4Tests.cs | 356 +++++++++++++++--- .../src/System/Numerics/Matrix4x4.Impl.cs | 240 ++++++++++-- .../src/System/Numerics/Matrix4x4.cs | 149 +++++++- 4 files changed, 645 insertions(+), 109 deletions(-) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 958909eda3b527..4222adb42047bc 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -82,11 +82,19 @@ public partial struct Matrix4x4 : System.IEquatable public static System.Numerics.Matrix4x4 CreateFromQuaternion(System.Numerics.Quaternion quaternion) { throw null; } public static System.Numerics.Matrix4x4 CreateFromYawPitchRoll(float yaw, float pitch, float roll) { throw null; } public static System.Numerics.Matrix4x4 CreateLookAt(System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraTarget, System.Numerics.Vector3 cameraUpVector) { throw null; } + public static System.Numerics.Matrix4x4 CreateLookAtLeftHanded(System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraTarget, System.Numerics.Vector3 cameraUpVector) { throw null; } + public static System.Numerics.Matrix4x4 CreateLookTo(System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraDirection, System.Numerics.Vector3 cameraUpVector) { throw null; } + public static System.Numerics.Matrix4x4 CreateLookToLeftHanded(System.Numerics.Vector3 cameraPosition, System.Numerics.Vector3 cameraDirection, System.Numerics.Vector3 cameraUpVector) { throw null; } public static System.Numerics.Matrix4x4 CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) { throw null; } + public static System.Numerics.Matrix4x4 CreateOrthographicLeftHanded(float width, float height, float zNearPlane, float zFarPlane) { throw null; } public static System.Numerics.Matrix4x4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) { throw null; } + public static System.Numerics.Matrix4x4 CreateOrthographicOffCenterLeftHanded(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) { throw null; } public static System.Numerics.Matrix4x4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance) { throw null; } + public static System.Numerics.Matrix4x4 CreatePerspectiveLeftHanded(float width, float height, float nearPlaneDistance, float farPlaneDistance) { throw null; } public static System.Numerics.Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) { throw null; } + public static System.Numerics.Matrix4x4 CreatePerspectiveFieldOfViewLeftHanded(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) { throw null; } public static System.Numerics.Matrix4x4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance) { throw null; } + public static System.Numerics.Matrix4x4 CreatePerspectiveOffCenterLeftHanded(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance) { throw null; } public static System.Numerics.Matrix4x4 CreateReflection(System.Numerics.Plane value) { throw null; } public static System.Numerics.Matrix4x4 CreateRotationX(float radians) { throw null; } public static System.Numerics.Matrix4x4 CreateRotationX(float radians, System.Numerics.Vector3 centerPoint) { throw null; } @@ -104,6 +112,7 @@ public partial struct Matrix4x4 : System.IEquatable public static System.Numerics.Matrix4x4 CreateTranslation(System.Numerics.Vector3 position) { throw null; } public static System.Numerics.Matrix4x4 CreateTranslation(float xPosition, float yPosition, float zPosition) { throw null; } public static System.Numerics.Matrix4x4 CreateViewport(float x, float y, float width, float height, float minDepth, float maxDepth) { throw null; } + public static System.Numerics.Matrix4x4 CreateViewportLeftHanded(float x, float y, float width, float height, float minDepth, float maxDepth) { throw null; } public static System.Numerics.Matrix4x4 CreateWorld(System.Numerics.Vector3 position, System.Numerics.Vector3 forward, System.Numerics.Vector3 up) { throw null; } public static bool Decompose(System.Numerics.Matrix4x4 matrix, out System.Numerics.Vector3 scale, out System.Numerics.Quaternion rotation, out System.Numerics.Vector3 translation) { throw null; } public readonly bool Equals(System.Numerics.Matrix4x4 other) { throw null; } diff --git a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs index f928a7c2d2e6bf..80877852d6378d 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Matrix4x4Tests.cs @@ -859,7 +859,6 @@ public void Matrix4x4CreateRotationZCenterTest() Assert.True(MathHelper.Equal(rotateAroundCenter, rotateAroundCenterExpected)); } - // A test for CrateLookAt (Vector3f, Vector3f, Vector3f) [Fact] public void Matrix4x4CreateLookAtTest() { @@ -868,30 +867,142 @@ public void Matrix4x4CreateLookAtTest() Vector3 cameraUpVector = new Vector3(0.0f, 1.0f, 0.0f); Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 0.979457f; - expected.M12 = -0.0928267762f; - expected.M13 = 0.179017f; + expected.M11 = +0.979457f; + expected.M12 = -0.0928268f; + expected.M13 = +0.179017f; - expected.M21 = 0.0f; - expected.M22 = 0.8877481f; - expected.M23 = 0.460329473f; + expected.M21 = +0.0f; + expected.M22 = +0.887748f; + expected.M23 = +0.460329f; - expected.M31 = -0.201652914f; - expected.M32 = -0.450872928f; - expected.M33 = 0.8695112f; + expected.M31 = -0.201653f; + expected.M32 = -0.450873f; + expected.M33 = +0.869511f; - expected.M41 = -3.74498272f; - expected.M42 = -3.30050683f; - expected.M43 = -37.0820961f; - expected.M44 = 1.0f; + expected.M41 = -3.74498f; + expected.M42 = -3.30051f; + expected.M43 = -37.0821f; + expected.M44 = +1.0f; Matrix4x4 actual = Matrix4x4.CreateLookAt(cameraPosition, cameraTarget, cameraUpVector); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateLookAt did not return the expected value."); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateLookAt)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateLookAtLeftHandedTest() + { + Vector3 cameraPosition = new Vector3(10.0f, 20.0f, 30.0f); + Vector3 cameraTarget = new Vector3(3.0f, 2.0f, -4.0f); + Vector3 cameraUpVector = new Vector3(0.0f, 1.0f, 0.0f); + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = -0.979457f; + expected.M12 = -0.0928268f; + expected.M13 = -0.179017f; + + expected.M21 = +0.0f; + expected.M22 = +0.887748f; + expected.M23 = -0.460329f; + + expected.M31 = +0.201653f; + expected.M32 = -0.450873f; + expected.M33 = -0.869511f; + + expected.M41 = +3.74498f; + expected.M42 = -3.30051f; + expected.M43 = +37.0821f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateLookAtLeftHanded(cameraPosition, cameraTarget, cameraUpVector); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateLookAtLeftHanded)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateLookToTest() + { + Vector3 cameraPosition = new Vector3(10.0f, 20.0f, 30.0f); + Vector3 cameraDirection = new Vector3(-7.0f, -18.0f, -34.0f); + Vector3 cameraUpVector = new Vector3(0.0f, 1.0f, 0.0f); + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +0.979457f; + expected.M12 = -0.0928268f; + expected.M13 = +0.179017f; + + expected.M21 = +0.0f; + expected.M22 = +0.887748f; + expected.M23 = +0.460329f; + + expected.M31 = -0.201653f; + expected.M32 = -0.450873f; + expected.M33 = +0.869511f; + + expected.M41 = -3.74498f; + expected.M42 = -3.30051f; + expected.M43 = -37.0821f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateLookTo(cameraPosition, cameraDirection, cameraUpVector); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateLookTo)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateLookToLeftHandedTest() + { + Vector3 cameraPosition = new Vector3(10.0f, 20.0f, 30.0f); + Vector3 cameraDirection = new Vector3(-7.0f, -18.0f, -34.0f); + Vector3 cameraUpVector = new Vector3(0.0f, 1.0f, 0.0f); + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = -0.979457f; + expected.M12 = -0.0928268f; + expected.M13 = -0.179017f; + + expected.M21 = +0.0f; + expected.M22 = +0.887748f; + expected.M23 = -0.460329f; + + expected.M31 = +0.201653f; + expected.M32 = -0.450873f; + expected.M33 = -0.869511f; + + expected.M41 = +3.74498f; + expected.M42 = -3.30051f; + expected.M43 = +37.0821f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateLookToLeftHanded(cameraPosition, cameraDirection, cameraUpVector); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateLookToLeftHanded)} did not return the expected value."); } - // A test for CreateViewport (x, y, width, height, minDepth, maxDepth) [Fact] public void Matrix4x4CreateViewportTest() + { + float x = 10.0f; + float y = 20.0f; + float width = 80.0f; + float height = 160.0f; + float minDepth = 1.5f; + float maxDepth = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +40.0f; + + expected.M22 = -80.0f; + + expected.M33 = -998.5f; + + expected.M41 = +50.0f; + expected.M42 = +100.0f; + expected.M43 = +1.5f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateViewport(x, y, width, height, minDepth, maxDepth); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateViewport)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateViewportLeftHandedTest() { float x = 10.0f, y = 20.0f; float width = 3.0f, height = 4.0f; @@ -905,8 +1016,8 @@ public void Matrix4x4CreateViewportTest() expected.M42 = y - expected.M22; expected.M43 = minDepth; - Matrix4x4 actual = Matrix4x4.CreateViewport(x, y, width, height, minDepth, maxDepth); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateViewport did not return the expected value."); + Matrix4x4 actual = Matrix4x4.CreateViewportLeftHanded(x, y, width, height, minDepth, maxDepth); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateViewportLeftHanded)} did not return the expected value."); } // A test for CreateWorld (Vector3f, Vector3f, Vector3f) @@ -946,7 +1057,6 @@ public void Matrix4x4CreateWorldTest() Assert.True(Vector3.Dot(Vector3.Normalize(objectForwardDirection), new Vector3(-actual.M31, -actual.M32, -actual.M33)) > 0.999f); } - // A test for CreateOrtho (float, float, float, float) [Fact] public void Matrix4x4CreateOrthoTest() { @@ -956,18 +1066,42 @@ public void Matrix4x4CreateOrthoTest() float zFarPlane = 1000.0f; Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 0.02f; - expected.M22 = 0.01f; - expected.M33 = -0.00100150227f; - expected.M43 = -0.00150225335f; - expected.M44 = 1.0f; + expected.M11 = +0.02f; + + expected.M22 = +0.01f; + + expected.M33 = -0.0010015f; + + expected.M43 = -0.00150225f; + expected.M44 = +1.0f; Matrix4x4 actual; actual = Matrix4x4.CreateOrthographic(width, height, zNearPlane, zFarPlane); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateOrtho did not return the expected value."); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateOrthographic)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateOrthoLeftHandedTest() + { + float width = 100.0f; + float height = 200.0f; + float zNearPlane = 1.5f; + float zFarPlane = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +0.02f; + + expected.M22 = +0.01f; + + expected.M33 = +0.0010015f; + + expected.M43 = -0.00150225f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateOrthographicLeftHanded(width, height, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateOrthographicLeftHanded)} did not return the expected value."); } - // A test for CreateOrthoOffCenter (float, float, float, float, float, float) [Fact] public void Matrix4x4CreateOrthoOffCenterTest() { @@ -979,20 +1113,47 @@ public void Matrix4x4CreateOrthoOffCenterTest() float zFarPlane = 1000.0f; Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 0.025f; - expected.M22 = 0.0125f; - expected.M33 = -0.00100150227f; + expected.M11 = +0.025f; + + expected.M22 = +0.0125f; + + expected.M33 = -0.0010015f; + expected.M41 = -1.25f; expected.M42 = -1.25f; - expected.M43 = -0.00150225335f; - expected.M44 = 1.0f; + expected.M43 = -0.00150225f; + expected.M44 = +1.0f; - Matrix4x4 actual; - actual = Matrix4x4.CreateOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreateOrthoOffCenter did not return the expected value."); + Matrix4x4 actual = Matrix4x4.CreateOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateOrthographicOffCenter)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreateOrthoOffCenterLeftHandedTest() + { + float left = 10.0f; + float right = 90.0f; + float bottom = 20.0f; + float top = 180.0f; + float zNearPlane = 1.5f; + float zFarPlane = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +0.025f; + + expected.M22 = +0.0125f; + + expected.M33 = +0.0010015f; + + expected.M41 = -1.25f; + expected.M42 = -1.25f; + expected.M43 = -0.00150225f; + expected.M44 = +1.0f; + + Matrix4x4 actual = Matrix4x4.CreateOrthographicOffCenterLeftHanded(left, right, bottom, top, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreateOrthographicOffCenterLeftHanded)} did not return the expected value."); } - // A test for CreatePerspective (float, float, float, float) [Fact] public void Matrix4x4CreatePerspectiveTest() { @@ -1002,15 +1163,39 @@ public void Matrix4x4CreatePerspectiveTest() float zFarPlane = 1000.0f; Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 0.03f; - expected.M22 = 0.015f; - expected.M33 = -1.00150228f; + expected.M11 = +0.03f; + + expected.M22 = +0.015f; + + expected.M33 = -1.0015f; expected.M34 = -1.0f; - expected.M43 = -1.50225341f; - Matrix4x4 actual; - actual = Matrix4x4.CreatePerspective(width, height, zNearPlane, zFarPlane); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreatePerspective did not return the expected value."); + expected.M43 = -1.50225f; + + Matrix4x4 actual = Matrix4x4.CreatePerspective(width, height, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspective)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreatePerspectiveLeftHandedTest() + { + float width = 100.0f; + float height = 200.0f; + float zNearPlane = 1.5f; + float zFarPlane = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +0.03f; + + expected.M22 = +0.015f; + + expected.M33 = +1.0015f; + expected.M34 = +1.0f; + + expected.M43 = -1.50225f; + + Matrix4x4 actual = Matrix4x4.CreatePerspectiveLeftHanded(width, height, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspectiveLeftHanded)} did not return the expected value."); } // A test for CreatePerspective (float, float, float, float) @@ -1062,7 +1247,6 @@ public void Matrix4x4CreatePerspectiveTest4() }); } - // A test for CreatePerspectiveFieldOfView (float, float, float, float) [Fact] public void Matrix4x4CreatePerspectiveFieldOfViewTest() { @@ -1072,15 +1256,39 @@ public void Matrix4x4CreatePerspectiveFieldOfViewTest() float zFarPlane = 1000.0f; Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 2.09927845f; - expected.M22 = 3.73205066f; - expected.M33 = -1.00150228f; + expected.M11 = +2.09928f; + + expected.M22 = +3.73205f; + + expected.M33 = -1.0015f; expected.M34 = -1.0f; - expected.M43 = -1.50225341f; - Matrix4x4 actual; - actual = Matrix4x4.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, zNearPlane, zFarPlane); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreatePerspectiveFieldOfView did not return the expected value."); + expected.M43 = -1.50225f; + + Matrix4x4 actual = Matrix4x4.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspectiveFieldOfView)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreatePerspectiveFieldOfViewLeftHandedTest() + { + float fieldOfView = MathHelper.ToRadians(30.0f); + float aspectRatio = 1280.0f / 720.0f; + float zNearPlane = 1.5f; + float zFarPlane = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +2.09928f; + + expected.M22 = +3.73205f; + + expected.M33 = +1.0015f; + expected.M34 = +1.0f; + + expected.M43 = -1.50225f; + + Matrix4x4 actual = Matrix4x4.CreatePerspectiveFieldOfViewLeftHanded(fieldOfView, aspectRatio, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspectiveFieldOfViewLeftHanded)} did not return the expected value."); } // A test for CreatePerspectiveFieldOfView (float, float, float, float) @@ -1138,7 +1346,6 @@ public void Matrix4x4CreatePerspectiveFieldOfViewTest5() }); } - // A test for CreatePerspectiveOffCenter (float, float, float, float, float, float) [Fact] public void Matrix4x4CreatePerspectiveOffCenterTest() { @@ -1150,17 +1357,46 @@ public void Matrix4x4CreatePerspectiveOffCenterTest() float zFarPlane = 1000.0f; Matrix4x4 expected = new Matrix4x4(); - expected.M11 = 0.0375f; - expected.M22 = 0.01875f; - expected.M31 = 1.25f; - expected.M32 = 1.25f; - expected.M33 = -1.00150228f; + expected.M11 = +0.0375f; + + expected.M22 = +0.01875f; + + expected.M31 = +1.25f; + expected.M32 = +1.25f; + expected.M33 = -1.0015f; expected.M34 = -1.0f; - expected.M43 = -1.50225341f; - Matrix4x4 actual; - actual = Matrix4x4.CreatePerspectiveOffCenter(left, right, bottom, top, zNearPlane, zFarPlane); - Assert.True(MathHelper.Equal(expected, actual), "Matrix4x4.CreatePerspectiveOffCenter did not return the expected value."); + expected.M43 = -1.50225f; + + Matrix4x4 actual = Matrix4x4.CreatePerspectiveOffCenter(left, right, bottom, top, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspectiveOffCenter)} did not return the expected value."); + } + + [Fact] + public void Matrix4x4CreatePerspectiveOffCenterLeftHandedTest() + { + float left = 10.0f; + float right = 90.0f; + float bottom = 20.0f; + float top = 180.0f; + float zNearPlane = 1.5f; + float zFarPlane = 1000.0f; + + Matrix4x4 expected = new Matrix4x4(); + expected.M11 = +0.0375f; + + expected.M22 = +0.01875f; + + expected.M31 = -1.25f; + expected.M32 = -1.25f; + expected.M33 = +1.0015f; + expected.M34 = +1.0f; + + expected.M43 = -1.50225f; + + + Matrix4x4 actual = Matrix4x4.CreatePerspectiveOffCenterLeftHanded(left, right, bottom, top, zNearPlane, zFarPlane); + Assert.True(MathHelper.Equal(expected, actual), $"{nameof(Matrix4x4)}.{nameof(Matrix4x4.CreatePerspectiveOffCenterLeftHanded)} did not return the expected value."); } // A test for CreatePerspectiveOffCenter (float, float, float, float, float, float) diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs index 776913b5061269..492eda1b452d0d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.Impl.cs @@ -424,11 +424,12 @@ public static Impl CreateFromYawPitchRoll(float yaw, float pitch, float roll) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Impl CreateLookAt(in Vector3 cameraPosition, in Vector3 cameraTarget, in Vector3 cameraUpVector) + public static Impl CreateLookTo(in Vector3 cameraPosition, in Vector3 cameraDirection, in Vector3 cameraUpVector) { - Vector3 axisZ = Vector3.Normalize(cameraPosition - cameraTarget); + Vector3 axisZ = Vector3.Normalize(-cameraDirection); Vector3 axisX = Vector3.Normalize(Vector3.Cross(cameraUpVector, axisZ)); Vector3 axisY = Vector3.Cross(axisZ, axisX); + Vector3 negativeCameraPosition = -cameraPosition; Impl result; @@ -451,9 +452,47 @@ public static Impl CreateLookAt(in Vector3 cameraPosition, in Vector3 cameraTarg 0 ); result.W = new Vector4( - -Vector3.Dot(axisX, cameraPosition), - -Vector3.Dot(axisY, cameraPosition), - -Vector3.Dot(axisZ, cameraPosition), + Vector3.Dot(axisX, negativeCameraPosition), + Vector3.Dot(axisY, negativeCameraPosition), + Vector3.Dot(axisZ, negativeCameraPosition), + 1 + ); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreateLookToLeftHanded(in Vector3 cameraPosition, in Vector3 cameraDirection, in Vector3 cameraUpVector) + { + Vector3 axisZ = Vector3.Normalize(cameraDirection); + Vector3 axisX = Vector3.Normalize(Vector3.Cross(cameraUpVector, axisZ)); + Vector3 axisY = Vector3.Cross(axisZ, axisX); + Vector3 negativeCameraPosition = -cameraPosition; + + Impl result; + + result.X = new Vector4( + axisX.X, + axisY.X, + axisZ.X, + 0 + ); + result.Y = new Vector4( + axisX.Y, + axisY.Y, + axisZ.Y, + 0 + ); + result.Z = new Vector4( + axisX.Z, + axisY.Z, + axisZ.Z, + 0 + ); + result.W = new Vector4( + Vector3.Dot(axisX, negativeCameraPosition), + Vector3.Dot(axisY, negativeCameraPosition), + Vector3.Dot(axisZ, negativeCameraPosition), 1 ); @@ -463,12 +502,29 @@ public static Impl CreateLookAt(in Vector3 cameraPosition, in Vector3 cameraTarg [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Impl CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) { + float range = 1.0f / (zNearPlane - zFarPlane); + Impl result; result.X = new Vector4(2.0f / width, 0, 0, 0); result.Y = new Vector4(0, 2.0f / height, 0, 0); - result.Z = new Vector4(0, 0, 1.0f / (zNearPlane - zFarPlane), 0); - result.W = new Vector4(0, 0, zNearPlane / (zNearPlane - zFarPlane), 1); + result.Z = new Vector4(0, 0, range, 0); + result.W = new Vector4(0, 0, range * zNearPlane, 1); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreateOrthographicLeftHanded(float width, float height, float zNearPlane, float zFarPlane) + { + float range = 1.0f / (zFarPlane - zNearPlane); + + Impl result; + + result.X = new Vector4(2.0f / width, 0, 0, 0); + result.Y = new Vector4(0, 2.0f / height, 0, 0); + result.Z = new Vector4(0, 0, range, 0); + result.W = new Vector4(0, 0, -range * zNearPlane, 1); return result; } @@ -476,15 +532,41 @@ public static Impl CreateOrthographic(float width, float height, float zNearPlan [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Impl CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) { + float reciprocalWidth = 1.0f / (right - left); + float reciprocalHeight = 1.0f / (top - bottom); + float range = 1.0f / (zNearPlane - zFarPlane); + Impl result; - result.X = new Vector4(2.0f / (right - left), 0, 0, 0); - result.Y = new Vector4(0, 2.0f / (top - bottom), 0, 0); - result.Z = new Vector4(0, 0, 1.0f / (zNearPlane - zFarPlane), 0); + result.X = new Vector4(reciprocalWidth + reciprocalWidth, 0, 0, 0); + result.Y = new Vector4(0, reciprocalHeight + reciprocalHeight, 0, 0); + result.Z = new Vector4(0, 0, range, 0); result.W = new Vector4( - (left + right) / (left - right), - (top + bottom) / (bottom - top), - zNearPlane / (zNearPlane - zFarPlane), + -(left + right) * reciprocalWidth, + -(top + bottom) * reciprocalHeight, + range * zNearPlane, + 1 + ); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreateOrthographicOffCenterLeftHanded(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) + { + float reciprocalWidth = 1.0f / (right - left); + float reciprocalHeight = 1.0f / (top - bottom); + float range = 1.0f / (zFarPlane - zNearPlane); + + Impl result; + + result.X = new Vector4(reciprocalWidth + reciprocalWidth, 0, 0, 0); + result.Y = new Vector4(0, reciprocalHeight + reciprocalHeight, 0, 0); + result.Z = new Vector4(0, 0, range, 0); + result.W = new Vector4( + -(left + right) * reciprocalWidth, + -(top + bottom) * reciprocalHeight, + -range * zNearPlane, 1 ); @@ -498,14 +580,35 @@ public static Impl CreatePerspective(float width, float height, float nearPlaneD ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); - float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float dblNearPlaneDistance = nearPlaneDistance + nearPlaneDistance; + float range = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); Impl result; - result.X = new Vector4(2.0f * nearPlaneDistance / width, 0, 0, 0); - result.Y = new Vector4(0, 2.0f * nearPlaneDistance / height, 0, 0); - result.Z = new Vector4(0, 0, negFarRange, -1.0f); - result.W = new Vector4(0, 0, nearPlaneDistance * negFarRange, 0); + result.X = new Vector4(dblNearPlaneDistance / width, 0, 0, 0); + result.Y = new Vector4(0, dblNearPlaneDistance / height, 0, 0); + result.Z = new Vector4(0, 0, range, -1.0f); + result.W = new Vector4(0, 0, range * nearPlaneDistance, 0); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreatePerspectiveLeftHanded(float width, float height, float nearPlaneDistance, float farPlaneDistance) + { + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(nearPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); + + float dblNearPlaneDistance = nearPlaneDistance + nearPlaneDistance; + float range = float.IsPositiveInfinity(farPlaneDistance) ? 1.0f : farPlaneDistance / (farPlaneDistance - nearPlaneDistance); + + Impl result; + + result.X = new Vector4(dblNearPlaneDistance / width, 0, 0, 0); + result.Y = new Vector4(0, dblNearPlaneDistance / height, 0, 0); + result.Z = new Vector4(0, 0, range, 1.0f); + result.W = new Vector4(0, 0, -range * nearPlaneDistance, 0); return result; } @@ -514,22 +617,46 @@ public static Impl CreatePerspective(float width, float height, float nearPlaneD public static Impl CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) { ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(fieldOfView, 0.0f); - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fieldOfView, MathF.PI); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fieldOfView, float.Pi); ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(nearPlaneDistance, 0.0f); ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); - float scaleY = 1.0f / MathF.Tan(fieldOfView * 0.5f); - float scaleX = scaleY / aspectRatio; - float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float height = 1.0f / MathF.Tan(fieldOfView * 0.5f); + float width = height / aspectRatio; + float range = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); Impl result; - result.X = new Vector4(scaleX, 0, 0, 0); - result.Y = new Vector4(0, scaleY, 0, 0); - result.Z = new Vector4(0, 0, negFarRange, -1.0f); - result.W = new Vector4(0, 0, nearPlaneDistance * negFarRange, 0); + result.X = new Vector4(width, 0, 0, 0); + result.Y = new Vector4(0, height, 0, 0); + result.Z = new Vector4(0, 0, range, -1.0f); + result.W = new Vector4(0, 0, range * nearPlaneDistance, 0); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreatePerspectiveFieldOfViewLeftHanded(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) + { + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(fieldOfView, 0.0f); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fieldOfView, float.Pi); + + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(nearPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); + + float height = 1.0f / MathF.Tan(fieldOfView * 0.5f); + float width = height / aspectRatio; + float range = float.IsPositiveInfinity(farPlaneDistance) ? 1.0f : farPlaneDistance / (farPlaneDistance - nearPlaneDistance); + + Impl result; + + result.X = new Vector4(width, 0, 0, 0); + result.Y = new Vector4(0, height, 0, 0); + result.Z = new Vector4(0, 0, range, 1.0f); + result.W = new Vector4(0, 0, -range * nearPlaneDistance, 0); return result; } @@ -541,19 +668,49 @@ public static Impl CreatePerspectiveOffCenter(float left, float right, float bot ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); - float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float dblNearPlaneDistance = nearPlaneDistance + nearPlaneDistance; + float reciprocalWidth = 1.0f / (right - left); + float reciprocalHeight = 1.0f / (top - bottom); + float range = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); Impl result; - result.X = new Vector4(2.0f * nearPlaneDistance / (right - left), 0, 0, 0); - result.Y = new Vector4(0, 2.0f * nearPlaneDistance / (top - bottom), 0, 0); + result.X = new Vector4(dblNearPlaneDistance * reciprocalWidth, 0, 0, 0); + result.Y = new Vector4(0, dblNearPlaneDistance * reciprocalHeight, 0, 0); result.Z = new Vector4( - (left + right) / (right - left), - (top + bottom) / (top - bottom), - negFarRange, + (left + right) * reciprocalWidth, + (top + bottom) * reciprocalHeight, + range, -1.0f ); - result.W = new Vector4(0, 0, nearPlaneDistance * negFarRange, 0); + result.W = new Vector4(0, 0, range * nearPlaneDistance, 0); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreatePerspectiveOffCenterLeftHanded(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance) + { + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(nearPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(farPlaneDistance, 0.0f); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(nearPlaneDistance, farPlaneDistance); + + float dblNearPlaneDistance = nearPlaneDistance + nearPlaneDistance; + float reciprocalWidth = 1.0f / (right - left); + float reciprocalHeight = 1.0f / (top - bottom); + float range = float.IsPositiveInfinity(farPlaneDistance) ? 1.0f : farPlaneDistance / (farPlaneDistance - nearPlaneDistance); + + Impl result; + + result.X = new Vector4(dblNearPlaneDistance * reciprocalWidth, 0, 0, 0); + result.Y = new Vector4(0, dblNearPlaneDistance * reciprocalHeight, 0, 0); + result.Z = new Vector4( + -(left + right) * reciprocalWidth, + -(top + bottom) * reciprocalHeight, + range, + 1.0f + ); + result.W = new Vector4(0, 0, -range * nearPlaneDistance, 0); return result; } @@ -842,6 +999,23 @@ public static Impl CreateViewport(float x, float y, float width, float height, f result.W = new Vector4(width, height, 0f, 0f); result.W *= new Vector4(0.5f, 0.5f, 0f, 0f); + result.X = new Vector4(result.W.X, 0f, 0f, 0f); + result.Y = new Vector4(0f, -result.W.Y, 0f, 0f); + result.Z = new Vector4(0f, 0f, minDepth - maxDepth, 0f); + result.W += new Vector4(x, y, minDepth, 1f); + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Impl CreateViewportLeftHanded(float x, float y, float width, float height, float minDepth, float maxDepth) + { + Impl result; + + // 4x SIMD fields to get a lot better codegen + result.W = new Vector4(width, height, 0f, 0f); + result.W *= new Vector4(0.5f, 0.5f, 0f, 0f); + result.X = new Vector4(result.W.X, 0f, 0f, 0f); result.Y = new Vector4(0f, -result.W.Y, 0f, 0f); result.Z = new Vector4(0f, 0f, maxDepth - minDepth, 0f); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs index b8e6580d518c57..3834877ae44a85 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Matrix4x4.cs @@ -264,40 +264,92 @@ public static Matrix4x4 CreateFromQuaternion(Quaternion quaternion) public static Matrix4x4 CreateFromYawPitchRoll(float yaw, float pitch, float roll) => Impl.CreateFromYawPitchRoll(yaw, pitch, roll).AsM4x4(); - /// Creates a view matrix. + /// Creates a right-handed view matrix. /// The position of the camera. /// The target towards which the camera is pointing. /// The direction that is "up" from the camera's point of view. - /// The view matrix. + /// The right-handed view matrix. public static Matrix4x4 CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) - => Impl.CreateLookAt(in cameraPosition, in cameraTarget, in cameraUpVector).AsM4x4(); + { + Vector3 cameraDirection = cameraTarget - cameraPosition; + return Impl.CreateLookTo(in cameraPosition, in cameraDirection, in cameraUpVector).AsM4x4(); + } + + /// Creates a left-handed view matrix. + /// The position of the camera. + /// The target towards which the camera is pointing. + /// The direction that is "up" from the camera's point of view. + /// The left-handed view matrix. + public static Matrix4x4 CreateLookAtLeftHanded(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector) + { + Vector3 cameraDirection = cameraTarget - cameraPosition; + return Impl.CreateLookToLeftHanded(in cameraPosition, in cameraDirection, in cameraUpVector).AsM4x4(); + } + + /// Creates a right-handed view matrix. + /// The position of the camera. + /// The direction in which the camera is pointing. + /// The direction that is "up" from the camera's point of view. + /// The right-handed view matrix. + public static Matrix4x4 CreateLookTo(Vector3 cameraPosition, Vector3 cameraDirection, Vector3 cameraUpVector) + => Impl.CreateLookTo(in cameraPosition, in cameraDirection, in cameraUpVector).AsM4x4(); + + /// Creates a left-handed view matrix. + /// The position of the camera. + /// The direction in which the camera is pointing. + /// The direction that is "up" from the camera's point of view. + /// The left-handed view matrix. + public static Matrix4x4 CreateLookToLeftHanded(Vector3 cameraPosition, Vector3 cameraDirection, Vector3 cameraUpVector) + { + return Impl.CreateLookToLeftHanded(in cameraPosition, in cameraDirection, in cameraUpVector).AsM4x4(); + } - /// Creates an orthographic perspective matrix from the given view volume dimensions. + /// Creates a right-handed orthographic perspective matrix from the given view volume dimensions. /// The width of the view volume. /// The height of the view volume. /// The minimum Z-value of the view volume. /// The maximum Z-value of the view volume. - /// The orthographic projection matrix. + /// The right-handed orthographic projection matrix. public static Matrix4x4 CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane) => Impl.CreateOrthographic(width, height, zNearPlane, zFarPlane).AsM4x4(); - /// Creates a customized orthographic projection matrix. + /// Creates a left-handed orthographic perspective matrix from the given view volume dimensions. + /// The width of the view volume. + /// The height of the view volume. + /// The minimum Z-value of the view volume. + /// The maximum Z-value of the view volume. + /// The left-handed orthographic projection matrix. + public static Matrix4x4 CreateOrthographicLeftHanded(float width, float height, float zNearPlane, float zFarPlane) + => Impl.CreateOrthographicLeftHanded(width, height, zNearPlane, zFarPlane).AsM4x4(); + + /// Creates a right-handed customized orthographic projection matrix. /// The minimum X-value of the view volume. /// The maximum X-value of the view volume. /// The minimum Y-value of the view volume. /// The maximum Y-value of the view volume. /// The minimum Z-value of the view volume. /// The maximum Z-value of the view volume. - /// The orthographic projection matrix. + /// The right-handed orthographic projection matrix. public static Matrix4x4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) => Impl.CreateOrthographicOffCenter(left, right, bottom, top, zNearPlane, zFarPlane).AsM4x4(); - /// Creates a perspective projection matrix from the given view volume dimensions. + /// Creates a left-handed customized orthographic projection matrix. + /// The minimum X-value of the view volume. + /// The maximum X-value of the view volume. + /// The minimum Y-value of the view volume. + /// The maximum Y-value of the view volume. + /// The minimum Z-value of the view volume. + /// The maximum Z-value of the view volume. + /// The left-handed orthographic projection matrix. + public static Matrix4x4 CreateOrthographicOffCenterLeftHanded(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane) + => Impl.CreateOrthographicOffCenterLeftHanded(left, right, bottom, top, zNearPlane, zFarPlane).AsM4x4(); + + /// Creates a right-handed perspective projection matrix from the given view volume dimensions. /// The width of the view volume at the near view plane. /// The height of the view volume at the near view plane. /// The distance to the near view plane. /// The distance to the far view plane. - /// The perspective projection matrix. + /// The right-handed perspective projection matrix. /// is less than or equal to zero. /// -or- /// is less than or equal to zero. @@ -306,12 +358,26 @@ public static Matrix4x4 CreateOrthographicOffCenter(float left, float right, flo public static Matrix4x4 CreatePerspective(float width, float height, float nearPlaneDistance, float farPlaneDistance) => Impl.CreatePerspective(width, height, nearPlaneDistance, farPlaneDistance).AsM4x4(); - /// Creates a perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances. + /// Creates a left-handed perspective projection matrix from the given view volume dimensions. + /// The width of the view volume at the near view plane. + /// The height of the view volume at the near view plane. + /// The distance to the near view plane. + /// The distance to the far view plane. + /// The left-handed perspective projection matrix. + /// is less than or equal to zero. + /// -or- + /// is less than or equal to zero. + /// -or- + /// is greater than or equal to . + public static Matrix4x4 CreatePerspectiveLeftHanded(float width, float height, float nearPlaneDistance, float farPlaneDistance) + => Impl.CreatePerspectiveLeftHanded(width, height, nearPlaneDistance, farPlaneDistance).AsM4x4(); + + /// Creates a right-handed perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances. /// The field of view in the y direction, in radians. /// The aspect ratio, defined as view space width divided by height. /// The distance to the near view plane. /// The distance to the far view plane. - /// The perspective projection matrix. + /// The right-handed perspective projection matrix. /// is less than or equal to zero. /// -or- /// is greater than or equal to . @@ -323,14 +389,31 @@ public static Matrix4x4 CreatePerspective(float width, float height, float nearP public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) => Impl.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance).AsM4x4(); - /// Creates a customized perspective projection matrix. + /// Creates a left-handed perspective projection matrix based on a field of view, aspect ratio, and near and far view plane distances. + /// The field of view in the y direction, in radians. + /// The aspect ratio, defined as view space width divided by height. + /// The distance to the near view plane. + /// The distance to the far view plane. + /// The left-handed perspective projection matrix. + /// is less than or equal to zero. + /// -or- + /// is greater than or equal to . + /// is less than or equal to zero. + /// -or- + /// is less than or equal to zero. + /// -or- + /// is greater than or equal to . + public static Matrix4x4 CreatePerspectiveFieldOfViewLeftHanded(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance) + => Impl.CreatePerspectiveFieldOfViewLeftHanded(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance).AsM4x4(); + + /// Creates a right-handed customized perspective projection matrix. /// The minimum x-value of the view volume at the near view plane. /// The maximum x-value of the view volume at the near view plane. /// The minimum y-value of the view volume at the near view plane. /// The maximum y-value of the view volume at the near view plane. /// The distance to the near view plane. /// The distance to the far view plane. - /// The perspective projection matrix. + /// The right-handed perspective projection matrix. /// is less than or equal to zero. /// -or- /// is less than or equal to zero. @@ -339,6 +422,22 @@ public static Matrix4x4 CreatePerspectiveFieldOfView(float fieldOfView, float as public static Matrix4x4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance) => Impl.CreatePerspectiveOffCenter(left, right, bottom, top, nearPlaneDistance, farPlaneDistance).AsM4x4(); + /// Creates a left-handed customized perspective projection matrix. + /// The minimum x-value of the view volume at the near view plane. + /// The maximum x-value of the view volume at the near view plane. + /// The minimum y-value of the view volume at the near view plane. + /// The maximum y-value of the view volume at the near view plane. + /// The distance to the near view plane. + /// The distance to the far view plane. + /// The left-handed perspective projection matrix. + /// is less than or equal to zero. + /// -or- + /// is less than or equal to zero. + /// -or- + /// is greater than or equal to . + public static Matrix4x4 CreatePerspectiveOffCenterLeftHanded(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance) + => Impl.CreatePerspectiveOffCenterLeftHanded(left, right, bottom, top, nearPlaneDistance, farPlaneDistance).AsM4x4(); + /// Creates a matrix that reflects the coordinate system about a specified plane. /// The plane about which to create a reflection. /// A new matrix expressing the reflection. @@ -448,24 +547,42 @@ public static Matrix4x4 CreateTranslation(Vector3 position) public static Matrix4x4 CreateTranslation(float xPosition, float yPosition, float zPosition) => Impl.CreateTranslation(xPosition, yPosition, zPosition).AsM4x4(); - /// Creates a viewport matrix from the specified parameters. + /// Creates a right-handed viewport matrix from the specified parameters. /// X coordinate of the viewport upper left corner. /// Y coordinate of the viewport upper left corner. /// Viewport width. /// Viewport height. /// Viewport minimum depth. /// Viewport maximum depth. - /// The viewport matrix. + /// The right-handed viewport matrix. /// /// Viewport matrix /// | width / 2 | 0 | 0 | 0 | /// | 0 | -height / 2 | 0 | 0 | - /// | 0 | 0 | maxDepth - minDepth | 0 | + /// | 0 | 0 | minDepth - maxDepth | 0 | /// | x + width / 2 | y + height / 2 | minDepth | 1 | /// public static Matrix4x4 CreateViewport(float x, float y, float width, float height, float minDepth, float maxDepth) => Impl.CreateViewport(x, y, width, height, minDepth, maxDepth).AsM4x4(); + /// Creates a left-handed viewport matrix from the specified parameters. + /// X coordinate of the viewport upper left corner. + /// Y coordinate of the viewport upper left corner. + /// Viewport width. + /// Viewport height. + /// Viewport minimum depth. + /// Viewport maximum depth. + /// The left-handed viewport matrix. + /// + /// Viewport matrix + /// | width / 2 | 0 | 0 | 0 | + /// | 0 | -height / 2 | 0 | 0 | + /// | 0 | 0 | maxDepth - minDepth | 0 | + /// | x + width / 2 | y + height / 2 | minDepth | 1 | + /// + public static Matrix4x4 CreateViewportLeftHanded(float x, float y, float width, float height, float minDepth, float maxDepth) + => Impl.CreateViewportLeftHanded(x, y, width, height, minDepth, maxDepth).AsM4x4(); + /// Creates a world matrix with the specified parameters. /// The position of the object. /// The forward direction of the object.