Vicente Penades 6 年 前
コミット
15739c2b63

+ 14 - 14
examples/InfiniteSkinnedTentacle/Program.cs

@@ -49,10 +49,10 @@ namespace InfiniteSkinnedTentacle
                 .CreateMeshes(CreateMesh(10))
                 .First();
 
-            RecusiveTentacle(scene, Matrix4x4.CreateTranslation(+25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0.2f, 0f), 2);
-            RecusiveTentacle(scene, Matrix4x4.CreateTranslation(-25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);
-            RecusiveTentacle(scene, Matrix4x4.CreateTranslation(-25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0f, 0.2f), 2);
-            RecusiveTentacle(scene, Matrix4x4.CreateTranslation(+25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);            
+            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(+25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0.2f, 0f), 2);
+            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(-25, 0, +25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);
+            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(-25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0f, 0f, 0.2f), 2);
+            RecusiveTentacle(scene, scene, Matrix4x4.CreateTranslation(+25, 0, -25), mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), 2);            
 
             model.SaveGLB("recursive tentacles.glb");
 
@@ -63,25 +63,25 @@ namespace InfiniteSkinnedTentacle
             model.SaveAsWavefront("recursive_tentacles_at_100.obj", model.LogicalAnimations[0], 1);
         }
         
-        static void RecusiveTentacle(IVisualNodeContainer parent, Matrix4x4 offset, Mesh mesh, Quaternion anim, int repeat)
+        static void RecusiveTentacle(Scene scene, IVisualNodeContainer parent, Matrix4x4 offset, Mesh mesh, Quaternion anim, int repeat)
         {
             parent = parent
                 .CreateNode()
                 .WithLocalTransform(offset);
 
-            parent = AddTentacleSkeleton(parent as Node, mesh, anim);
+            parent = AddTentacleSkeleton(scene, parent as Node, mesh, anim);
 
             if (repeat == 0) return;
 
             var scale = Matrix4x4.CreateScale(0.2f);
 
-            RecusiveTentacle(parent, Matrix4x4.CreateTranslation(+15, 0, +15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0f, 0.2f, 0f), repeat - 1);
-            RecusiveTentacle(parent, Matrix4x4.CreateTranslation(-15, 0, +15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), repeat - 1);
-            RecusiveTentacle(parent, Matrix4x4.CreateTranslation(-15, 0, -15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0f, 0f, 0.2f), repeat - 1);
-            RecusiveTentacle(parent, Matrix4x4.CreateTranslation(+15, 0, -15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), repeat - 1);
+            RecusiveTentacle(scene, parent, Matrix4x4.CreateTranslation(+15, 0, +15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0f, 0.2f, 0f), repeat - 1);
+            RecusiveTentacle(scene, parent, Matrix4x4.CreateTranslation(-15, 0, +15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), repeat - 1);
+            RecusiveTentacle(scene, parent, Matrix4x4.CreateTranslation(-15, 0, -15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0f, 0f, 0.2f), repeat - 1);
+            RecusiveTentacle(scene, parent, Matrix4x4.CreateTranslation(+15, 0, -15) * scale, mesh, Quaternion.CreateFromYawPitchRoll(0.2f, 0f, 0f), repeat - 1);
         }
 
-        static Node AddTentacleSkeleton(Node skeleton, Mesh mesh, Quaternion anim)
+        static Node AddTentacleSkeleton(Scene scene, Node skeleton, Mesh mesh, Quaternion anim)
         {
             var bindings = new List<Node>();
 
@@ -104,9 +104,9 @@ namespace InfiniteSkinnedTentacle
                 bindings.Add(bone);                
             }
 
-            skeleton.VisualScene.CreateNode()
-                .WithMesh(mesh)
-                .WithSkinBinding(bindings.ToArray());
+            scene
+                .CreateNode()
+                .WithSkinnedMesh(mesh, bindings.ToArray());
 
             return bindings.Last();
         }

+ 7 - 4
src/SharpGLTF.Core/Schema2/gltf.Node.cs

