Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate stride math for numerics alternatives #2579

Draft
wants to merge 17 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions sources/core/Stride.Core.Mathematics.Tests/TestMatrix.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using Avalonia.Media;
using Xunit;

namespace Stride.Core.Mathematics.Tests
Expand Down Expand Up @@ -75,5 +76,83 @@ public void TestDecomposeXYZFromMatricesXYZ(float yawDegrees, float pitchDegrees
var expectedQuat = Quaternion.RotationX(pitchRadians) * Quaternion.RotationY(yawRadians) * Quaternion.RotationZ(rollRadians);
Assert.True(expectedQuat == decompedQuat || expectedQuat == -decompedQuat, $"Quat not equals: Expected: {expectedQuat} - Actual: {decompedQuat}");
}

[Fact]
public void TestNumericConversion()
{
System.Numerics.Matrix4x4 matrix = new System.Numerics.Matrix4x4(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);

Matrix baseStrideMatrix = new Matrix(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);

Matrix strideMatrix = matrix;
Assert.Equal(baseStrideMatrix, strideMatrix);
}

[Fact]
public void TestStrideConversion()
{
Matrix matrix = new(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);

System.Numerics.Matrix4x4 baseNumericseMatrix = new(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);

System.Numerics.Matrix4x4 numericsMatrix = matrix;
Assert.Equal(baseNumericseMatrix, numericsMatrix);
}

[Fact]
public void TestMathUtil_Orthogonalize()
{
var matrix = new Matrix(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);

Matrix result = MathUtil.Orthogonalize(matrix);
Matrix expected = Matrix.Orthogonalize(matrix);
Assert.Equal(expected, result);
}

[Fact]
public void TestMathUtil_Invert()
{
var matrix = new Matrix(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
Matrix result = MathUtil.Invert(matrix);
Matrix expected = Matrix.Invert(matrix);
Assert.Equal(expected, result);
}

[Fact]
public void TestMathUtil_Orthonomolize()
{
var matrix = new Matrix(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
Matrix result = MathUtil.Orthonormalize(matrix);
Matrix expected = Matrix.Orthonormalize(matrix);
Assert.Equal(expected, result);
}
}
}
13 changes: 12 additions & 1 deletion sources/core/Stride.Core.Mathematics/Double2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Expand Down Expand Up @@ -141,6 +140,18 @@ public double this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static implicit operator Double2(System.Numerics.Vector2 v) => new(v.X,v.Y);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a space here?


/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector2(Double2 v) => new((float)v.X, (float)v.Y);

/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
13 changes: 13 additions & 0 deletions sources/core/Stride.Core.Mathematics/Double3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,19 @@ public double this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static implicit operator Double3(System.Numerics.Vector3 v) => new(v.X, v.Y, v.Z);

/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector3(Double3 v) => new((float)v.X, (float)v.Y, (float)v.Z);


/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions sources/core/Stride.Core.Mathematics/Double4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,18 @@ public double this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static implicit operator Double4(System.Numerics.Vector4 v) => new(v.X, v.Y, v.Z, v.W);

/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector4(Double4 v) => new((float)v.X, (float)v.Y,(float)v.Z,(float)v.W);

/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
3 changes: 0 additions & 3 deletions sources/core/Stride.Core.Mathematics/Half.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.InteropServices;
using Stride.Core.Serialization;

namespace Stride.Core.Mathematics
{
Expand Down
12 changes: 12 additions & 0 deletions sources/core/Stride.Core.Mathematics/Int2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ public int this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator Int2(System.Numerics.Vector2 v) => new((int)v.X,(int)v.Y);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.


/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector2(Int2 v) => new(v.X, v.Y);

/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions sources/core/Stride.Core.Mathematics/Int3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,18 @@ public int this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator Int3(System.Numerics.Vector3 v) => new((int)v.X, (int)v.Y, (int)v.Z);

/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector3(Int3 v) => new(v.X, v.Y, v.Z);

/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions sources/core/Stride.Core.Mathematics/Int4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ public int this[int index]
}
}

/// <summary>
/// Casts from System.Numerics to Stride.Maths vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator Int4(System.Numerics.Vector4 v) => new((int)v.X, (int)v.Y, (int)v.Z, (int)v.W);

/// <summary>
/// Casts from Stride.Maths to System.Numerics vectors
/// </summary>
/// <param name="v">Value to cast</param>
public static explicit operator System.Numerics.Vector4(Int4 v) => new(v.X, v.Y, v.Z, v.W);

/// <summary>
/// Calculates the length of the vector.
/// </summary>
Expand Down
97 changes: 97 additions & 0 deletions sources/core/Stride.Core.Mathematics/MathUtil.Matrix.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using System.Numerics;
using System.Transactions;

