Browse Source

wrapping up...

Vicente Penades 6 years ago
parent
commit
ef059225bf

+ 31 - 11
src/SharpGLTF.Core/Schema2/gltf.Camera.cs

@@ -64,10 +64,7 @@ namespace SharpGLTF.Schema2
         /// <param name="zfar">Distance to the far plane in the Z axis.</param>
         public void SetOrthographicMode(float xmag, float ymag, float znear, float zfar)
         {
-            Guard.MustBeGreaterThanOrEqualTo(znear, 0, nameof(znear));
-            Guard.MustBeGreaterThanOrEqualTo(zfar, 0, nameof(zfar));
-            Guard.MustBeGreaterThan(zfar, znear, nameof(zfar));
-            Guard.MustBeLessThan(zfar, float.PositiveInfinity, nameof(zfar));
+            CameraOrthographic.CheckParameters(xmag, ymag, znear, zfar);
 
             this._perspective = null;
             this._orthographic = new CameraOrthographic(xmag, ymag, znear, zfar);
@@ -84,13 +81,7 @@ namespace SharpGLTF.Schema2
         /// <param name="zfar">Distance to the far plane in the Z axis.</param>
         public void SetPerspectiveMode(float? aspectRatio, float yfov, float znear, float zfar)
         {
-            if (aspectRatio.HasValue) Guard.MustBeGreaterThanOrEqualTo(aspectRatio.Value, 0, nameof(aspectRatio));
-            Guard.MustBeGreaterThan(yfov, 0, nameof(yfov));
-            Guard.MustBeLessThan(yfov, (float)Math.PI, nameof(yfov));
-
-            Guard.MustBeGreaterThanOrEqualTo(znear, 0, nameof(znear));
-            Guard.MustBeGreaterThanOrEqualTo(zfar, 0, nameof(zfar));
-            Guard.MustBeGreaterThan(zfar, znear, nameof(zfar));
+            CameraPerspective.CheckParameters(aspectRatio, yfov, znear, zfar);
 
             this._orthographic = null;
             this._perspective = new CameraPerspective(aspectRatio, yfov, znear, zfar);
@@ -158,6 +149,18 @@ namespace SharpGLTF.Schema2
         public System.Numerics.Matrix4x4 Matrix => Transforms.Projection.CreateOrthographicMatrix(XMag, YMag, ZNear, ZFar);
 
         #endregion
+
+        #region API
+
+        public static void CheckParameters(float xmag, float ymag, float znear, float zfar)
+        {
+            Guard.MustBeGreaterThanOrEqualTo(znear, 0, nameof(znear));
+            Guard.MustBeGreaterThanOrEqualTo(zfar, 0, nameof(zfar));
+            Guard.MustBeGreaterThan(zfar, znear, nameof(zfar));
+            Guard.MustBeLessThan(zfar, float.PositiveInfinity, nameof(zfar));
+        }
+
+        #endregion
     }
 
     [System.Diagnostics.DebuggerDisplay("Perspective {AspectRatio} {VerticalFOV}   {ZNear} < {ZFar}")]
@@ -169,6 +172,8 @@ namespace SharpGLTF.Schema2
 
         internal CameraPerspective(float? aspectRatio, float yfov, float znear, float zfar)
         {
+            CheckParameters(aspectRatio, yfov, znear, zfar);
+
             this._aspectRatio = aspectRatio ?? null;
             this._yfov = yfov;
             this._znear = znear;
@@ -212,6 +217,21 @@ namespace SharpGLTF.Schema2
         public System.Numerics.Matrix4x4 Matrix => Transforms.Projection.CreateOrthographicMatrix(AspectRatio.AsValue(1), VerticalFOV, ZNear, ZFar);
 
         #endregion
+
+        #region API
+
+        public static void CheckParameters(float? aspectRatio, float yfov, float znear, float zfar = float.PositiveInfinity)
+        {
+            if (aspectRatio.HasValue) Guard.MustBeGreaterThanOrEqualTo(aspectRatio.Value, 0, nameof(aspectRatio));
+            Guard.MustBeGreaterThan(yfov, 0, nameof(yfov));
+            Guard.MustBeLessThan(yfov, (float)Math.PI, nameof(yfov));
+
+            Guard.MustBeGreaterThanOrEqualTo(znear, 0, nameof(znear));
+            Guard.MustBeGreaterThanOrEqualTo(zfar, 0, nameof(zfar));
+            Guard.MustBeGreaterThan(zfar, znear, nameof(zfar));
+        }
+
+        #endregion
     }
 
     public partial class ModelRoot

+ 3 - 3
src/SharpGLTF.Core/Transforms/MeshTransforms.cs

@@ -51,9 +51,9 @@ namespace SharpGLTF.Transforms
         #region data
 
         /// <summary>
-        /// Represents a normalized sparse collection of weights where:
-        /// - Indices with value zero point to the master mesh
-        /// - Indices with value over zero point to MorphTarget[index-1].
+        /// Represents a sparse collection of weights where:
+        /// - Index of value <see cref="_COMPLEMENT_INDEX"/> points to the Mesh master positions.
+        /// - All other indices point to Mesh MorphTarget[index] positions.
         /// </summary>
         private SparseWeight8 _Weights;
 

+ 2 - 2
src/SharpGLTF.Core/Transforms/SparseWeight8.cs

@@ -581,10 +581,10 @@ namespace SharpGLTF.Transforms
         }
 
         /// <summary>
