Browse Source

Merge branch 'master' of https://github.com/vpenades/SharpGLTF

Vicente Penades 3 years ago
parent
commit
5b0b7a73a0

+ 11 - 5
src/SharpGLTF.Core/Schema2/Serialization.WriteContext.cs

@@ -118,7 +118,7 @@ namespace SharpGLTF.Schema2
             // Binary settings should allow BufferView and SatelliteFile ImageWriting modes:
             // Binary settings should allow BufferView and SatelliteFile ImageWriting modes:
 
 
             if (ImageWriting == ResourceWriteMode.Default) ImageWriting = ResourceWriteMode.BufferView;
             if (ImageWriting == ResourceWriteMode.Default) ImageWriting = ResourceWriteMode.BufferView;
-            if (ImageWriting == ResourceWriteMode.Embedded) ImageWriting = ResourceWriteMode.BufferView;
+            if (ImageWriting == ResourceWriteMode.EmbeddedAsBase64) ImageWriting = ResourceWriteMode.BufferView;
 
 
             MergeBuffers = true;
             MergeBuffers = true;
             JsonIndented = false;
             JsonIndented = false;
@@ -205,12 +205,15 @@ namespace SharpGLTF.Schema2
             Guard.NotNullOrEmpty(baseName, nameof(baseName));
             Guard.NotNullOrEmpty(baseName, nameof(baseName));
             Guard.NotNull(model, nameof(model));
             Guard.NotNull(model, nameof(model));
 
 
-            model = this._PreprocessSchema2(model, this.ImageWriting == ResourceWriteMode.BufferView, this.MergeBuffers, this.BuffersMaxSize);
+            // merge images when explicitly requested.
+            var mergeImages = this.ImageWriting == ResourceWriteMode.BufferView;
+
+            model = this._PreprocessSchema2(model, mergeImages, this.MergeBuffers, this.BuffersMaxSize);
             Guard.NotNull(model, nameof(model));
             Guard.NotNull(model, nameof(model));
 
 
             model._PrepareBuffersForSatelliteWriting(this, baseName);
             model._PrepareBuffersForSatelliteWriting(this, baseName);
 
 
-            model._PrepareImagesForWriting(this, baseName, ResourceWriteMode.SatelliteFile);
+            model._PrepareImagesForWriting(this, baseName, false, ResourceWriteMode.SatelliteFile);
 
 
             _ValidateBeforeWriting(model);
             _ValidateBeforeWriting(model);
 
 
@@ -234,7 +237,10 @@ namespace SharpGLTF.Schema2
             Guard.NotNullOrEmpty(baseName, nameof(baseName));
             Guard.NotNullOrEmpty(baseName, nameof(baseName));
             Guard.NotNull(model, nameof(model));
             Guard.NotNull(model, nameof(model));
 
 
-            model = this._PreprocessSchema2(model, this.ImageWriting == ResourceWriteMode.BufferView, true, int.MaxValue);
+            // merge images for all cases except for satellite files
+            var mergeImages = this.ImageWriting != ResourceWriteMode.SatelliteFile;
+
+            model = this._PreprocessSchema2(model, mergeImages, true, int.MaxValue);
             Guard.NotNull(model, nameof(model));
             Guard.NotNull(model, nameof(model));
 
 
             var ex = _BinarySerialization.IsBinaryCompatible(model);
             var ex = _BinarySerialization.IsBinaryCompatible(model);
@@ -242,7 +248,7 @@ namespace SharpGLTF.Schema2
 
 
             model._PrepareBuffersForInternalWriting();
             model._PrepareBuffersForInternalWriting();
 
 
-            model._PrepareImagesForWriting(this, baseName, ResourceWriteMode.Embedded);
+            model._PrepareImagesForWriting(this, baseName, true, ResourceWriteMode.BufferView);
 
 
             _ValidateBeforeWriting(model);
             _ValidateBeforeWriting(model);
 
 

+ 18 - 3
src/SharpGLTF.Core/Schema2/Serialization.WriteSettings.cs

@@ -23,9 +23,13 @@ namespace SharpGLTF.Schema2
         SatelliteFile,
         SatelliteFile,
 
 
         /// <summary>
         /// <summary>
-        /// Resources will be embedded into the JSON encoded in MIME64.
+        /// Resources will be embedded into the JSON encoded in Base64.
         /// </summary>
         /// </summary>
-        Embedded,
+        /// <remarks>
+        /// When writing to GLB this does not have any effect.<br/>
+        /// This flag only has effect with images, not with binary blobs.
+        /// </remarks>
+        EmbeddedAsBase64,
 
 
         /// <summary>
         /// <summary>
         /// Resources will be stored as internal binary buffers. Valid only for <see cref="Image"/>
         /// Resources will be stored as internal binary buffers. Valid only for <see cref="Image"/>
@@ -342,10 +346,21 @@ namespace SharpGLTF.Schema2
             }
             }
         }
         }
 
 
