Explorar o código

Fixed empty nodes roundtrip from gtlf to scenebuilder and back

Vicente Penades %!s(int64=3) %!d(string=hai) anos
pai
achega
bbbce2c5f9

+ 33 - 3
src/SharpGLTF.Toolkit/Scenes/SceneBuilder.Schema2.cs

@@ -150,9 +150,11 @@ namespace SharpGLTF.Scenes
         {
             if (srcScenes == null) yield break;
 
+            srcScenes = srcScenes.Distinct();
+
             // gather shared mesh instances
 
-            var dstMeshIntances = _GatherMeshInstances(srcScenes.Distinct().SelectMany(s => Node.Flatten(s)));
+            var dstMeshIntances = _GatherMeshInstances(srcScenes.SelectMany(s => Node.Flatten(s)));
 
             // process each scene
 
@@ -162,7 +164,7 @@ namespace SharpGLTF.Scenes
             }
         }
 
-        private static SceneBuilder _CreateFrom(Scene srcScene, IReadOnlyDictionary<Node, MESHBUILDER> dstInstances)
+        private static SceneBuilder _CreateFrom(Scene srcScene, IReadOnlyDictionary<Node, MESHBUILDER> meshInstances)
         {
             // Process armatures
 
@@ -180,21 +182,37 @@ namespace SharpGLTF.Scenes
 
             dstScene.SetNameAndExtrasFrom(srcScene);
 
-            _AddMeshInstances(dstScene, Node.Flatten(srcScene), dstNodes, dstInstances);
+            // process mesh instances
+
+            _AddMeshInstances(dstScene, Node.Flatten(srcScene), dstNodes, meshInstances);
 
             // process cameras
+
             var srcCameraInstances = Node.Flatten(srcScene)
                 .Where(item => item.Camera != null)
                 .ToList();
 
             _AddCameraInstances(dstScene, dstNodes, srcCameraInstances);
 
+            // process lights
+
             var srcLightInstances = Node.Flatten(srcScene)
                 .Where(item => item.PunctualLight != null)
                 .ToList();
 
             _AddLightInstances(dstScene, dstNodes, srcCameraInstances);
 
+            // process empty nodes with at least name or extras
+
+            var emptyInstances = Node.Flatten(srcScene)
+                .Except(meshInstances.Keys)
+                .Except(srcCameraInstances)
+                .Except(srcLightInstances)
+                .Where(item => item.Name != null)
+                .ToList();
+
+            _AddEmptyInstances(dstScene, dstNodes, emptyInstances);
+
             #if DEBUG
             dstScene._VerifyConversion(srcScene);
             #endif
@@ -320,6 +338,18 @@ namespace SharpGLTF.Scenes
             }
         }
 
+        private static void _AddEmptyInstances(SceneBuilder dstScene, IReadOnlyDictionary<Node, NodeBuilder> dstNodes, IReadOnlyList<Node> srcInstances)
+        {
+            if (srcInstances.Count == 0) return;
+
+            foreach (var srcInstance in srcInstances)
+            {
+                var dstNode = dstNodes[srcInstance];
+                
+                dstScene.AddNode(dstNode);
+            }
+        }
+
         private static void _CopyToNodeBuilder(NodeBuilder dstNode, Node srcNode, IDictionary<Node, NodeBuilder> nodeMapping)
         {
             Guard.NotNull(srcNode, nameof(srcNode));

+ 21 - 0
tests/SharpGLTF.Toolkit.Tests/Scenes/SceneBuilderTests.cs

@@ -656,6 +656,27 @@ namespace SharpGLTF.Scenes
             Assert.Throws<SharpGLTF.Validation.SchemaException>(() => schema.SaveGLB(fileName));
         }
 
+        [Test]
+        public void TestEmptyNodeRoundtrip()
+        {
+            // create a scenebuilder with an empty node
+            var sb = new SceneBuilder();
+
+            sb.AddNode(new NodeBuilder()); // unnamed nodes will be optimized out
+            sb.AddNode(new NodeBuilder("Named"));            
+
+            var gltf = sb.ToGltf2();
+
+            Assert.AreEqual(2, gltf.LogicalNodes.Count);
+
+            // roundtrip
+            sb = SceneBuilder.CreateFrom(gltf.DefaultScene);
+
+            var instance = sb.Instances.FirstOrDefault(item => item.Name == "Named");
+
+            Assert.NotNull(instance);            
+        }
+
         [Test]
         public void CreateSceneWithEmptyMeshes()
         {