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

[release/6.0.4xx] [SceneKit] Fix SCNMatrix4 in .NET. Fixes #15094. #15296

Merged
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
401 changes: 259 additions & 142 deletions src/SceneKit/SCNMatrix4_dotnet.cs

Large diffs are not rendered by default.

133 changes: 105 additions & 28 deletions src/SceneKit/SCNVector3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -740,29 +740,53 @@ public static void BaryCentric(ref SCNVector3 a, ref SCNVector3 b, ref SCNVector

#region Transform

#if NET
/// <summary>Transform a direction vector by the given Matrix
/// Assumes the matrix has a right-most column of (0,0,0,1), that is the translation part is ignored.
/// </summary>
/// <param name="vec">The column vector to transform</param>
#else
/// <summary>Transform a direction vector by the given Matrix
/// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored.
/// </summary>
/// <param name="vec">The vector to transform</param>
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <returns>The transformed vector</returns>
public static SCNVector3 TransformVector(SCNVector3 vec, SCNMatrix4 mat)
{
SCNVector3 v;
v.X = SCNVector3.Dot(vec, new SCNVector3(mat.Column0));
v.Y = SCNVector3.Dot(vec, new SCNVector3(mat.Column1));
v.Z = SCNVector3.Dot(vec, new SCNVector3(mat.Column2));
TransformVector (ref vec, ref mat, out var v);
return v;
}

#if NET
/// <summary>Transform a direction vector by the given Matrix
/// Assumes the matrix has a right-most column of (0,0,0,1), that is the translation part is ignored.
/// </summary>
/// <param name="vec">The column vector to transform</param>
#else
/// <summary>Transform a direction vector by the given Matrix
/// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored.
/// </summary>
/// <param name="vec">The vector to transform</param>
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <param name="result">The transformed vector</param>
public static void TransformVector(ref SCNVector3 vec, ref SCNMatrix4 mat, out SCNVector3 result)
{
#if NET
result.X = vec.X * mat.Row0.X +
vec.Y * mat.Row0.Y +
vec.Z * mat.Row0.Z;

result.Y = vec.X * mat.Row1.X +
vec.Y * mat.Row1.Y +
vec.Z * mat.Row1.Z;

result.Z = vec.X * mat.Row2.X +
vec.Y * mat.Row2.Y +
vec.Z * mat.Row2.Z;
#else
result.X = vec.X * mat.Row0.X +
vec.Y * mat.Row1.X +
vec.Z * mat.Row2.X;
Expand All @@ -774,14 +798,19 @@ public static void TransformVector(ref SCNVector3 vec, ref SCNMatrix4 mat, out S
result.Z = vec.X * mat.Row0.Z +
vec.Y * mat.Row1.Z +
vec.Z * mat.Row2.Z;
#endif
}

/// <summary>Transform a Normal by the given Matrix</summary>
/// <remarks>
/// This calculates the inverse of the given matrix, use TransformNormalInverse if you
/// already have the inverse to avoid this extra calculation
/// </remarks>
/// <param name="norm">The normal to transform</param>
#if NET
/// <param name="norm">The column-based normal to transform</param>
#else
/// <param name="norm">The row-based normal to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <returns>The transformed normal</returns>
public static SCNVector3 TransformNormal(SCNVector3 norm, SCNMatrix4 mat)
Expand All @@ -795,7 +824,11 @@ public static SCNVector3 TransformNormal(SCNVector3 norm, SCNMatrix4 mat)
/// This calculates the inverse of the given matrix, use TransformNormalInverse if you
/// already have the inverse to avoid this extra calculation
/// </remarks>
/// <param name="norm">The normal to transform</param>
#if NET
/// <param name="norm">The column-based normal to transform</param>
#else
/// <param name="norm">The row-based normal to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <param name="result">The transformed normal</param>
public static void TransformNormal(ref SCNVector3 norm, ref SCNMatrix4 mat, out SCNVector3 result)
Expand All @@ -809,15 +842,16 @@ public static void TransformNormal(ref SCNVector3 norm, ref SCNMatrix4 mat, out
/// This version doesn't calculate the inverse matrix.
/// Use this version if you already have the inverse of the desired transform to hand
/// </remarks>
/// <param name="norm">The normal to transform</param>
#if NET
/// <param name="norm">The column-based normal to transform</param>
#else
/// <param name="norm">The row-based normal to transform</param>
#endif
/// <param name="invMat">The inverse of the desired transformation</param>
/// <returns>The transformed normal</returns>
public static SCNVector3 TransformNormalInverse(SCNVector3 norm, SCNMatrix4 invMat)
{
SCNVector3 n;
n.X = SCNVector3.Dot(norm, new SCNVector3(invMat.Row0));
n.Y = SCNVector3.Dot(norm, new SCNVector3(invMat.Row1));
n.Z = SCNVector3.Dot(norm, new SCNVector3(invMat.Row2));
TransformNormalInverse (ref norm, ref invMat, out var n);
return n;
}

Expand All @@ -826,11 +860,28 @@ public static SCNVector3 TransformNormalInverse(SCNVector3 norm, SCNMatrix4 invM
/// This version doesn't calculate the inverse matrix.
/// Use this version if you already have the inverse of the desired transform to hand
/// </remarks>
/// <param name="norm">The normal to transform</param>
#if NET
/// <param name="norm">The column-based normal to transform</param>
#else
/// <param name="norm">The row-based normal to transform</param>
#endif
/// <param name="invMat">The inverse of the desired transformation</param>
/// <param name="result">The transformed normal</param>
public static void TransformNormalInverse(ref SCNVector3 norm, ref SCNMatrix4 invMat, out SCNVector3 result)
{
#if NET
result.X = norm.X * invMat.Column0.X +
norm.Y * invMat.Column0.Y +
norm.Z * invMat.Column0.Z;

result.Y = norm.X * invMat.Column1.X +
norm.Y * invMat.Column1.Y +
norm.Z * invMat.Column1.Z;

result.Z = norm.X * invMat.Column2.X +
norm.Y * invMat.Column2.Y +
norm.Z * invMat.Column2.Z;
#else
result.X = norm.X * invMat.Row0.X +
norm.Y * invMat.Row0.Y +
norm.Z * invMat.Row0.Z;
Expand All @@ -842,27 +893,49 @@ public static void TransformNormalInverse(ref SCNVector3 norm, ref SCNMatrix4 in
result.Z = norm.X * invMat.Row2.X +
norm.Y * invMat.Row2.Y +
norm.Z * invMat.Row2.Z;
#endif
}

/// <summary>Transform a Position by the given Matrix</summary>
/// <param name="pos">The position to transform</param>
#if NET
/// <param name="pos">The column-based position to transform</param>
#else
/// <param name="pos">The row-based position to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <returns>The transformed position</returns>
public static SCNVector3 TransformPosition(SCNVector3 pos, SCNMatrix4 mat)
{
SCNVector3 p;
p.X = SCNVector3.Dot(pos, new SCNVector3(mat.Column0)) + mat.Row3.X;
p.Y = SCNVector3.Dot(pos, new SCNVector3(mat.Column1)) + mat.Row3.Y;
p.Z = SCNVector3.Dot(pos, new SCNVector3(mat.Column2)) + mat.Row3.Z;
TransformPosition (ref pos, ref mat, out var p);
return p;
}

/// <summary>Transform a Position by the given Matrix</summary>
/// <param name="pos">The position to transform</param>
#if NET
/// <param name="pos">The column-based position to transform</param>
#else
/// <param name="pos">The row-based position to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <param name="result">The transformed position</param>
public static void TransformPosition(ref SCNVector3 pos, ref SCNMatrix4 mat, out SCNVector3 result)
{
#if NET
result.X = mat.Row0.X * pos.X +
mat.Row0.Y * pos.Y +
mat.Row0.Z * pos.Z +
mat.Row0.W;

result.Y = mat.Row1.X * pos.X +
mat.Row1.Y * pos.Y +
mat.Row1.Z * pos.Z +
mat.Row1.W;

result.Z = mat.Row2.X * pos.X +
mat.Row2.Y * pos.Y +
mat.Row2.Z * pos.Z +
mat.Row2.W;
#else
result.X = pos.X * mat.Row0.X +
pos.Y * mat.Row1.X +
pos.Z * mat.Row2.X +
Expand All @@ -877,25 +950,29 @@ public static void TransformPosition(ref SCNVector3 pos, ref SCNMatrix4 mat, out
pos.Y * mat.Row1.Z +
pos.Z * mat.Row2.Z +
mat.Row3.Z;
#endif
}

/// <summary>Transform a Vector by the given Matrix</summary>
/// <param name="vec">The vector to transform</param>
#if NET
/// <param name="vec">The column vector to transform</param>
#else
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <returns>The transformed vector</returns>
public static SCNVector4 Transform(SCNVector3 vec, SCNMatrix4 mat)
{
SCNVector4 v4 = new SCNVector4(vec.X, vec.Y, vec.Z, 1.0f);
SCNVector4 result;
result.X = SCNVector4.Dot(v4, mat.Column0);
result.Y = SCNVector4.Dot(v4, mat.Column1);
result.Z = SCNVector4.Dot(v4, mat.Column2);
result.W = SCNVector4.Dot(v4, mat.Column3);
return result;
return SCNVector4.Transform (v4, mat);
}

/// <summary>Transform a Vector by the given Matrix</summary>
/// <param name="vec">The vector to transform</param>
#if NET
/// <param name="vec">The column vector to transform</param>
#else
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <param name="result">The transformed vector</param>
public static void Transform(ref SCNVector3 vec, ref SCNMatrix4 mat, out SCNVector4 result)
Expand Down
42 changes: 34 additions & 8 deletions src/SceneKit/SCNVector4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -843,25 +843,50 @@ public static void BaryCentric(ref SCNVector4 a, ref SCNVector4 b, ref SCNVector
#region Transform

/// <summary>Transform a Vector by the given Matrix</summary>
/// <param name="vec">The vector to transform</param>
#if NET
/// <param name="vec">The column vector to transform</param>
#else
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <returns>The transformed vector</returns>
public static SCNVector4 Transform(SCNVector4 vec, SCNMatrix4 mat)
{
SCNVector4 result;
result.X = SCNVector4.Dot(vec, mat.Column0);
result.Y = SCNVector4.Dot(vec, mat.Column1);
result.Z = SCNVector4.Dot(vec, mat.Column2);
result.W = SCNVector4.Dot(vec, mat.Column3);
Transform(ref vec, ref mat, out var result);
return result;
}

/// <summary>Transform a Vector by the given Matrix</summary>
/// <param name="vec">The vector to transform</param>
/// <summary>Transform a Vector by the given Matrix.</summary>
#if NET
/// <param name="vec">The column vector to transform</param>
#else
/// <param name="vec">The row vector to transform</param>
#endif
/// <param name="mat">The desired transformation</param>
/// <param name="result">The transformed vector</param>
public static void Transform(ref SCNVector4 vec, ref SCNMatrix4 mat, out SCNVector4 result)
{
#if NET
result.X = vec.X * mat.Column0.X +
vec.Y * mat.Column1.X +
vec.Z * mat.Column2.X +
vec.W * mat.Column3.X;

result.Y = vec.X * mat.Column0.Y +
vec.Y * mat.Column1.Y +
vec.Z * mat.Column2.Y +
vec.W * mat.Column3.Y;

result.Z = vec.X * mat.Column0.Z +
vec.Y * mat.Column1.Z +
vec.Z * mat.Column2.Z +
vec.W * mat.Column3.Z;

result.W = vec.X * mat.Column0.W +
vec.Y * mat.Column1.W +
vec.Z * mat.Column2.W +
vec.W * mat.Column3.W;
#else
result.X = vec.X * mat.Row0.X +
vec.Y * mat.Row1.X +
vec.Z * mat.Row2.X +
Expand All @@ -881,6 +906,7 @@ public static void Transform(ref SCNVector4 vec, ref SCNMatrix4 mat, out SCNVect
vec.Y * mat.Row1.W +
vec.Z * mat.Row2.W +
vec.W * mat.Row3.W;
#endif
}

#endregion
Expand Down
20 changes: 20 additions & 0 deletions tests/bindings-test/StructsAndEnums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Foundation;
using ObjCRuntime;
using SceneKit;

#if NET
using MatrixFloat2x2 = global::CoreGraphics.NMatrix2;
Expand All @@ -16,6 +17,16 @@
using MatrixFloat4x4 = global::OpenTK.NMatrix4;
#endif

#if __MACOS__
#if NET
using pfloat = System.Runtime.InteropServices.NFloat;
#else
using pfloat = System.nfloat;
#endif
#else
using pfloat = System.Single;
#endif

public static class LibTest {
[DllImport ("__Internal")]
public static extern int theUltimateAnswer ();
Expand Down Expand Up @@ -126,5 +137,14 @@ public static MatrixFloat4x4 MDLTransform_GetRotationMatrix (INativeObject obj,
r3c0, r3c1, r3c2, r3c3);
}
#endif

[DllImport ("__Internal")]
public static extern SCNMatrix4 x_SCNMatrix4MakeTranslation (pfloat tx, pfloat ty, pfloat tz);

[DllImport ("__Internal")]
public static extern SCNMatrix4 x_SCNMatrix4MakeScale (pfloat tx, pfloat ty, pfloat tz);

[DllImport ("__Internal")]
public static extern SCNMatrix4 x_SCNMatrix4Translate (SCNMatrix4 m, pfloat tx, pfloat ty, pfloat tz);
}
}
Loading