Explorar o código

Improve glTF LOD handling

Gary Hsu %!s(int64=7) %!d(string=hai) anos
pai
achega
b4293447e3

+ 2 - 2
inspector/src/tabs/GLTFTab.ts

@@ -159,8 +159,8 @@ module INSPECTOR {
                 defaults.extensions[extension.name] = extensionDefaults;
                 defaults.extensions[extension.name] = extensionDefaults;
             });
             });
 
 
-            const data = '{ "asset": { "version": "2.0" }, "scenes": [ { } ] }';
-            return loader.loadAsync(scene, data, "").then(() => {
+            const data = '{ "asset": { "version": "2.0" } }';
+            return loader.importMeshAsync([], scene, data, "").then(() => {
                 scene.dispose();
                 scene.dispose();
                 engine.dispose();
                 engine.dispose();
 
 

+ 44 - 61
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -32,29 +32,35 @@ module BABYLON.GLTF2.Extensions {
          */
          */
         public onMaterialLODsLoadedObservable = new Observable<number>();
         public onMaterialLODsLoadedObservable = new Observable<number>();
 
 
-        private _loadingNodeLOD: Nullable<_ILoaderNode> = null;
-        private _loadNodeSignals: { [nodeIndex: number]: Deferred<void> } = {};
-        private _loadNodePromises = new Array<Array<Promise<void>>>();
+        private _nodeIndexLOD: Nullable<number> = null;
+        private _nodeSignalLODs = new Array<Deferred<void>>();
+        private _nodePromiseLODs = new Array<Array<Promise<void>>>();
 
 
-        private _loadingMaterialLOD: Nullable<_ILoaderMaterial> = null;
-        private _loadMaterialSignals: { [materialIndex: number]: Deferred<void> } = {};
-        private _loadMaterialPromises = new Array<Array<Promise<void>>>();
+        private _materialIndexLOD: Nullable<number> = null;
+        private _materialSignalLODs = new Array<Deferred<void>>();
+        private _materialPromiseLODs = new Array<Array<Promise<void>>>();
 
 
         constructor(loader: GLTFLoader) {
         constructor(loader: GLTFLoader) {
             super(loader);
             super(loader);
 
 
-            this._loader._onReadyObservable.addOnce(() => {
-                for (let indexLOD = 0; indexLOD < this._loadNodePromises.length; indexLOD++) {
-                    Promise.all(this._loadNodePromises[indexLOD]).then(() => {
+            this._loader._readyPromise.then(() => {
+                for (let indexLOD = 0; indexLOD < this._nodePromiseLODs.length; indexLOD++) {
+                    Promise.all(this._nodePromiseLODs[indexLOD]).then(() => {
                         this._loader._parent._log(`Loaded node LOD ${indexLOD}`);
                         this._loader._parent._log(`Loaded node LOD ${indexLOD}`);
                         this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
                         this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                        if (indexLOD !== this._nodePromiseLODs.length - 1) {
+                            this._nodeSignalLODs[indexLOD].resolve();
+                        }
                     });
                     });
                 }
                 }
 
 
-                for (let indexLOD = 0; indexLOD < this._loadMaterialPromises.length; indexLOD++) {
-                    Promise.all(this._loadMaterialPromises[indexLOD]).then(() => {
+                for (let indexLOD = 0; indexLOD < this._materialPromiseLODs.length; indexLOD++) {
+                    Promise.all(this._materialPromiseLODs[indexLOD]).then(() => {
                         this._loader._parent._log(`Loaded material LOD ${indexLOD}`);
                         this._loader._parent._log(`Loaded material LOD ${indexLOD}`);
                         this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
                         this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                        if (indexLOD !==  this._materialPromiseLODs.length - 1) {
+                            this._materialSignalLODs[indexLOD].resolve();
+                        }
                     });
                     });
                 }
                 }
             });
             });
@@ -63,10 +69,13 @@ module BABYLON.GLTF2.Extensions {
         public dispose() {
         public dispose() {
             super.dispose();
             super.dispose();
 
 
-            this._loadingNodeLOD = null;
-            this._loadNodeSignals = {};
-            this._loadingMaterialLOD = null;
-            this._loadMaterialSignals = {};
+            this._nodeIndexLOD = null;
+            this._nodeSignalLODs.length = 0;
+            this._nodePromiseLODs.length = 0;
+
+            this._materialIndexLOD = null;
+            this._materialSignalLODs.length = 0;
+            this._materialPromiseLODs.length = 0;
 
 
             this.onMaterialLODsLoadedObservable.clear();
             this.onMaterialLODsLoadedObservable.clear();
             this.onNodeLODsLoadedObservable.clear();
             this.onNodeLODsLoadedObservable.clear();
@@ -83,11 +92,8 @@ module BABYLON.GLTF2.Extensions {
                     const nodeLOD = nodeLODs[indexLOD];
                     const nodeLOD = nodeLODs[indexLOD];
 
 
                     if (indexLOD !== 0) {
                     if (indexLOD !== 0) {
-                        this._loadingNodeLOD = nodeLOD;
-
-                        if (!this._loadNodeSignals[nodeLOD._index]) {
-                            this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
-                        }
+                        this._nodeIndexLOD = indexLOD;
+                        this._nodeSignalLODs[indexLOD] = this._nodeSignalLODs[indexLOD] || new Deferred();
                     }
                     }
 
 
                     const promise = this._loader._loadNodeAsync(`#/nodes/${nodeLOD._index}`, nodeLOD).then(() => {
                     const promise = this._loader._loadNodeAsync(`#/nodes/${nodeLOD._index}`, nodeLOD).then(() => {
@@ -98,15 +104,6 @@ module BABYLON.GLTF2.Extensions {
                                 delete previousNodeLOD._babylonMesh;
                                 delete previousNodeLOD._babylonMesh;
                             }
                             }
                         }
                         }
-
-                        if (indexLOD !== nodeLODs.length - 1) {
-                            const nodeIndex = nodeLODs[indexLOD + 1]._index;
-
-                            if (this._loadNodeSignals[nodeIndex]) {
-                                this._loadNodeSignals[nodeIndex].resolve();
-                                delete this._loadNodeSignals[nodeIndex];
-                            }
-                        }
                     });
                     });
 
 
                     if (indexLOD === 0) {
                     if (indexLOD === 0) {
@@ -114,11 +111,11 @@ module BABYLON.GLTF2.Extensions {
                     }
                     }
                     else {
                     else {
                         this._loader._completePromises.push(promise);
                         this._loader._completePromises.push(promise);
-                        this._loadingNodeLOD = null;
+                        this._nodeIndexLOD = null;
                     }
                     }
 
 
-                    this._loadNodePromises[indexLOD] = this._loadNodePromises[indexLOD] || [];
-                    this._loadNodePromises[indexLOD].push(promise);
+                    this._nodePromiseLODs[indexLOD] = this._nodePromiseLODs[indexLOD] || [];
+                    this._nodePromiseLODs[indexLOD].push(promise);
                 }
                 }
 
 
                 this._loader._parent._logClose();
                 this._loader._parent._logClose();
@@ -128,7 +125,7 @@ module BABYLON.GLTF2.Extensions {
 
 
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>> {
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, mesh: _ILoaderMesh, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>> {
             // Don't load material LODs if already loading a node LOD.
             // Don't load material LODs if already loading a node LOD.
-            if (this._loadingNodeLOD) {
+            if (this._nodeIndexLOD) {
                 return null;
                 return null;
             }
             }
 
 
@@ -142,11 +139,7 @@ module BABYLON.GLTF2.Extensions {
                     const materialLOD = materialLODs[indexLOD];
                     const materialLOD = materialLODs[indexLOD];
 
 
                     if (indexLOD !== 0) {
                     if (indexLOD !== 0) {
-                        this._loadingMaterialLOD = materialLOD;
-
-                        if (!this._loadMaterialSignals[materialLOD._index]) {
-                            this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
-                        }
+                        this._materialIndexLOD = indexLOD;
                     }
                     }
 
 
                     const promise = this._loader._loadMaterialAsync(`#/materials/${materialLOD._index}`, materialLOD, mesh, babylonMesh, babylonDrawMode, indexLOD === 0 ? assign : () => {}).then(() => {
                     const promise = this._loader._loadMaterialAsync(`#/materials/${materialLOD._index}`, materialLOD, mesh, babylonMesh, babylonDrawMode, indexLOD === 0 ? assign : () => {}).then(() => {
@@ -160,14 +153,6 @@ module BABYLON.GLTF2.Extensions {
                                 delete previousBabylonDataLOD[babylonDrawMode];
                                 delete previousBabylonDataLOD[babylonDrawMode];
                             }
                             }
                         }
                         }
-
-                        if (indexLOD !== materialLODs.length - 1) {
-                            const materialIndex = materialLODs[indexLOD + 1]._index;
-                            if (this._loadMaterialSignals[materialIndex]) {
-                                this._loadMaterialSignals[materialIndex].resolve();
-                                delete this._loadMaterialSignals[materialIndex];
-                            }
-                        }
                     });
                     });
 
 
                     if (indexLOD === 0) {
                     if (indexLOD === 0) {
@@ -175,11 +160,11 @@ module BABYLON.GLTF2.Extensions {
                     }
                     }
                     else {
                     else {
                         this._loader._completePromises.push(promise);
                         this._loader._completePromises.push(promise);
-                        this._loadingMaterialLOD = null;
+                        this._materialIndexLOD = null;
                     }
                     }
 
 
-                    this._loadMaterialPromises[indexLOD] = this._loadMaterialPromises[indexLOD] || [];
-                    this._loadMaterialPromises[indexLOD].push(promise);
+                    this._materialPromiseLODs[indexLOD] = this._materialPromiseLODs[indexLOD] || [];
+                    this._materialPromiseLODs[indexLOD].push(promise);
                 }
                 }
 
 
                 this._loader._parent._logClose();
                 this._loader._parent._logClose();
@@ -188,22 +173,20 @@ module BABYLON.GLTF2.Extensions {
         }
         }
 
 
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>> {
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>> {
-            if (this._loadingMaterialLOD || this._loadingNodeLOD) {
-                if (this._loader._parent.loggingEnabled) {
-                    this._loader._parent._log(`deferred`);
-                }
-            }
-
             // Defer the loading of uris if loading a material or node LOD.
             // Defer the loading of uris if loading a material or node LOD.
-            if (this._loadingMaterialLOD) {
-                const index = this._loadingMaterialLOD._index;
-                return this._loadMaterialSignals[index].promise.then(() => {
+            if (this._materialIndexLOD !== null) {
+                this._loader._parent._log(`deferred`);
+                const previousIndexLOD = this._materialIndexLOD - 1;
+                this._materialSignalLODs[previousIndexLOD] = this._materialSignalLODs[previousIndexLOD] || new Deferred<void>();
+                return this._materialSignalLODs[previousIndexLOD].promise.then(() => {
                     return this._loader._loadUriAsync(context, uri);
                     return this._loader._loadUriAsync(context, uri);
                 });
                 });
             }
             }
-            else if (this._loadingNodeLOD) {
-                const index = this._loadingNodeLOD._index;
-                return this._loadNodeSignals[index].promise.then(() => {
+            else if (this._nodeIndexLOD !== null) {
+                this._loader._parent._log(`deferred`);
+                const previousIndexLOD = this._nodeIndexLOD - 1;
+                this._nodeSignalLODs[previousIndexLOD] = this._nodeSignalLODs[previousIndexLOD] || new Deferred<void>();
+                return this._nodeSignalLODs[this._nodeIndexLOD - 1].promise.then(() => {
                     return this._loader._loadUriAsync(context, uri);
                     return this._loader._loadUriAsync(context, uri);
                 });
                 });
             }
             }

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

@@ -25,8 +25,8 @@ module BABYLON.GLTF2 {
         public _parent: GLTFFileLoader;
         public _parent: GLTFFileLoader;
         public _gltf: _ILoaderGLTF;
         public _gltf: _ILoaderGLTF;
         public _babylonScene: Scene;
         public _babylonScene: Scene;
+        public _readyPromise: Promise<void>;
         public _completePromises = new Array<Promise<void>>();
         public _completePromises = new Array<Promise<void>>();
-        public _onReadyObservable = new Observable<IGLTFLoader>();
 
 
         private _disposed = false;
         private _disposed = false;
         private _state: Nullable<GLTFLoaderState> = null;
         private _state: Nullable<GLTFLoaderState> = null;
@@ -79,8 +79,8 @@ module BABYLON.GLTF2 {
 
 
             delete this._gltf;
             delete this._gltf;
             delete this._babylonScene;
             delete this._babylonScene;
+            delete this._readyPromise;
             this._completePromises.length = 0;
             this._completePromises.length = 0;
-            this._onReadyObservable.clear();
 
 
             for (const name in this._extensions) {
             for (const name in this._extensions) {
                 this._extensions[name].dispose();
                 this._extensions[name].dispose();
@@ -101,14 +101,14 @@ module BABYLON.GLTF2 {
                 this._progressCallback = onProgress;
                 this._progressCallback = onProgress;
                 this._loadData(data);
                 this._loadData(data);
 
 
-                let nodes: Nullable<Array<_ILoaderNode>> = null;
+                let nodes: Nullable<Array<number>> = null;
 
 
                 if (meshesNames) {
                 if (meshesNames) {
-                    const nodeMap: { [name: string]: _ILoaderNode } = {};
+                    const nodeMap: { [name: string]: number } = {};
                     if (this._gltf.nodes) {
                     if (this._gltf.nodes) {
                         for (const node of this._gltf.nodes) {
                         for (const node of this._gltf.nodes) {
                             if (node.name) {
                             if (node.name) {
-                                nodeMap[node.name] = node;
+                                nodeMap[node.name] = node._index;
                             }
                             }
                         }
                         }
                     }
                     }
@@ -116,7 +116,7 @@ module BABYLON.GLTF2 {
                     const names = (meshesNames instanceof Array) ? meshesNames : [meshesNames];
                     const names = (meshesNames instanceof Array) ? meshesNames : [meshesNames];
                     nodes = names.map(name => {
                     nodes = names.map(name => {
                         const node = nodeMap[name];
                         const node = nodeMap[name];
-                        if (!node) {
+                        if (node === undefined) {
                             throw new Error(`Failed to find node '${name}'`);
                             throw new Error(`Failed to find node '${name}'`);
                         }
                         }
 
 
@@ -145,18 +145,21 @@ module BABYLON.GLTF2 {
             });
             });
         }
         }
 
 
-        private _loadAsync(nodes: Nullable<Array<_ILoaderNode>>): Promise<void> {
+        private _loadAsync(nodes: Nullable<Array<number>>): Promise<void> {
             return Promise.resolve().then(() => {
             return Promise.resolve().then(() => {
                 this._state = GLTFLoaderState.LOADING;
                 this._state = GLTFLoaderState.LOADING;
                 this._parent._log(`Loading`);
                 this._parent._log(`Loading`);
 
 
+                const readyDeferred = new Deferred<void>();
+                this._readyPromise = readyDeferred.promise;
+
                 this._loadExtensions();
                 this._loadExtensions();
                 this._checkExtensions();
                 this._checkExtensions();
 
 
                 const promises = new Array<Promise<void>>();
                 const promises = new Array<Promise<void>>();
 
 
                 if (nodes) {
                 if (nodes) {
-                    promises.push(this._loadNodesAsync(nodes));
+                    promises.push(this._loadSceneAsync("#/nodes", { nodes: nodes, _index: -1 }));
                 }
                 }
                 else {
                 else {
                     const scene = GLTFLoader._GetProperty(`#/scene`, this._gltf.scenes, this._gltf.scene || 0);
                     const scene = GLTFLoader._GetProperty(`#/scene`, this._gltf.scenes, this._gltf.scene || 0);
@@ -175,7 +178,8 @@ module BABYLON.GLTF2 {
                     this._state = GLTFLoaderState.READY;
                     this._state = GLTFLoaderState.READY;
                     this._parent._log(`Ready`);
                     this._parent._log(`Ready`);
 
 
-                    this._onReadyObservable.notifyObservers(this);
+                    readyDeferred.resolve();
+
                     this._startAnimations();
                     this._startAnimations();
                 });
                 });
 
 
@@ -313,18 +317,6 @@ module BABYLON.GLTF2 {
             return rootNode;
             return rootNode;
         }
         }
 
 
-        private _loadNodesAsync(nodes: _ILoaderNode[]): Promise<void> {
-            const promises = new Array<Promise<void>>();
-
-            for (let node of nodes) {
-                promises.push(this._loadNodeAsync(`#/nodes/${node._index}`, node));
-            }
-
-            promises.push(this._loadAnimationsAsync());
-
-            return Promise.all(promises).then(() => {});
-        }
-
         public _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void> {
         public _loadSceneAsync(context: string, scene: _ILoaderScene): Promise<void> {
             const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
             const promise = GLTFLoaderExtension._LoadSceneAsync(this, context, scene);
             if (promise) {
             if (promise) {

+ 2 - 1
sandbox/index.js

@@ -264,8 +264,9 @@ if (BABYLON.Engine.isSupported()) {
 
 
     window.addEventListener("keydown", function (event) {
     window.addEventListener("keydown", function (event) {
         // Press R to reload
         // Press R to reload
-        if (event.keyCode === 82 && event.target.nodeName !== "INPUT") {
+        if (event.keyCode === 82 && event.target.nodeName !== "INPUT" && currentScene) {
             debugLayerLastActiveTab = currentScene.debugLayer.getActiveTab();
             debugLayerLastActiveTab = currentScene.debugLayer.getActiveTab();
+
             if (assetUrl) {
             if (assetUrl) {
                 loadFromAssetUrl();
                 loadFromAssetUrl();
             }
             }