Przeglądaj źródła

Fix bug with multiple primitives in glTF loader

Gary Hsu 7 lat temu
rodzic
commit
6816747274

Plik diff jest za duży
+ 9162 - 0
Playground/scenes/BrainStem/BrainStem.gltf


BIN
Playground/scenes/BrainStem/BrainStem0.bin


BIN
Playground/scenes/MultiPrimitive/MultiPrimitive.bin


+ 134 - 0
Playground/scenes/MultiPrimitive/MultiPrimitive.gltf

@@ -0,0 +1,134 @@
+{
+  "accessors": [
+    {
+      "bufferView": 0,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 1,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 2,
+      "componentType": 5125,
+      "count": 3,
+      "type": "SCALAR"
+    },
+    {
+      "bufferView": 3,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 4,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 5,
+      "componentType": 5125,
+      "count": 3,
+      "type": "SCALAR"
+    }
+  ],
+  "asset": {
+    "version": "2.0"
+  },
+  "buffers": [
+    {
+      "uri": "MultiPrimitive.bin",
+      "byteLength": 144
+    }
+  ],
+  "bufferViews": [
+    {
+      "buffer": 0,
+      "byteLength": 36
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 36,
+      "byteLength": 24
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 60,
+      "byteLength": 12
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 72,
+      "byteLength": 36
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 108,
+      "byteLength": 24
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 132,
+      "byteLength": 12
+    }
+  ],
+  "meshes": [
+    {
+      "primitives": [
+        {
+          "attributes": {
+            "POSITION": 0,
+            "TEXCOORD_0": 1
+          },
+          "indices": 2
+        },
+        {
+          "attributes": {
+            "POSITION": 3,
+            "TEXCOORD_0": 4
+          },
+          "indices": 5
+        }
+      ]
+    }
+  ],
+  "nodes": [
+    {
+      "name": "node",
+      "mesh": 0
+    }
+  ],
+  "scene": 0,
+  "scenes": [
+    {
+      "nodes": [
+        0
+      ]
+    }
+  ]
+}

+ 18 - 13
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -307,16 +307,15 @@ module BABYLON.GLTF2 {
             return Promise.all(promises).then(() => {});
         }
 
-        private _forEachNodeMesh(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
-            if (node._babylonMesh) {
-                callback(node._babylonMesh);
-            }
-
+        private _forEachPrimitive(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
             if (node._primitiveBabylonMeshes) {
                 for (const babylonMesh of node._primitiveBabylonMeshes) {
                     callback(babylonMesh);
                 }
             }
+            else {
+                callback(node._babylonMesh!);
+        }
         }
 
         private _getMeshes(): Mesh[] {
@@ -328,9 +327,15 @@ module BABYLON.GLTF2 {
             const nodes = this._gltf.nodes;
             if (nodes) {
                 for (const node of nodes) {
-                    this._forEachNodeMesh(node, mesh => {
-                        meshes.push(mesh);
-                    });
+                    if (node._babylonMesh) {
+                        meshes.push(node._babylonMesh);
+                }
+
+                    if (node._primitiveBabylonMeshes) {
+                        for (const babylonMesh of node._primitiveBabylonMeshes) {
+                            meshes.push(babylonMesh);
+            }
+                    }
                 }
             }
 
@@ -437,7 +442,7 @@ module BABYLON.GLTF2 {
                 node._primitiveBabylonMeshes = [];
                 for (const primitive of primitives) {
                     const primitiveBabylonMesh = new Mesh(`${mesh.name || babylonMesh.name}_${primitive._index}`, this._babylonScene, babylonMesh);
-                    node._primitiveBabylonMeshes.push(babylonMesh);
+                    node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                     promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, primitiveBabylonMesh));
                     this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 }
@@ -449,7 +454,7 @@ module BABYLON.GLTF2 {
             }
 
             return Promise.all(promises).then(() => {
-                this._forEachNodeMesh(node, babylonMesh => {
+                this._forEachPrimitive(node, babylonMesh => {
                     babylonMesh._refreshBoundingInfo(true);
                 });
             });
@@ -711,8 +716,8 @@ module BABYLON.GLTF2 {
 
         private _loadSkinAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, skin: ILoaderSkin): Promise<void> {
             const assignSkeleton = () => {
-                this._forEachNodeMesh(node, babylonMesh => {
-                    babylonMesh.skeleton = skin._babylonSkeleton;
+                this._forEachPrimitive(node, babylonMesh => {
+                    babylonMesh.skeleton = skin._babylonSkeleton!;
                 });
 
                 node._babylonMesh!.parent = this._rootBabylonMesh;
@@ -965,7 +970,7 @@ module BABYLON.GLTF2 {
                             outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                         })));
 
-                        this._forEachNodeMesh(targetNode, babylonMesh => {
+                        this._forEachPrimitive(targetNode, babylonMesh => {
                             const morphTarget = babylonMesh.morphTargetManager!.getTarget(targetIndex);
                             babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         });

+ 36 - 0
tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts

@@ -286,6 +286,42 @@ describe('Babylon Scene Loader', function () {
             return Promise.all(promises);
         });
 
+        it('Load MultiPrimitive', () => {
+            const scene = new BABYLON.Scene(subject);
+            return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/MultiPrimitive/", "MultiPrimitive.gltf", scene).then(result => {
+                expect(result.meshes, "meshes").to.have.lengthOf(4);
+
+                const node = scene.getMeshByName("node");
+                expect(node, "node").to.exist;
+                expect(node, "node").to.be.an.instanceof(BABYLON.Mesh);
+
+                const mesh = node as BABYLON.Mesh;
+                expect(mesh.geometry).to.not.exist;
+                expect(mesh.material).to.not.exist;
+
+                expect(mesh.getChildren(), "mesh children").to.have.lengthOf(2);
+                for (const childNode of mesh.getChildren()) {
+                    expect(childNode, "child node").to.be.an.instanceof(BABYLON.Mesh);
+                    const childMesh = childNode as BABYLON.Mesh;
+                    expect(childMesh.geometry).to.exist;
+                    expect(childMesh.material).to.exist;
+                }
+            });
+        });
+
+        it('Load BrainStem', () => {
+            const scene = new BABYLON.Scene(subject);
+            return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/BrainStem/", "BrainStem.gltf", scene).then(result => {
+                expect(result.skeletons, "skeletons").to.have.lengthOf(1);
+
+                const node1 = scene.getMeshByName("node1");
+                for (const childMesh of node1.getChildMeshes()) {
+                    expect(childMesh.skeleton, "mesh skeleton").to.exist;
+                    expect(childMesh.skeleton.name, "mesh skeleton name").to.equal(result.skeletons[0].name);
+                }
+            });
+        });
+
         // TODO: test animation group callback
         // TODO: test material instancing
         // TODO: test ImportMesh with specific node name