Prechádzať zdrojové kódy

Improved AffineTransform multiplication.

Vicente Penades 3 rokov pred
rodič
commit
fdcd1b2a45

+ 19 - 18
src/SharpGLTF.Core/Transforms/AffineTransform.cs

@@ -616,34 +616,35 @@ namespace SharpGLTF.Transforms
         /// </returns>
         /// </returns>
         public static AffineTransform Multiply(in AffineTransform a, in AffineTransform b)
         public static AffineTransform Multiply(in AffineTransform a, in AffineTransform b)
         {
         {
-            // if any of the two operators is a matrix, do a matrix multiplication.
+            Guard.IsFalse(a._Representation == DATA_UNDEFINED, nameof(a));
+            Guard.IsFalse(b._Representation == DATA_UNDEFINED, nameof(b));
+            
             if (a.IsMatrix || b.IsMatrix)
             if (a.IsMatrix || b.IsMatrix)
             {
             {
+                // if any of the two operators is a matrix,
+                // do a matrix multiplication.
+
                 return new AffineTransform(a.Matrix * b.Matrix);
                 return new AffineTransform(a.Matrix * b.Matrix);
             }
             }
-
-            Guard.IsFalse(a._Representation == DATA_UNDEFINED, nameof(a));
-            Guard.IsFalse(b._Representation == DATA_UNDEFINED, nameof(b));
-
-            // if the B operator has an uneven scale AND a rotation, do a matrix multiplication
-            // which produces a squeezed matrix and cannot be decomposed.
-
+            
             var sb = b.Scale;
             var sb = b.Scale;
 
 
-            if (!(sb.X == sb.Y && sb.X == sb.Z) && b.Rotation != Quaternion.Identity)
+            if (sb.X != sb.Y || sb.X != sb.Z)
             {
             {
-                return new AffineTransform(a.Matrix * b.Matrix);
-            }
-
-            // we're safe to make a decomposed multiplication
+                // If the B operator has an uneven scale,                
+                // do a matrix multiplication which produces
+                // a sheared matrix that cannot be decomposed.
 
 
-            var s = _Vector3Transform(b.Scale * _Vector3Transform(a.Scale, a.Rotation), Quaternion.Inverse(a.Rotation));
+                return new AffineTransform(a.Matrix * b.Matrix);
+            }            
 
 
-            var r = Quaternion.Multiply(b.Rotation, a.Rotation);
+            var s = sb * a.Scale;
+            
+            var rb = b.Rotation;
 
 
-            var t
-                = b.Translation
-                + _Vector3Transform(a.Translation * b.Scale, b.Rotation);
+            var r = Quaternion.Multiply(rb, a.Rotation);            
+            
+            var t = b.Translation + _Vector3Transform(a.Translation * sb, rb);
 
 
             return new AffineTransform(s, r, t);
             return new AffineTransform(s, r, t);
         }
         }

+ 31 - 9
tests/SharpGLTF.Core.Tests/Transforms/AffineTransformMatrixTests.cs

@@ -4,8 +4,12 @@ using System.Numerics;
 using System.Text;
 using System.Text;
 using System.Xml;
 using System.Xml;
 
 
+using Newtonsoft.Json;
+
 using NUnit.Framework;
 using NUnit.Framework;
 
 
+using Plotly;
+
 namespace SharpGLTF.Transforms
 namespace SharpGLTF.Transforms
 {
 {
     [Category("Core.Transforms")]
     [Category("Core.Transforms")]
@@ -102,15 +106,30 @@ namespace SharpGLTF.Transforms
             Assert.IsTrue(asDecomposed.IsIdentity);
             Assert.IsTrue(asDecomposed.IsIdentity);
         }
         }
 
 
-        [Test]
-        public void TestAffineTransformMult()
+        [TestCase(false, false, false, false)]
+        [TestCase(false, false, false, true)]
+        [TestCase(false, false, true, false)]
+        [TestCase(false, false, true, true)]
+        [TestCase(false, true, false, false)]
+        [TestCase(false, true, false, true)]
+        [TestCase(false, true, true, false)]
+        [TestCase(false, true, true, true)]
+        [TestCase(true, false, false, false)]
+        [TestCase(true, false, false, true)]
+        [TestCase(true, false, true, false)]
+        [TestCase(true, false, true, true)]
+        [TestCase(true, true, false, false)]
+        [TestCase(true, true, false, true)]
+        [TestCase(true, true, true, false)]
+        [TestCase(true, true, true, true)]
+        public void TestAffineTransformMult(bool sa, bool sb, bool ra, bool rb)
         {
         {
-            var s_a = new Vector3(1, 2, 4);
-            var r_a = Quaternion.CreateFromYawPitchRoll(1, 2, 3);
-            var t_a = Vector3.Zero;
+            var s_a = sa ? new Vector3(1, 2, 4) : Vector3.One;
+            var r_a = ra ? Quaternion.CreateFromYawPitchRoll(1, 2, 3) : Quaternion.Identity;
+            var t_a = new Vector3(1, 5, -9);
 
 
-            var s_b = new Vector3(1, 1, 1);
-            var r_b = Quaternion.CreateFromYawPitchRoll(1, 0, 2);
+            var s_b = sb ? new Vector3(1, 2, 4) : Vector3.One;
+            var r_b = rb ? Quaternion.CreateFromYawPitchRoll(1, 0, 2) : Quaternion.Identity;
             var t_b = new Vector3(3, -4, 2);
             var t_b = new Vector3(3, -4, 2);
 
 
             var mat_a = Matrix4x4.CreateScale(s_a) * Matrix4x4.CreateFromQuaternion(r_a) * Matrix4x4.CreateTranslation(t_a);
             var mat_a = Matrix4x4.CreateScale(s_a) * Matrix4x4.CreateFromQuaternion(r_a) * Matrix4x4.CreateTranslation(t_a);
@@ -123,8 +142,11 @@ namespace SharpGLTF.Transforms
             var srt_ab = AffineTransform.Multiply(srt_a, srt_b);
             var srt_ab = AffineTransform.Multiply(srt_a, srt_b);
             var srt_ba = AffineTransform.Multiply(srt_b, srt_a);
             var srt_ba = AffineTransform.Multiply(srt_b, srt_a);
 
 
-            NumericsAssert.AreEqual(mat_ab, srt_ab.Matrix, 0.0001f);
-            NumericsAssert.AreEqual(mat_ba, srt_ba.Matrix, 0.0001f);
+            TestContext.WriteLine($"A({sa},{ra}) x B({sb},{rb}) = {srt_ab.IsSRT}");
+            TestContext.WriteLine($"B({sb},{rb}) x A({sa},{ra}) = {srt_ba.IsSRT}");
+
+            NumericsAssert.AreEqual(mat_ab, srt_ab.Matrix, 0.00001f);
+            NumericsAssert.AreEqual(mat_ba, srt_ba.Matrix, 0.00001f);
         }
         }