Browse Source

added small tolerance to IBM check

Vicente Penades 3 years ago
parent
commit
f31e8d4c1c

+ 3 - 2
src/Shared/Guard.cs

@@ -247,10 +247,11 @@ namespace SharpGLTF
             foreach (var val in collection) Guard.NotNull(val, parameterName, message);
         }
 
-        public static void AreTrue(IEnumerable<bool> collection, string parameterName, string message = "")
+        public static void AreTrue(IEnumerable<bool> collection, string parameterName, Func<int,string> messageFunc = null)
         {
             Guard.NotNull(collection, nameof(collection));
-            foreach (var val in collection) Guard.IsTrue(val, parameterName, message);
+            int index = 0;
+            foreach (var val in collection) { Guard.IsTrue(val, parameterName, messageFunc?.Invoke(index) ?? String.Empty); ++index; }
         }
 
         public static void MustBeEqualTo<TValue>(IEnumerable<TValue> collection, TValue expected, string parameterName)

+ 5 - 5
src/Shared/_Extensions.cs

@@ -208,7 +208,7 @@ namespace SharpGLTF
             InverseBindMatrix = Invertible | IdentityColumn4
         }
 
-        internal static bool IsValid(this in Matrix4x4 matrix, MatrixCheck check)
+        internal static bool IsValid(this in Matrix4x4 matrix, MatrixCheck check, float tolerance = 0)
         {
             if (!matrix._IsFinite()) return false;
 
@@ -216,13 +216,13 @@ namespace SharpGLTF
             if (check.HasFlag(MatrixCheck.Identity) && matrix != Matrix4x4.Identity) return false;
             if (check.HasFlag(MatrixCheck.IdentityColumn4))
             {
-                // glTF validator requires 4th column to be (0,0,0,1)
-                // so it means the glTF standard does not allow rounding errors.
-                // https://github.com/vpenades/SharpGLTF/issues/130#issuecomment-1086306019
+                // Acording to gltf schema
+                // "The fourth row of each matrix MUST be set to [0.0, 0.0, 0.0, 1.0]."
+                // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins-overview
                 if (matrix.M14 != 0) return false;
                 if (matrix.M24 != 0) return false;
                 if (matrix.M34 != 0) return false;
-                if (matrix.M44 != 1) return false;
+                if (Math.Abs(matrix.M44 - 1) > tolerance) return false;
             }
 
             if (check.HasFlag(MatrixCheck.Invertible) && !Matrix4x4.Invert(matrix, out _)) return false;

+ 8 - 3
src/SharpGLTF.Core/Schema2/gltf.Skin.cs

@@ -120,17 +120,22 @@ namespace SharpGLTF.Schema2
 
             _FindCommonAncestor(joints.Select(item => item.Joint));
 
-            // fix 4th column to meet gltf schema specification and gltf Validator.
+            // Acording to gltf schema
+            // "The fourth row of each matrix MUST be set to [0.0, 0.0, 0.0, 1.0]."
+            // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins-overview
             for (int i = 0; i < joints.Length; ++i)
             {
                 var ibm = joints[i].InverseBindMatrix;
+
+                Guard.IsTrue(ibm.IsValid(_Extensions.MatrixCheck.InverseBindMatrix, 0.01f), nameof(joints));
+
+                // fourth column (row in schema) is within tolerance
+                // so we can enforce exact values,
                 ibm.M14 = 0;
                 ibm.M24 = 0;
                 ibm.M34 = 0;
                 ibm.M44 = 1;
 
-                Guard.IsTrue(ibm.IsValid(_Extensions.MatrixCheck.InverseBindMatrix), nameof(joints));
-
                 joints[i] = (joints[i].Joint, ibm);
             }
 

+ 1 - 1
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.cs

@@ -186,7 +186,7 @@ namespace SharpGLTF.Scenes
         {
             Guard.NotNull(mesh, nameof(mesh));
             GuardAll.NotNull(joints.Select(item => item.Joint), nameof(joints));
-            GuardAll.AreTrue(joints.Select(item => item.InverseBindMatrix.IsValid(_Extensions.MatrixCheck.InverseBindMatrix)), nameof(joints), "Invalid matrix");
+            GuardAll.AreTrue(joints.Select(item => item.InverseBindMatrix.IsValid(_Extensions.MatrixCheck.InverseBindMatrix, 0.01f)), nameof(joints), idx => $"matrix {idx} is invalid.");
 
             var instance = new InstanceBuilder(this);
             instance.Content = new SkinnedTransformer(mesh, joints);

+ 2 - 0
src/SharpGLTF.Toolkit/Scenes/Transformers.cs

@@ -436,6 +436,8 @@ namespace SharpGLTF.Scenes
             Guard.NotNull(joints, nameof(joints));
             Guard.IsTrue(NodeBuilder.IsValidArmature(joints.Select(item => item.Joint)), nameof(joints));
 
+            GuardAll.AreTrue(joints.Select(item => item.InverseBindMatrix.IsValid(_Extensions.MatrixCheck.InverseBindMatrix, 0.01f)), nameof(joints), idx => $"matrix {idx} is invalid");
+
             _MeshPoseWorldTransform = null;
             _Joints.Clear();
             _Joints.AddRange(joints.Select(item => (item.Joint, (Matrix4x4?)item.InverseBindMatrix)));