Browse Source

Clarified requirements for rigid mesh morph targets
fixed tests

Vicente Penades 3 years ago
parent
commit
dfe61c49b3

+ 1 - 1
src/SharpGLTF.Core/SharpGLTF.Core.csproj

@@ -29,7 +29,7 @@
     <Compile Include="..\Shared\_Extensions.cs" Link="_Extensions.cs" />
   </ItemGroup>  
   
-  <ItemGroup Condition=" '$(TargetFramework)' != 'net5.0' AND  '$(TargetFramework)' != 'net6.0'">    
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'netstandard2.1'">    
     <PackageReference Include="System.Text.Json" Version="5.0.2" />
   </ItemGroup>
 

+ 1 - 1
src/SharpGLTF.Toolkit/Animations/AnimatableProperty.cs

@@ -166,7 +166,7 @@ namespace SharpGLTF.Animations
             if (typeof(T) == typeof(Quaternion)) return (T)(Object)new Quaternion(elements[0], elements[1], elements[2], elements[3]);
 
             if (typeof(T) == typeof(Single[])) return (T)(Object)new ArraySegment<Single>(elements).ToArray();
-            if (typeof(T) == typeof(ArraySegment<Single>)) return (T)(Object)new ArraySegment<Single>(elements);
+            if (typeof(T) == typeof(ArraySegment<Single>)) return (T)(Object)new ArraySegment<Single>(elements.CloneArray());
             if (typeof(T) == typeof(Transforms.SparseWeight8)) return (T)(Object)Transforms.SparseWeight8.Create(elements);
 
             throw new NotSupportedException();

+ 27 - 0
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.cs

@@ -100,6 +100,12 @@ namespace SharpGLTF.Scenes
 
         #region API
 
+        /// <summary>
+        /// Adds a mesh instance to the scene, attached to an animatable <see cref="NodeBuilder"/>
+        /// </summary>
+        /// <param name="mesh">The mesh to add.</param>
+        /// <param name="node">The node to which the mesh will be attached.</param>
+        /// <returns>The instance representing this mesh-node pair.</returns>
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, NodeBuilder node)
         {
             Guard.NotNull(mesh, nameof(mesh));
@@ -113,6 +119,16 @@ namespace SharpGLTF.Scenes
             return instance;
         }
 
+        /// <summary>
+        /// Adds a mesh instance to the scene, at the given location.
+        /// </summary>
+        /// <param name="mesh">The mesh to add.</param>
+        /// <param name="meshWorldTransform">The location of the mesh.</param>
+        /// <returns>The instance representing this mesh.</returns>
+        /// <remarks>
+        /// Mesh instances with a fixed transform cannot be animated,
+        /// If you need morph animations, use <see cref="AddRigidMesh(MESHBUILDER, NodeBuilder)"/> instead.
+        /// </remarks>
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, Transforms.AffineTransform meshWorldTransform)
         {
             Guard.NotNull(mesh, nameof(mesh));
@@ -125,6 +141,17 @@ namespace SharpGLTF.Scenes
             return instance;
         }
 
+        /// <summary>
+        /// Adds a mesh instance to the scene, at the given location, relative to the given node.
+        /// </summary>
+        /// <param name="mesh">The mesh to add.</param>
+        /// <param name="node">The parent node.</param>
+        /// <param name="instanceTransform">The location of the mesh.</param>
+        /// <returns>The instance representing this mesh.</returns>
+        /// <remarks>
+        /// Mesh instances with a fixed transform cannot be animated,
+        /// If you need morph animations, use <see cref="AddRigidMesh(MESHBUILDER, NodeBuilder)"/> instead.
+        /// </remarks>
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, NodeBuilder node, Transforms.AffineTransform instanceTransform)
         {
             Guard.NotNull(mesh, nameof(mesh));

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

@@ -115,6 +115,8 @@ namespace SharpGLTF.Scenes
 
         public Animations.AnimatableProperty<ArraySegment<float>> UseMorphing()
         {
+            if (this is FixedTransformer) throw new InvalidOperationException($"Internal {nameof(FixedTransformer)} does not support animations. Use {nameof(SceneBuilder.AddRigidMesh)}(MeshBuilder mesh, NodeBuilder node) to add an animatable instance");
+
             if (_Morphings == null)
             {
                 _Morphings = new Animations.AnimatableProperty<ArraySegment<float>>();

+ 23 - 6
tests/SharpGLTF.Core.Tests/Schema2/LoadAndSave/RegressionTests.cs

@@ -15,17 +15,34 @@ namespace SharpGLTF.Schema2.LoadAndSave
         [Test]
         public void LoadSuzanneTest()
         {
-            var path = TestFiles.GetSampleModelsPaths().First(item => item.EndsWith("Suzanne.gltf"));
+            var path1 = TestFiles.GetSampleModelsPaths().First(item => item.EndsWith("Suzanne.gltf"));
 
-            var suzanne1 = ModelRoot.Load(path, ValidationMode.TryFix);
+            var suzanne1 = ModelRoot.Load(path1, ValidationMode.TryFix);
+            var suzanne1Mem = suzanne1.LogicalBuffers.Sum(item => item.Content.Length);
 
-            path = suzanne1.AttachToCurrentTest("suzanne.glb");
+            // direct save-load
 
-            var suzanne2 = ModelRoot.Load(path);
+            var path2 = suzanne1
+                .AttachToCurrentTest("suzanne2.glb");            
 
+            var suzanne2 = ModelRoot.Load(path2);
+            var suzanne2Mem = suzanne1.LogicalBuffers.Sum(item => item.Content.Length);
+
+            Assert.AreEqual(suzanne1Mem, suzanne2Mem);
             Assert.AreEqual(suzanne1.LogicalMeshes.Count, suzanne2.LogicalMeshes.Count);
 
-            Assert.Less( new System.IO.FileInfo(path).Length, 1024*512);
-        }
+            // scenebuilder roundtrip
+
+            var path3 = Scenes.SceneBuilder
+                .CreateFrom(suzanne1.DefaultScene)
+                .ToGltf2()
+                .AttachToCurrentTest("suzanne.glb");
+
+            var suzanne3 = ModelRoot.Load(path3);
+            var suzanne3Mem = suzanne1.LogicalBuffers.Sum(item => item.Content.Length);
+
+            Assert.AreEqual(suzanne1Mem, suzanne3Mem);
+            Assert.AreEqual(suzanne1.LogicalMeshes.Count, suzanne3.LogicalMeshes.Count);
+        }        
     }
 }