@@ -49,14 +49,17 @@ namespace SharpGLTF.Schema2
         public Node VisualRoot => this.LogicalParent._FindVisualRootNode(this);
 
         /// <summary>
-        /// Gets the visual root <see cref="Scene"/> instance that contains this <see cref="Node"/>.
+        /// Gets the collection of <see cref="Scene"/> instances that reference this <see cref="Node"/>.
         /// </summary>
-        public Scene VisualScene
+        public IEnumerable<Scene> VisualScenes
         {
             get
             {
                 var rootNode = this.VisualRoot;
-                return LogicalParent.LogicalScenes.FirstOrDefault(item => item._ContainsVisualNode(rootNode, false));
+
+                return LogicalParent
+                    .LogicalScenes
+                    .Where(item => item._ContainsVisualNode(rootNode, false));
             }
         }
 
@@ -221,11 +224,11 @@ namespace SharpGLTF.Schema2
                 if (value == null) { this._skin = null; return; }
 
                 Guard.MustShareLogicalParent(this.LogicalParent, value, nameof(value));
+
                 Guard.IsFalse(_matrix.HasValue, _NOTRANSFORMMESSAGE);
                 Guard.IsFalse(_scale.HasValue, _NOTRANSFORMMESSAGE);
                 Guard.IsFalse(_rotation.HasValue, _NOTRANSFORMMESSAGE);
                 Guard.IsFalse(_translation.HasValue, _NOTRANSFORMMESSAGE);
-                // Todo: guard against animations.
 
                 this._skin = value.LogicalIndex;
             }

+ 7 - 2
src/SharpGLTF.Core/Schema2/gltf.Skin.cs

@@ -86,9 +86,14 @@ namespace SharpGLTF.Schema2
             BindJoints(rootJoint.WorldMatrix, joints);
         }
 