-        /// Normalizes the current <see cref="SparseWeight8"/> by adding a complement weight
+        /// Normalizes the current <see cref="SparseWeight8"/> by adding a complementary weight
         /// at index <paramref name="complementIndex"/> that resolves <see cref="WeightSum"/> to 1.
         /// </summary>
-        /// <returns>A new <see cref="SparseWeight8"/> with an extra weight.</returns>
+        /// <returns>A new <see cref="SparseWeight8"/> with a complementary weight.</returns>
         internal SparseWeight8 GetNormalizedWithComplement(int complementIndex)
         {
             Span<IndexWeight> weights = stackalloc IndexWeight[8 + 1];

+ 49 - 3
src/SharpGLTF.Toolkit/Scenes/Content.cs

@@ -34,6 +34,12 @@ namespace SharpGLTF.Scenes
     {
         #region lifecycle
 
+        public StaticTransformer(IContent content, Matrix4x4 xform)
+        {
+            _Transform = xform;
+            _Target = content;
+        }
+
         public StaticTransformer(MESHBUILDER mesh, Matrix4x4 xform)
         {
             _Transform = xform;
@@ -71,6 +77,12 @@ namespace SharpGLTF.Scenes
     {
         #region lifecycle
 
+        public NodeTransformer(IContent content, NodeBuilder node)
+        {
+            _Node = node;
+            _Target = content;
+        }
+
         public NodeTransformer(MESHBUILDER mesh, NodeBuilder node)
         {
             _Node = node;
@@ -197,7 +209,7 @@ namespace SharpGLTF.Scenes
 
     // We really have two options here: Either implement this here, or as a derived of IMeshBuilder<MaterialBuilder>
 
-    class MorphModifier : IRenderableContent // must be a child of a controller, and the parent of a mesh
+    class MorphMeshModifier : IRenderableContent // must be a child of a controller, and the parent of a mesh
     {
         #region data
 
@@ -258,11 +270,45 @@ namespace SharpGLTF.Scenes
         }
     }
 
-    class CameraContent : IContent
+    class OrthographicCameraContent : IContent
     {
+        public OrthographicCameraContent(float xmag, float ymag, float znear, float zfar)
+        {
+            _XMag = xmag;
+            _YMag = ymag;
+            _ZNear = znear;
+            _ZFar = zfar;
+        }
+
+        private float _XMag;
+        private float _YMag;
+        private float _ZNear;
+        private float _ZFar;
+
         public void Setup(Node dstNode, Schema2SceneBuilder context)
         {
-            throw new NotImplementedException();
+            dstNode.WithOrthographicCamera(_XMag, _YMag, _ZNear, _ZFar);
+        }
+    }
+
+    class PerspectiveCameraContent : IContent
+    {
+        public PerspectiveCameraContent(float? aspectRatio, float fovy, float znear, float zfar = float.PositiveInfinity)
+        {
+            _AspectRatio = aspectRatio;
+            _FovY = fovy;
+            _ZNear = znear;
+            _ZFar = zfar;
+        }
+
+        float? _AspectRatio;
+        float _FovY;
+        float _ZNear;
+        float _ZFar;
+
+        public void Setup(Node dstNode, Schema2SceneBuilder context)
+        {
+            dstNode.WithPerspectiveCamera(_AspectRatio, _FovY, _ZNear, _ZFar);
         }
     }
 }

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

@@ -25,7 +25,7 @@ namespace SharpGLTF.Scenes
 
         #endregion
 
-        #region public
+        #region properties
 
         internal IContentRoot Content
         {

+ 121 - 0
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.Schema2.cs

@@ -136,6 +136,8 @@ namespace SharpGLTF.Scenes
 
     public partial class SceneBuilder
     {
+        #region from SceneBuilder to Schema2
+
         /// <summary>
         /// Converts this <see cref="SceneBuilder"/> instance into a <see cref="ModelRoot"/> instance.
         /// </summary>
@@ -151,5 +153,124 @@ namespace SharpGLTF.Scenes
 
             return dstModel;
         }
+
+        #endregion
+
+        #region from Schema2 to SceneBuilder
+
+        internal static SceneBuilder CreateFrom(Scene srcScene)
+        {
+            if (srcScene == null) return null;
+
+            var dstNodes = new Dictionary<Node, NodeBuilder>();
+
+            foreach (var srcArmature in srcScene.VisualChildren)
+            {
+                var dstArmature = new NodeBuilder();
+                CopyToNodeBuilder(srcArmature, dstArmature, dstNodes);
+            }
+
+            // TODO: we must also process the armatures of every skin, in case the joints are outside the scene.
+
+            var dstScene = new SceneBuilder();
+
+            // process meshes
+            var srcMeshInstances = Node.Flatten(srcScene).Where(item => item.Mesh != null).ToList();
+            _AddMeshInstances(dstScene, dstNodes, srcMeshInstances);
+
+            // process cameras
+            var srcCameraInstances = Node.Flatten(srcScene).Where(item => item.Camera != null).ToList();
+            _AddCameraInstances(dstScene, dstNodes, srcCameraInstances);
+
+            return dstScene;
+        }
+
+        private static void _AddMeshInstances(SceneBuilder dstScene, IReadOnlyDictionary<Node, NodeBuilder> dstNodes, IReadOnlyList<Node> srcInstances)
+        {
+            var dstMeshes = srcInstances
+                            .Select(item => item.Mesh)
+                            .Distinct()
+                            .ToDictionary(item => item, item => item.ToMeshBuilder());
+
+            foreach (var srcInstance in srcInstances)
+            {
+                var dstMesh = dstMeshes[srcInstance.Mesh];
+
+                if (srcInstance.Skin == null)
+                {
+                    var dstNode = dstNodes[srcInstance];
+                    dstScene.AddMesh(dstMesh, dstNode);
+                }
+                else
+                {
+                    var joints = new (NodeBuilder, Matrix4x4)[srcInstance.Skin.JointsCount];
+
+                    for (int i = 0; i < joints.Length; ++i)
+                    {
+                        var j = srcInstance.Skin.GetJoint(i);
+                        joints[i] = (dstNodes[j.Item1], j.Item2);
+                    }
+
+                    dstScene.AddSkinnedMesh(dstMesh, joints);
+                }
+            }
+        }
+
+        private static void _AddCameraInstances(SceneBuilder dstScene, IReadOnlyDictionary<Node, NodeBuilder> dstNodes, IReadOnlyList<Node> srcInstances)
+        {
+            if (srcInstances.Count == 0) return;
+
+            foreach (var srcInstance in srcInstances)
+            {
+                var dstNode = dstNodes[srcInstance];
+                var cam = srcInstance.Camera;
+
+                if (cam.Settings is CameraPerspective perspective)
+                {
+                    dstScene.AddPerspectiveCamera(dstNode, perspective.AspectRatio, perspective.VerticalFOV, perspective.ZNear, perspective.ZFar);
+                }
+
+                if (cam.Settings is CameraOrthographic orthographic)
+                {
+                    dstScene.AddOrthographicCamera(dstNode, orthographic.XMag, orthographic.YMag, orthographic.ZNear, orthographic.ZFar);
+                }
+            }
+        }
+
+        private static void CopyToNodeBuilder(Node srcNode, NodeBuilder dstNode, IDictionary<Node, NodeBuilder> nodeMapping)
+        {
+            Guard.NotNull(srcNode, nameof(srcNode));
+            Guard.NotNull(dstNode, nameof(dstNode));
+
+            dstNode.Name = srcNode.Name;
+            dstNode.LocalTransform = srcNode.LocalTransform;
+
+            foreach (var anim in srcNode.LogicalParent.LogicalAnimations)
+            {
+                var name = anim.Name;
+                if (string.IsNullOrWhiteSpace(name)) name = anim.LogicalIndex.ToString(System.Globalization.CultureInfo.InvariantCulture);
+
+                var scaAnim = anim.FindScaleSampler(srcNode)?.CreateCurveSampler();
+                if (scaAnim != null) dstNode.UseScale(name).SetCurve(scaAnim);
+
+                var rotAnim = anim.FindRotationSampler(srcNode)?.CreateCurveSampler();
+                if (rotAnim != null) dstNode.UseRotation(name).SetCurve(rotAnim);
+
+                var traAnim = anim.FindTranslationSampler(srcNode)?.CreateCurveSampler();
+                if (traAnim != null) dstNode.UseTranslation(name).SetCurve(traAnim);
+            }
+
+            if (nodeMapping == null) return;
+
+            nodeMapping[srcNode] = dstNode;
+
+            foreach (var srcChild in srcNode.VisualChildren)
+            {
+                var dstChild = dstNode.CreateNode();
+                CopyToNodeBuilder(srcChild, dstChild, nodeMapping);
+            }
+        }
+
+        #endregion
     }
 }

+ 20 - 2
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.cs

@@ -3,10 +3,10 @@ using System.Collections.Generic;
 using System.Numerics;
 using System.Text;
 
+using MESHBUILDER = SharpGLTF.Geometry.IMeshBuilder<SharpGLTF.Materials.MaterialBuilder>;
+
 namespace SharpGLTF.Scenes
 {
-    using MESHBUILDER = Geometry.IMeshBuilder<Materials.MaterialBuilder>;
-
     public partial class SceneBuilder
     {
         #region data
@@ -65,6 +65,24 @@ namespace SharpGLTF.Scenes
             return instance;
         }
 
+        public InstanceBuilder AddOrthographicCamera(NodeBuilder node, float xmag, float ymag, float znear, float zfar)
+        {
+            var content = new OrthographicCameraContent(xmag, ymag, znear, zfar);
+            var instance = new InstanceBuilder(this);
+            instance.Content = new NodeTransformer(content, node);
+            _Instances.Add(instance);
+            return instance;
+        }
+
+        public InstanceBuilder AddPerspectiveCamera(NodeBuilder node, float? aspectRatio, float fovy, float znear, float zfar = float.PositiveInfinity)
+        {
+            var content = new PerspectiveCameraContent(aspectRatio, fovy, znear, zfar);
+            var instance = new InstanceBuilder(this);
+            instance.Content = new NodeTransformer(content, node);
+            _Instances.Add(instance);
+            return instance;
+        }
+
         #endregion
     }
 }

+ 20 - 80
src/SharpGLTF.Toolkit/Schema2/SceneExtensions.cs

@@ -74,6 +74,8 @@ namespace SharpGLTF.Schema2
         {
             Guard.NotNull(node, nameof(node));
 
+            foreach (var j in joints) Guard.MustShareLogicalParent(node, j, nameof(joints));
+
             var skin = node.LogicalParent.CreateSkin();
             skin.BindJoints(meshPoseTransform, joints);
 
@@ -85,6 +87,12 @@ namespace SharpGLTF.Schema2
         {
             Guard.NotNull(node, nameof(node));
 
+            foreach (var j in joints)
+            {
+                Guard.MustShareLogicalParent(node, j.Item1, nameof(joints));
+                Guard.IsTrue(Matrix4x4.Invert(j.Item2, out Matrix4x4 r), nameof(joints), "Invalid Matrix");
+            }
+
             var skin = node.LogicalParent.CreateSkin();
             skin.BindJoints(joints);
 
@@ -115,7 +123,11 @@ namespace SharpGLTF.Schema2
             Guard.NotNull(joints, nameof(joints));
             Guard.MustShareLogicalParent(node, mesh, nameof(mesh));
 
-            foreach (var j in joints) Guard.MustShareLogicalParent(node, j.Item1, nameof(joints));
+            foreach (var j in joints)
+            {
+                Guard.MustShareLogicalParent(node, j.Item1, nameof(joints));
+                Guard.IsTrue(Matrix4x4.Invert(j.Item2, out Matrix4x4 r), nameof(joints), "Invalid Matrix");
+            }
 
             // TODO: the joints must be visible in the visual tree that contains node.
 
@@ -126,6 +138,9 @@ namespace SharpGLTF.Schema2
 
         public static Node WithPerspectiveCamera(this Node node, float? aspectRatio, float fovy, float znear, float zfar = float.PositiveInfinity)
         {
+            Guard.NotNull(node, nameof(node));
+            CameraPerspective.CheckParameters(aspectRatio, fovy, znear, zfar);
+
             var camera = node.LogicalParent.CreateCamera();
             camera.SetPerspectiveMode(aspectRatio, fovy, znear, zfar);
 
@@ -136,6 +151,9 @@ namespace SharpGLTF.Schema2
 
         public static Node WithOrthographicCamera(this Node node, float xmag, float ymag, float znear, float zfar)
         {
+            Guard.NotNull(node, nameof(node));
+            CameraOrthographic.CheckParameters(xmag, ymag, znear, zfar);
+
             var camera = node.LogicalParent.CreateCamera();
             camera.SetOrthographicMode(xmag, ymag, znear, zfar);
 
@@ -226,85 +244,7 @@ namespace SharpGLTF.Schema2
 
         public static Scenes.SceneBuilder ToSceneBuilder(this Scene srcScene)
         {
-            if (srcScene == null) return null;
-
-            var dstNodes = new Dictionary<Node, Scenes.NodeBuilder>();
-
-            foreach (var srcArmature in srcScene.VisualChildren)
-            {
-                var dstArmature = new Scenes.NodeBuilder();
-                srcArmature.CopyToNodeBuilder(dstArmature, dstNodes);
-            }
-
-            var srcInstances = Node.Flatten(srcScene).Where(item => item.Mesh != null).ToList();
-
-            // TODO: we must process the armatures of the skin, in case the joints are outside the scene.
-
-            var dstMeshes = srcInstances
-                .Select(item => item.Mesh)
-                .Distinct()
-                .ToDictionary(item => item, item => item.ToMeshBuilder());
-
-            var dstScene = new Scenes.SceneBuilder();
-
-            foreach (var srcInstance in srcInstances)
-            {
-                var dstMesh = dstMeshes[srcInstance.Mesh];
-
-                if (srcInstance.Skin == null)
-                {
-                    var dstNode = dstNodes[srcInstance];
-                    dstScene.AddMesh(dstMesh, dstNode);
-                }
-                else
-                {
-                    var joints = new (Scenes.NodeBuilder, Matrix4x4)[srcInstance.Skin.JointsCount];
-
-                    for (int i = 0; i < joints.Length; ++i)
-                    {
-                        var j = srcInstance.Skin.GetJoint(i);
-                        joints[i] = (dstNodes[j.Item1], j.Item2);
-                    }
-
-                    dstScene.AddSkinnedMesh(dstMesh, joints);
-                }
-            }
-
-            return dstScene;
-        }
-
-        public static void CopyToNodeBuilder(this Node srcNode, Scenes.NodeBuilder dstNode,  IDictionary<Node, Scenes.NodeBuilder> nodeMapping)
-        {
-            Guard.NotNull(srcNode, nameof(srcNode));
-            Guard.NotNull(dstNode, nameof(dstNode));
-
-            dstNode.Name = srcNode.Name;
-            dstNode.LocalTransform = srcNode.LocalTransform;
-
-            foreach (var anim in srcNode.LogicalParent.LogicalAnimations)
-            {
-                var name = anim.Name;
-                if (string.IsNullOrWhiteSpace(name)) name = anim.LogicalIndex.ToString(System.Globalization.CultureInfo.InvariantCulture);
-
-                var scaAnim = anim.FindScaleSampler(srcNode)?.CreateCurveSampler();
-                if (scaAnim != null) dstNode.UseScale(name).SetCurve(scaAnim);
-
-                var rotAnim = anim.FindRotationSampler(srcNode)?.CreateCurveSampler();
-                if (rotAnim != null) dstNode.UseRotation(name).SetCurve(rotAnim);
-
-                var traAnim = anim.FindTranslationSampler(srcNode)?.CreateCurveSampler();
-                if (traAnim != null) dstNode.UseTranslation(name).SetCurve(traAnim);
-            }
-
-            if (nodeMapping == null) return;
-
-            nodeMapping[srcNode] = dstNode;
-
-            foreach (var srcChild in srcNode.VisualChildren)
-            {
-                var dstChild = dstNode.CreateNode();
-                srcChild.CopyToNodeBuilder(dstChild, nodeMapping);
-            }
+            return Scenes.SceneBuilder.CreateFrom(srcScene);
         }
 
         #endregion

+ 46 - 42
tests/SharpGLTF.Tests/Schema2/LoadAndSave/LoadSampleTests.cs

@@ -8,7 +8,7 @@ using NUnit.Framework;
 namespace SharpGLTF.Schema2.LoadAndSave
 {
     /// <summary>
-    /// Test cases for models found in <see href="https://github.com/KhronosGroup/glTF-Sample-Models"/>
+    /// Test cases for models found in <see href="https://github.com/KhronosGroup/glTF-Sample-Models"/> and more....
     /// </summary>
     [TestFixture]
     [Category("Model Load and Save")]
@@ -21,39 +21,10 @@ namespace SharpGLTF.Schema2.LoadAndSave
         {
             TestFiles.DownloadReferenceModels();
         }
-
+        
         #endregion
 
-        [TestCase("\\glTF\\")]
-        // [TestCase("\\glTF-Draco\\")] // Not supported
-        [TestCase("\\glTF-IBL\\")]
-        [TestCase("\\glTF-Binary\\")]
-        [TestCase("\\glTF-Embedded\\")]
-        [TestCase("\\glTF-pbrSpecularGlossiness\\")]
-        public void LoadSampleModels(string section)
-        {
-            TestContext.CurrentContext.AttachShowDirLink();
-            TestContext.CurrentContext.AttachGltfValidatorLinks();
-
-            foreach (var f in TestFiles.GetSampleModelsPaths())
-            {
-                if (!f.Contains(section)) continue;
-
-                _LoadModel(f);
-            }
-        }
-
-        [Test]
-        public void LoadBabylonJsModels()
-        {
-            TestContext.CurrentContext.AttachShowDirLink();
-            TestContext.CurrentContext.AttachGltfValidatorLinks();
-
-            foreach (var f in TestFiles.GetBabylonJSModelsPaths())
-            {
-                _LoadModel(f);
-            }
-        }
+        #region helpers
 
         private static void _LoadModel(string f)
         {
@@ -66,14 +37,14 @@ namespace SharpGLTF.Schema2.LoadAndSave
                 model = ModelRoot.Load(f);
                 Assert.NotNull(model);
             }
-            catch(Exception ex)
+            catch (Exception ex)
             {
                 TestContext.Progress.WriteLine($"Failed {f.ToShortDisplayPath()}");
 
                 Assert.Fail(ex.Message);
             }
-            
-            
+
+
 
             var perf_load = perf.ElapsedMilliseconds;
 
@@ -106,7 +77,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
             var aa = a.GetLogicalChildrenFlattened().ToList();
             var bb = b.GetLogicalChildrenFlattened().ToList();
 
-            Assert.AreEqual(aa.Count,bb.Count);
+            Assert.AreEqual(aa.Count, bb.Count);
 
             CollectionAssert.AreEqual
                 (
@@ -115,10 +86,43 @@ namespace SharpGLTF.Schema2.LoadAndSave
                 );
         }
 
+        #endregion
+
+        [TestCase("\\glTF\\")]
+        // [TestCase("\\glTF-Draco\\")] // Not supported
+        [TestCase("\\glTF-IBL\\")]
+        [TestCase("\\glTF-Binary\\")]
+        [TestCase("\\glTF-Embedded\\")]
+        [TestCase("\\glTF-pbrSpecularGlossiness\\")]
+        public void LoadModelsFromKhronosSamples(string section)
+        {
+            TestContext.CurrentContext.AttachShowDirLink();
+            TestContext.CurrentContext.AttachGltfValidatorLinks();
+
+            foreach (var f in TestFiles.GetSampleModelsPaths())
+            {
+                if (!f.Contains(section)) continue;
+
+                _LoadModel(f);
+            }
+        }
+
+        [Test]
+        public void LoadModelsFromBabylonJs()
+        {
+            TestContext.CurrentContext.AttachShowDirLink();
+            TestContext.CurrentContext.AttachGltfValidatorLinks();
+
+            foreach (var f in TestFiles.GetBabylonJSModelsPaths())
+            {
+                _LoadModel(f);
+            }
+        }
+
         [TestCase("SpecGlossVsMetalRough.gltf")]
         [TestCase(@"TextureTransformTest.gltf")]
         [TestCase(@"UnlitTest\glTF-Binary\UnlitTest.glb")]        
-        public void LoadExtendedModels(string filePath)
+        public void LoadModelsWithExtensions(string filePath)
         {
             TestContext.CurrentContext.AttachShowDirLink();
             TestContext.CurrentContext.AttachGltfValidatorLinks();
@@ -142,7 +146,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         }
 
         [Test]
-        public void LoadUnlitModel()
+        public void LoadModelWithUnlitMaterial()
         {
             var f = TestFiles
                 .GetSampleModelsPaths()
@@ -161,7 +165,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         }
 
         [Test]
-        public void LoadLightsModel()
+        public void LoadModelWithLights()
         {
             var f = TestFiles
                 .GetSchemaExtensionsModelsPaths()
@@ -177,7 +181,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         }
 
         [Test]
-        public void LoadSparseModel()
+        public void LoadModelWithSparseAccessor()
         {
             var path = TestFiles
                 .GetSampleModelsPaths()
@@ -196,7 +200,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         }
 
         [Test]
-        public void LoadMorphTargetModel()
+        public void LoadModelWithMorphTargets()
         {
             TestContext.CurrentContext.AttachShowDirLink();
 
@@ -223,7 +227,7 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [TestCase("CesiumMan.glb")]
         [TestCase("Monster.glb")]
         [TestCase("BrainStem.glb")]
-        public void LoadAnimatedModels(string path)
+        public void LoadModelsWithAnimations(string path)
         {
             TestContext.CurrentContext.AttachShowDirLink();
 

+ 7 - 4
tests/SharpGLTF.Tests/TestFiles.cs

@@ -21,7 +21,8 @@ namespace SharpGLTF
             _SchemaDir = System.IO.Path.Combine(workingDir, "glTF-Schema");
             _SampleModelsDir = System.IO.Path.Combine(workingDir, "glTF-Sample-Models");
             _PollyModelsDir = System.IO.Path.Combine(workingDir, "glTF-Blender-Exporter");
-            _BabylonJsDir = System.IO.Path.Combine(workingDir, "BabylonJS-MeshesLibrary");
+            _BabylonJsMeshesDir = System.IO.Path.Combine(workingDir, "BabylonJS-MeshesLibrary");
+            _BabylonJsPlaygroundDir = System.IO.Path.Combine(workingDir, "BabylonJS-PlaygroundScenes");
         }
 
         public static void DownloadReferenceModels()
@@ -39,7 +40,8 @@ namespace SharpGLTF
             DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Sample-Models.git", _SampleModelsDir);
             DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF-Blender-Exporter.git", _PollyModelsDir);            
             DownloadUtils.SyncronizeGitRepository("https://github.com/KhronosGroup/glTF.git", _SchemaDir);
-            DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/MeshesLibrary.git", _BabylonJsDir);
+            DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/MeshesLibrary.git", _BabylonJsMeshesDir);
+            // DownloadUtils.SyncronizeGitRepository("https://github.com/BabylonJS/Babylon.js.git", _BabylonJsPlaygroundDir);
 
             TestContext.Progress.WriteLine("... Download Completed.");
         }
@@ -53,7 +55,8 @@ namespace SharpGLTF
         private static readonly string _SchemaDir;
         private static readonly string _SampleModelsDir;
         private static readonly string _PollyModelsDir;
-        private static readonly string _BabylonJsDir;
+        private static readonly string _BabylonJsMeshesDir;
+        private static readonly string _BabylonJsPlaygroundDir;
 
         private static string _GeneratedModelsDir;        
 
@@ -115,7 +118,7 @@ namespace SharpGLTF
 
         public static IReadOnlyList<string> GetBabylonJSModelsPaths()
         {
-            var files = GetModelPathsInDirectory(_BabylonJsDir);
+            var files = GetModelPathsInDirectory(_BabylonJsMeshesDir);
 
             return files
                 .OrderBy(item => item)

+ 6 - 5
tests/SharpGLTF.Tests/Transforms/SparseWeight8Tests.cs

@@ -131,13 +131,14 @@ namespace SharpGLTF.Transforms
         [Test]
         public void TestSparseNormalization()
         {
-            var sparse1 = SparseWeight8.Create(0, 0, 0, 0, 0, 0.1f, 0.7f, 0, 0, 0, 0.1f);
-
-            var sparse1Nrm = sparse1.GetNormalizedWithComplement(int.MaxValue);            
+            var sparse1 = SparseWeight8
+                .Create(0, 0, 0, 0, 0, 0.1f, 0.7f, 0, 0, 0, 0.1f)
+                .GetNormalizedWithComplement(int.MaxValue);
+            
             Assert.AreEqual(0.1f, sparse1[5]);
             Assert.AreEqual(0.7f, sparse1[6]);
             Assert.AreEqual(0.1f, sparse1[10]);
-            Assert.AreEqual(0.1f, sparse1[int.MaxValue]);
+            Assert.AreEqual(0.1f, sparse1[int.MaxValue], 0.0000001f);
             Assert.AreEqual(1, sparse1.WeightSum);
         }
 
@@ -157,7 +158,7 @@ namespace SharpGLTF.Transforms
         public void TestSparseWeightsLinearInterpolation1()
         {
             var x = SparseWeight8.Create(0,0,1,2); CollectionAssert.AreEqual(new[] { 0f, 0f, 1f, 2f }, x.Expand(4));
-            var y = SparseWeight8.Create(1,2,0,0); CollectionAssert.AreEqual(new[] { 1f, 2f, 0f, 0f }, x.Expand(4));
+            var y = SparseWeight8.Create(1,2,0,0); CollectionAssert.AreEqual(new[] { 1f, 2f, 0f, 0f }, y.Expand(4));
 
             var z = SparseWeight8.InterpolateLinear(x, y, 0.5f);
             Assert.AreEqual(0.5f, z[0]);