-        internal void _PrepareImagesForWriting(WriteContext context, string baseName, ResourceWriteMode rmode)
+        internal void _PrepareImagesForWriting(WriteContext context, string baseName, bool isBinary, ResourceWriteMode rmode)
         {
         {
             if (context.ImageWriting != ResourceWriteMode.Default) rmode = context.ImageWriting;
             if (context.ImageWriting != ResourceWriteMode.Default) rmode = context.ImageWriting;
 
 
+            if (rmode == ResourceWriteMode.Default) throw new InvalidOperationException(nameof(ResourceWriteMode) + " is not set");
+
+            if (isBinary)
+            {
+                if (rmode == ResourceWriteMode.EmbeddedAsBase64) throw new InvalidOperationException(nameof(ResourceWriteMode.EmbeddedAsBase64) + " not supported when writing binary GLB.");
+            }
+            else
+            {
+                if (rmode == ResourceWriteMode.BufferView) throw new InvalidOperationException(nameof(ResourceWriteMode.BufferView) + " not supported when writing text glTF.");
+            }
+
             // setup all images to be written to the appropiate location.
             // setup all images to be written to the appropiate location.
             for (int i = 0; i < this._images.Count; ++i)
             for (int i = 0; i < this._images.Count; ++i)
             {
             {

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

@@ -29,7 +29,7 @@
     <Compile Include="..\Shared\_Extensions.cs" Link="_Extensions.cs" />
     <Compile Include="..\Shared\_Extensions.cs" Link="_Extensions.cs" />
   </ItemGroup>  
   </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" />
     <PackageReference Include="System.Text.Json" Version="5.0.2" />
   </ItemGroup>
   </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(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(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);
             if (typeof(T) == typeof(Transforms.SparseWeight8)) return (T)(Object)Transforms.SparseWeight8.Create(elements);
 
 
             throw new NotSupportedException();
             throw new NotSupportedException();

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

@@ -100,6 +100,12 @@ namespace SharpGLTF.Scenes
 
 
         #region API
         #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)
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, NodeBuilder node)
         {
         {
             Guard.NotNull(mesh, nameof(mesh));
             Guard.NotNull(mesh, nameof(mesh));
@@ -113,6 +119,16 @@ namespace SharpGLTF.Scenes
             return instance;
             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)
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, Transforms.AffineTransform meshWorldTransform)
         {
         {
             Guard.NotNull(mesh, nameof(mesh));
             Guard.NotNull(mesh, nameof(mesh));
@@ -125,6 +141,17 @@ namespace SharpGLTF.Scenes
             return instance;
             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)
         public InstanceBuilder AddRigidMesh(MESHBUILDER mesh, NodeBuilder node, Transforms.AffineTransform instanceTransform)
         {
         {
             Guard.NotNull(mesh, nameof(mesh));
             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()
         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)
             if (_Morphings == null)
             {
             {
                 _Morphings = new Animations.AnimatableProperty<ArraySegment<float>>();
                 _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]
         [Test]
         public void LoadSuzanneTest()
         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.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);
+        }        
     }
     }
 }
 }

+ 1 - 1
tests/SharpGLTF.NUnit/SharpGLTF.NUnit.csproj

@@ -9,7 +9,7 @@
 
 
   <ItemGroup>    
   <ItemGroup>    
     <PackageReference Include="GltfValidator" Version="2.0.0-dev.3.5.202109201056" />    
     <PackageReference Include="GltfValidator" Version="2.0.0-dev.3.5.202109201056" />    
-    <PackageReference Include="nunit" Version="3.13.2" />
+    <PackageReference Include="nunit" Version="3.13.3" />
     <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
     <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 1 - 1
tests/SharpGLTF.ThirdParty.Tests/SharpGLTF.ThirdParty.Tests.csproj

@@ -12,7 +12,7 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <ItemGroup>
   <ItemGroup>
-    <PackageReference Include="NUnit" Version="3.13.2" />
+    <PackageReference Include="NUnit" Version="3.13.3" />
     <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
     <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />    
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />    
   </ItemGroup>
   </ItemGroup>

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

@@ -439,7 +439,7 @@ namespace SharpGLTF.Scenes
             scene.AttachToCurrentTest("skinned.gltf");
             scene.AttachToCurrentTest("skinned.gltf");
         }
         }
 
 
-        [Test]
+        [Test(Description = "Creates a morph animated cube")]
         public void CreateAllAnimationTypesScene()
         public void CreateAllAnimationTypesScene()
         {
         {
             // 3D View 7.1908.9012.0 has an issue displaying off-center meshes with animated morph targets.
             // 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));
                 .WithChannelParam(KnownChannel.BaseColor, KnownProperty.RGBA, new Vector4(1, 0, 1, 1));
 
 
             var yellow = new MaterialBuilder("material2")
             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");
             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");
             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.glb");
             scene.AttachToCurrentTest("static.gltf");
             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(0), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(1), (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(2), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(3), (Vector3.UnitY, Vector3.Zero));
             morphBuilder.SetVertexDelta(morphBuilder.Positions.ElementAt(3), (Vector3.UnitY, Vector3.Zero));
 
 
+            // set default value.
             inst2.Content.UseMorphing().SetValue(1);
             inst2.Content.UseMorphing().SetValue(1);
             
             
+            // ser animation curve.
             var curve = inst2.Content.UseMorphing().UseTrackBuilder("Default");
             var curve = inst2.Content.UseMorphing().UseTrackBuilder("Default");
             curve.SetPoint(0, true, 0);
             curve.SetPoint(0, true, 0);
             curve.SetPoint(1, true, 1);
             curve.SetPoint(1, true, 1);
@@ -484,7 +492,13 @@ namespace SharpGLTF.Scenes
 
 
             var gltf = scene.ToGltf2();
             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.glb");
             scene.AttachToCurrentTest("mopth.gltf");
             scene.AttachToCurrentTest("mopth.gltf");