-        public void BindJoints(Matrix4x4 meshBingTransform, params Node[] joints)
+        /// <summary>
+        /// Binds the tree of bones to the associated skinned mesh.
+        /// </summary>
+        /// <param name="meshBindTransform">The world transform matrix of the mesh at the time of binding.</param>
+        /// <param name="joints">A collection of <see cref="Node"/> joints.</param>
+        public void BindJoints(Matrix4x4 meshBindTransform, params Node[] joints)
         {
-            var meshBingInverse = meshBingTransform.Inverse();
+            var meshBingInverse = meshBindTransform.Inverse();
 
             var pairs = new KeyValuePair<Node, Matrix4x4>[joints.Length];
 

+ 21 - 12
src/SharpGLTF.Toolkit/Schema2/SceneExtensions.cs

@@ -4,12 +4,11 @@ using System.Linq;
 using System.Numerics;
 using System.Text;
 
+using SharpGLTF.Geometry;
+using SharpGLTF.Geometry.VertexTypes;
+
 namespace SharpGLTF.Schema2
 {
-    using Geometry;
-    using Geometry.VertexTypes;
-    using VEMPTY = Geometry.VertexTypes.VertexEmpty;
-
     public static partial class Schema2Toolkit
     {
         #region fluent creation
@@ -61,11 +60,7 @@ namespace SharpGLTF.Schema2
 
         public static Node WithSkinBinding(this Node node, params Node[] joints)
         {
-            var skin = node.LogicalParent.CreateSkin();
-            skin.BindJoints(joints);
-
-            node.Skin = skin;
-            return node;
+            return node.WithSkinBinding(node.WorldMatrix, joints);
         }
 
         public static Node WithSkinBinding(this Node node, Matrix4x4 meshPoseTransform, params Node[] joints)
@@ -77,6 +72,20 @@ namespace SharpGLTF.Schema2
             return node;
         }
 
+        public static Node WithSkinnedMesh(this Node node, Mesh mesh, params Node[] joints)
+        {
+            Guard.NotNull(node, nameof(node));
+            Guard.MustShareLogicalParent(node, mesh, nameof(mesh));
+
+            foreach (var j in joints) Guard.MustShareLogicalParent(node, j, nameof(joints));
+
+            // TODO: the joints must be visible in the visual tree that contains node.
+
+            return node
+                .WithMesh(mesh)
+                .WithSkinBinding(joints);
+        }
+
         #endregion
 
         #region evaluation
@@ -124,7 +133,7 @@ namespace SharpGLTF.Schema2
         /// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
         /// <param name="time">The animation time.</param>
         /// <returns>A collection of triangles in world space.</returns>
-        public static IEnumerable<(VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, Material)> Triangulate<TvG, TvM>(this Scene scene, Animation animation = null, float time = 0)
+        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> Triangulate<TvG, TvM>(this Scene scene, Animation animation = null, float time = 0)
             where TvG : struct, IVertexGeometry
             where TvM : struct, IVertexMaterial
         {
@@ -140,13 +149,13 @@ namespace SharpGLTF.Schema2
         /// <param name="animation">An <see cref="Animation"/> instance, or null.</param>
         /// <param name="time">The animation time.</param>
         /// <returns>A collection of triangles in world space.</returns>
-        public static IEnumerable<(VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, Material)> Triangulate<TvG, TvM>(this Node node, Animation animation = null, float time = 0)
+        public static IEnumerable<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)> Triangulate<TvG, TvM>(this Node node, Animation animation = null, float time = 0)
             where TvG : struct, IVertexGeometry
             where TvM : struct, IVertexMaterial
         {
             var mesh = node.Mesh;
 
-            if (mesh == null) return Enumerable.Empty<(VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, VertexBuilder<TvG, TvM, VEMPTY>, Material)>();
+            if (mesh == null) return Enumerable.Empty<(VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, VertexBuilder<TvG, TvM, VertexEmpty>, Material)>();
 
             var xform = node.GetMeshWorldTransform(animation, time);
 

+ 8 - 12
tests/SharpGLTF.Tests/AssemblyAPITests.cs

@@ -76,9 +76,7 @@ namespace SharpGLTF
 
             TestContext.CurrentContext.AttachText($"API.Core.{Schema2.Asset.AssemblyInformationalVersion}.txt", API);
 
-            var r = _CheckBackwardsCompatibility("API.Core.1.0.0-alpha0008.txt", API);
-
-            Assert.IsTrue(r);
+            _CheckBackwardsCompatibility("API.Core.1.0.0-alpha0008.txt", API);
         }
 
         [Test(Description = "Checks if we have introduced a breaking change between the current and previous API")]
@@ -92,29 +90,27 @@ namespace SharpGLTF
 
             TestContext.CurrentContext.AttachText($"API.Toolkit.{Schema2.Asset.AssemblyInformationalVersion}.txt", API);
 
-            var r = _CheckBackwardsCompatibility("API.Toolkit.1.0.0-alpha0008.txt", API);
-
-            Assert.IsTrue(r);
+            _CheckBackwardsCompatibility("API.Toolkit.1.0.0-alpha0008.txt", API);
         }
 
-        private static bool _CheckBackwardsCompatibility(string referenceAPIFile, string[] newLines)
+        private static void _CheckBackwardsCompatibility(string referenceAPIFile, string[] newLines)
         {
             referenceAPIFile = System.IO.Path.Combine(TestContext.CurrentContext.WorkDirectory, "Assets", referenceAPIFile);
 
             var refLines = System.IO.File.ReadAllLines(referenceAPIFile);
 
-            bool failed = false;
+            bool backwardsCompatible = true;
 
-            foreach(var l in refLines)
+            foreach (var l in refLines)
             {
                 if (!newLines.Contains(l))
                 {
                     TestContext.WriteLine($"Missing:  {l}");
-                    failed = true;
-                }
+                    backwardsCompatible = false;
+                }                
             }
 
-            return !failed;
+            Warn.If(!backwardsCompatible, "Current API is not backwards compatible");
         }
     }
 }