Przeglądaj źródła

Fix bug with MSFT_lod extension in glTF loader

Gary Hsu 7 lat temu
rodzic
commit
77465422b3

BIN
Playground/scenes/TwoQuads/LOD0.png


BIN
Playground/scenes/TwoQuads/LOD1.png


BIN
Playground/scenes/TwoQuads/LOD2.png


BIN
Playground/scenes/TwoQuads/TwoQuads.bin


+ 160 - 0
Playground/scenes/TwoQuads/TwoQuads.gltf

@@ -0,0 +1,160 @@
+{
+  "accessors": [
+    {
+      "bufferView": 0,
+      "componentType": 5126,
+      "count": 4,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 1,
+      "componentType": 5126,
+      "count": 4,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 2,
+      "componentType": 5125,
+      "count": 6,
+      "type": "SCALAR"
+    }
+  ],
+  "asset": {
+    "version": "2.0"
+  },
+  "buffers": [
+    {
+      "uri": "TwoQuads.bin",
+      "byteLength": 104
+    }
+  ],
+  "bufferViews": [
+    {
+      "buffer": 0,
+      "byteLength": 48
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 48,
+      "byteLength": 32
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 80,
+      "byteLength": 24
+    }
+  ],
+  "extensionsUsed": [
+    "MSFT_lod"
+  ],
+  "images": [
+    {
+      "uri": "LOD0.png"
+    },
+    {
+      "uri": "LOD1.png"
+    },
+    {
+      "uri": "LOD2.png"
+    }
+  ],
+  "materials": [
+    {
+      "name": "LOD0",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 0
+        },
+        "metallicFactor": 0
+      },
+      "extensions": {
+        "MSFT_lod": {
+          "ids": [
+            1,
+            2
+          ]
+        }
+      }
+    },
+    {
+      "name": "LOD1",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 1
+        },
+        "metallicFactor": 0
+      }
+    },
+    {
+      "name": "LOD2",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 2
+        },
+        "metallicFactor": 0
+      }
+    }
+  ],
+  "meshes": [
+    {
+      "primitives": [
+        {
+          "attributes": {
+            "POSITION": 0,
+            "TEXCOORD_0": 1
+          },
+          "indices": 2,
+          "material": 0
+        }
+      ]
+    }
+  ],
+  "nodes": [
+    {
+      "mesh": 0,
+      "translation": [
+        -0.55,
+        0,
+        0
+      ]
+    },
+    {
+      "mesh": 0,
+      "translation": [
+        0.55,
+        0,
+        0
+      ]
+    }
+  ],
+  "scene": 0,
+  "scenes": [
+    {
+      "nodes": [
+        0,
+        1
+      ]
+    }
+  ],
+  "textures": [
+    {
+      "source": 0
+    },
+    {
+      "source": 1
+    },
+    {
+      "source": 2
+    }
+  ]
+}

+ 17 - 6
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -33,7 +33,10 @@ module BABYLON.GLTF2.Extensions {
 
                     if (indexLOD !== 0) {
                         this._loadingNodeLOD = nodeLOD;
-                        this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
+
+                        if (!this._loadNodeSignals[nodeLOD._index]) {
+                            this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
+                        }
                     }
 
                     const promise = this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(() => {
@@ -44,8 +47,11 @@ module BABYLON.GLTF2.Extensions {
 
                         if (indexLOD !== nodeLODs.length - 1) {
                             const nodeIndex = nodeLODs[indexLOD + 1]._index;
-                            this._loadNodeSignals[nodeIndex].resolve();
-                            delete this._loadNodeSignals[nodeIndex];
+
+                            if (this._loadNodeSignals[nodeIndex]) {
+                                this._loadNodeSignals[nodeIndex].resolve();
+                                delete this._loadNodeSignals[nodeIndex];
+                            }
                         }
                     });
 
@@ -77,14 +83,19 @@ module BABYLON.GLTF2.Extensions {
 
                     if (indexLOD !== 0) {
                         this._loadingMaterialLOD = materialLOD;
-                        this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
+
+                        if (!this._loadMaterialSignals[materialLOD._index]) {
+                            this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
+                        }
                     }
 
                     const promise = this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(() => {
                         if (indexLOD !== materialLODs.length - 1) {
                             const materialIndex = materialLODs[indexLOD + 1]._index;
-                            this._loadMaterialSignals[materialIndex].resolve();
-                            delete this._loadMaterialSignals[materialIndex];
+                            if (this._loadMaterialSignals[materialIndex]) {
+                                this._loadMaterialSignals[materialIndex].resolve();
+                                delete this._loadMaterialSignals[materialIndex];
+                            }
                         }
                     });
 

+ 39 - 1
tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts

@@ -204,10 +204,48 @@ describe('Babylon Scene Loader', function () {
             });
         });
 
+        it('Load TwoQuads', () => {
+            const materials: { [name: string]: BABYLON.Material } = {};
+
+            const deferred = new BABYLON.Deferred();
+            BABYLON.SceneLoader.OnPluginActivatedObservable.add((loader: BABYLON.GLTFFileLoader) => {
+                loader.onMaterialLoaded = material => {
+                    expect(materials[material.name], `materials["${material.name}"]`).to.be.undefined;
+                    materials[material.name] = material;
+                };
+
+                loader.onComplete = () => {
+                    try {
+                        expect(materials["LOD0"].getActiveTextures().every(texture => texture.isReady()), "All textures of LOD 0 ready").to.be.true;
+                        expect(materials["LOD1"].getActiveTextures().every(texture => texture.isReady()), "All textures of LOD 1 ready").to.be.true;
+                        expect(materials["LOD2"].getActiveTextures().every(texture => texture.isReady()), "All textures of LOD 2 ready").to.be.true;
+                        deferred.resolve();
+                    }
+                    catch (e) {
+                        deferred.reject(e);
+                    }
+                };
+            }, undefined, undefined, undefined, true);
+
+            const scene = new BABYLON.Scene(subject);
+            const promise = BABYLON.SceneLoader.AppendAsync("/Playground/scenes/TwoQuads/", "TwoQuads.gltf", scene).then(() => {
+                expect(Object.keys(materials), "materials").to.have.lengthOf(3);
+
+                expect(materials["LOD0"].getActiveTextures(), "material LOD 0 active textures").to.have.lengthOf(1);
+                expect(materials["LOD1"].getActiveTextures(), "material LOD 1 active textures").to.have.lengthOf(1);
+                expect(materials["LOD2"].getActiveTextures(), "material LOD 2 active textures").to.have.lengthOf(1);
+
+                expect(materials["LOD0"].getActiveTextures().some(texture => texture.isReady()), "Some textures of LOD 0 ready").to.be.false;
+                expect(materials["LOD1"].getActiveTextures().some(texture => texture.isReady()), "Some textures of LOD 1 ready").to.be.false;
+                expect(materials["LOD2"].getActiveTextures().every(texture => texture.isReady()), "All textures of LOD 2 ready").to.be.true;
+            });
+
+            return Promise.all([promise, deferred.promise]);
+        });
+
         // TODO: test material instancing
         // TODO: test ImportMesh with specific node name
         // TODO: test KHR_materials_pbrSpecularGlossiness
-        // TODO: test MSFT_lod
         // TODO: test KHR_lights
     });