+ 24 - 10
tests/SharpGLTF.Toolkit.Tests/Scenes/SceneBuilderTests.cs

@@ -439,7 +439,7 @@ namespace SharpGLTF.Scenes
             scene.AttachToCurrentTest("skinned.gltf");
         }
 
-        [Test]
+        [Test(Description = "Creates a morph animated cube")]
         public void CreateAllAnimationTypesScene()
         {
             // 3D View 7.1908.9012.0 has an issue displaying off-center meshes with animated morph targets.
@@ -453,30 +453,38 @@ namespace SharpGLTF.Scenes
                 .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1));
 
             var yellow = new MaterialBuilder("material2")
-                .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 1, 0, 1));
-
-            var scene = new SceneBuilder();
+                .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 1, 0, 1));            
 
             var mesh1 = VPOSNRM.CreateCompatibleMesh("shape1");
-            mesh1.AddCube(MaterialBuilder.CreateDefault(), Matrix4x4.Identity);
-            var inst1 = scene.AddRigidMesh(mesh1, Matrix4x4.Identity);
+            mesh1.AddCube(pink, Matrix4x4.Identity);            
 
             var mesh2 = VPOSNRM.CreateCompatibleMesh("shape2");
-            mesh2.AddCube(pink, Matrix4x4.Identity);
-            var inst2 = scene.AddRigidMesh(mesh2, Matrix4x4.CreateTranslation(2, 0, 0));
+            mesh2.AddCube(yellow, Matrix4x4.Identity);            
+
+            var scene = new SceneBuilder();            
+
+            var inst1 = scene.AddRigidMesh(mesh1, Matrix4x4.Identity);
+
+            // meshes intended to support animation must be created using an armature
+            var armature = new NodeBuilder();
+            armature.LocalTransform = Matrix4x4.CreateTranslation(2, 0, 0);
+            var inst2 = scene.AddRigidMesh(mesh2, armature); 
 
             scene.AttachToCurrentTest("static.glb");
             scene.AttachToCurrentTest("static.gltf");
 
-            var morphBuilder = mesh2.UseMorphTarget(0);
+            // up to this point, the scene has two plain unanimated cubes.
 
+            var morphBuilder = mesh2.UseMorphTarget(0);
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(0), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(1), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(2), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(3), (Vector3.UnitY, Vector3.Zero));
 
+            // set default value.
             inst2.Content.UseMorphing().SetValue(1);
             
+            // ser animation curve.
             var curve = inst2.Content.UseMorphing().UseTrackBuilder("Default");
             curve.SetPoint(0, true, 0);
             curve.SetPoint(1, true, 1);
@@ -484,7 +492,13 @@ namespace SharpGLTF.Scenes
 
             var gltf = scene.ToGltf2();
 
-            // Assert.AreEqual(1, gltf.LogicalMeshes[1].MorphWeights[0]);
+            TestContext.WriteLine(gltf.GetJsonPreview());
+
+            var meshIdx = 1;
+
+            Assert.AreEqual(1, gltf.LogicalMeshes[meshIdx].Primitives[0].MorphTargetsCount);
+            Assert.AreEqual(1, gltf.LogicalMeshes[meshIdx].MorphWeights[0]);
+            Assert.AreEqual(1, gltf.LogicalAnimations.Count);
 
             scene.AttachToCurrentTest("mopth.glb");
             scene.AttachToCurrentTest("mopth.gltf");