namespace Stride.Core.Mathematics;
public static partial class MathUtil
{

public static Matrix4x4 Orthonormalize(Matrix4x4 matrix)
{
var result = matrix;

var row1 = new System.Numerics.Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit unfortunate that Matrix4x4 can't be read as 4 vectors, but it should be and you can do it from M11, M21, etc. There are several ways of doing that, e.g.:

var rows = MemoryMarshal.Cast<Matrix4x4, Vector4>(MemoryMarshal.CreateSpan(ref m, 1));
var row4 = rows[3]; // get the bounds check out of the way asap
var row3 = rows[2];
...

Or, even faster:

var row1 = Unsafe.As<float, Vector4>(ref m.M11);
var row2 = Unsafe.As<float, Vector4>(ref m.M21);
var row3 = Unsafe.As<float, Vector4>(ref m.M31);
var row4 = Unsafe.As<float, Vector4>(ref m.M41);

Could also use Bitcast, but since it is by value and the sizes don't match, I'd have to try. And either way not entirely sure the above code will be optimal.

Below you should do the reverse, since certainly 16 float assignments is a bad idea that you'd want to prevent everywhere you see them.

var row2 = new System.Numerics.Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24);
var row3 = new System.Numerics.Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34);
var row4 = new System.Numerics.Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44);

row1 = System.Numerics.Vector4.Normalize(row1);

row2 = row2 - System.Numerics.Vector4.Dot(row1, row2) * row1;
row2 = System.Numerics.Vector4.Normalize(row2);

row3 = row3 - System.Numerics.Vector4.Dot(row1, row3) * row1;
row3 = row3 - System.Numerics.Vector4.Dot(row2, row3) * row2;
row3 = System.Numerics.Vector4.Normalize(row3);

row4 = row4 - System.Numerics.Vector4.Dot(row1, row4) * row1;
row4 = row4 - System.Numerics.Vector4.Dot(row2, row4) * row2;
row4 = row4 - System.Numerics.Vector4.Dot(row3, row4) * row3;
row4 = System.Numerics.Vector4.Normalize(row4);

result = new Matrix4x4();
result.M11 = row1.X;
result.M12 = row1.Y;
result.M13 = row1.Z;
result.M14 = row1.W;
result.M21 = row2.X;
result.M22 = row2.Y;
result.M23 = row2.Z;
result.M24 = row2.W;
result.M31 = row3.X;
result.M32 = row3.Y;
result.M33 = row3.Z;
result.M34 = row3.W;
result.M41 = row4.X;
result.M42 = row4.Y;
result.M43 = row4.Z;
result.M44 = row4.W;

return result;
}

public static Matrix4x4 Orthogonalize(Matrix4x4 matrix)
{
var result = matrix;

var row1 = new System.Numerics.Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14);
var row2 = new System.Numerics.Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24);
var row3 = new System.Numerics.Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34);
var row4 = new System.Numerics.Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44);

row2 = row2 - (System.Numerics.Vector4.Dot(row1, row2) / System.Numerics.Vector4.Dot(row1, row1)) * row1;

row3 = row3 - (System.Numerics.Vector4.Dot(row1, row3) / System.Numerics.Vector4.Dot(row1, row1)) * row1;
row3 = row3 - (System.Numerics.Vector4.Dot(row2, row3) / System.Numerics.Vector4.Dot(row2, row2)) * row2;

row4 = row4 - (System.Numerics.Vector4.Dot(row1, row4) / System.Numerics.Vector4.Dot(row1, row1)) * row1;
row4 = row4 - (System.Numerics.Vector4.Dot(row2, row4) / System.Numerics.Vector4.Dot(row2, row2)) * row2;
row4 = row4 - (System.Numerics.Vector4.Dot(row3, row4) / System.Numerics.Vector4.Dot(row3, row3)) * row3;

result.M21 = row2.X;
result.M22 = row2.Y;
result.M23 = row2.Z;
result.M24 = row2.W;
result.M31 = row3.X;
result.M32 = row3.Y;
result.M33 = row3.Z;
result.M34 = row3.W;
result.M41 = row4.X;
result.M42 = row4.Y;
result.M43 = row4.Z;
result.M44 = row4.W;

return result;
}

public static Matrix4x4 Invert(Matrix4x4 matrix)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally speaking, not sure whether it is a good idea to add public API for System.Numerics to a type that may get scrapped when all deprecations and substitutions are done. Basically what you're doing by having these public is hinting at future work to get Stride.Core.Mathematics surface area on par between System.Numerics types and Stride types. Those two things are sort of in competition with each other.

Before that decision is made, I would keep these internal.

{
Matrix4x4.Invert(matrix, out var result);
return result;
}

public static void Decompose(Matrix4x4 matrix, out System.Numerics.Vector3 scale, out System.Numerics.Quaternion rotation, out System.Numerics.Vector3 translation)
{
Matrix4x4.Decompose(matrix, out scale, out rotation, out translation);
}

}
2 changes: 1 addition & 1 deletion sources/core/Stride.Core.Mathematics/MathUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace Stride.Core.Mathematics
/// <summary>
/// Common utility methods for math operations.
/// </summary>
public static class MathUtil
public static partial class MathUtil
{
/// <summary>
/// The value for which all absolute numbers smaller than are considered equal to zero.
Expand Down
Loading