David Catuhe 7 anni fa
parent
commit
b1261e7d33
30 ha cambiato i file con 9038 aggiunte e 8593 eliminazioni
  1. 1516 1481
      Playground/babylon.d.txt
  2. 6669 6657
      dist/preview release/babylon.d.ts
  3. 48 48
      dist/preview release/babylon.js
  4. 33 11
      dist/preview release/babylon.max.js
  5. 33 11
      dist/preview release/babylon.no-module.max.js
  6. 48 48
      dist/preview release/babylon.worker.js
  7. 33 11
      dist/preview release/es6.js
  8. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.js
  10. 2 2
      dist/preview release/inspector/babylon.inspector.min.js
  11. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  12. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  13. 18 0
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  14. 57 8
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  15. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  16. 18 0
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  17. 57 8
      dist/preview release/loaders/babylon.glTFFileLoader.js
  18. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  19. 18 0
      dist/preview release/loaders/babylonjs.loaders.d.ts
  20. 57 8
      dist/preview release/loaders/babylonjs.loaders.js
  21. 4 4
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 18 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 2 1
      dist/preview release/viewer/babylon.viewer.d.ts
  24. 31 31
      dist/preview release/viewer/babylon.viewer.js
  25. 333 239
      dist/preview release/viewer/babylon.viewer.max.js
  26. 2 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  27. 1 1
      inspector/src/tabs/StatsTab.ts
  28. 2 1
      src/Materials/Textures/babylon.texture.ts
  29. 12 11
      src/Tools/babylon.assetsManager.ts
  30. 15 0
      src/babylon.scene.ts

File diff suppressed because it is too large
+ 1516 - 1481
Playground/babylon.d.txt


File diff suppressed because it is too large
+ 6669 - 6657
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 48 - 48
dist/preview release/babylon.js


+ 33 - 11
dist/preview release/babylon.max.js

@@ -8211,6 +8211,14 @@ var BABYLON;
             return observer;
         };
         /**
+         * Create a new Observer with the specified callback and unregisters after the next notification
+         * @param callback the callback that will be executed for that Observer
+         * @returns the new observer created for the callback
+         */
+        Observable.prototype.addOnce = function (callback) {
+            return this.add(callback, undefined, undefined, undefined, true);
+        };
+        /**
          * Remove an Observer from the Observable object
          * @param observer the instance of the Observer to remove
          * @returns false if it doesn't belong to this Observable
@@ -28314,6 +28322,19 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * This function will remove the local cached buffer data from texture.
+         * It will save memory but will prevent the texture from being rebuilt
+         */
+        Scene.prototype.cleanCachedTextureBuffer = function () {
+            for (var _i = 0, _a = this.textures; _i < _a.length; _i++) {
+                var baseTexture = _a[_i];
+                var buffer = baseTexture._buffer;
+                if (buffer) {
+                    baseTexture._buffer = null;
+                }
+            }
+        };
         // Octrees
         /**
          * Get the world extend vectors with an optional filter
@@ -46968,7 +46989,7 @@ var BABYLON;
         ], PBRMaterial.prototype, "useRadianceOcclusion", void 0);
         __decorate([
             BABYLON.serialize(),
-            BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
+            BABYLON.expandToProperty("_markAllSubMeshesAsMiscDirty")
         ], PBRMaterial.prototype, "unlit", void 0);
         return PBRMaterial;
     }(BABYLON.PBRBaseMaterial));
@@ -94565,18 +94586,8 @@ var BABYLON;
             return task;
         };
         AssetsManager.prototype._decreaseWaitingTasksCount = function (task) {
-            var _this = this;
             this._waitingTasksCount--;
             try {
-                if (task.taskState === AssetTaskState.DONE) {
-                    // Let's remove successfull tasks
-                    BABYLON.Tools.SetImmediate(function () {
-                        var index = _this._tasks.indexOf(task);
-                        if (index > -1) {
-                            _this._tasks.splice(index, 1);
-                        }
-                    });
-                }
                 if (this.onProgress) {
                     this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
                 }
@@ -94591,6 +94602,17 @@ var BABYLON;
                     if (this.onFinish) {
                         this.onFinish(this._tasks);
                     }
+                    // Let's remove successfull tasks
+                    var currentTasks = this._tasks.slice();
+                    for (var _i = 0, currentTasks_1 = currentTasks; _i < currentTasks_1.length; _i++) {
+                        var task = currentTasks_1[_i];
+                        if (task.taskState === AssetTaskState.DONE) {
+                            var index = this._tasks.indexOf(task);
+                            if (index > -1) {
+                                this._tasks.splice(index, 1);
+                            }
+                        }
+                    }
                     this.onTasksDoneObservable.notifyObservers(this._tasks);
                 }
                 catch (e) {

+ 33 - 11
dist/preview release/babylon.no-module.max.js

@@ -8178,6 +8178,14 @@ var BABYLON;
             return observer;
         };
         /**
+         * Create a new Observer with the specified callback and unregisters after the next notification
+         * @param callback the callback that will be executed for that Observer
+         * @returns the new observer created for the callback
+         */
+        Observable.prototype.addOnce = function (callback) {
+            return this.add(callback, undefined, undefined, undefined, true);
+        };
+        /**
          * Remove an Observer from the Observable object
          * @param observer the instance of the Observer to remove
          * @returns false if it doesn't belong to this Observable
@@ -28281,6 +28289,19 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * This function will remove the local cached buffer data from texture.
+         * It will save memory but will prevent the texture from being rebuilt
+         */
+        Scene.prototype.cleanCachedTextureBuffer = function () {
+            for (var _i = 0, _a = this.textures; _i < _a.length; _i++) {
+                var baseTexture = _a[_i];
+                var buffer = baseTexture._buffer;
+                if (buffer) {
+                    baseTexture._buffer = null;
+                }
+            }
+        };
         // Octrees
         /**
          * Get the world extend vectors with an optional filter
@@ -46935,7 +46956,7 @@ var BABYLON;
         ], PBRMaterial.prototype, "useRadianceOcclusion", void 0);
         __decorate([
             BABYLON.serialize(),
-            BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
+            BABYLON.expandToProperty("_markAllSubMeshesAsMiscDirty")
         ], PBRMaterial.prototype, "unlit", void 0);
         return PBRMaterial;
     }(BABYLON.PBRBaseMaterial));
@@ -94532,18 +94553,8 @@ var BABYLON;
             return task;
         };
         AssetsManager.prototype._decreaseWaitingTasksCount = function (task) {
-            var _this = this;
             this._waitingTasksCount--;
             try {
-                if (task.taskState === AssetTaskState.DONE) {
-                    // Let's remove successfull tasks
-                    BABYLON.Tools.SetImmediate(function () {
-                        var index = _this._tasks.indexOf(task);
-                        if (index > -1) {
-                            _this._tasks.splice(index, 1);
-                        }
-                    });
-                }
                 if (this.onProgress) {
                     this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
                 }
@@ -94558,6 +94569,17 @@ var BABYLON;
                     if (this.onFinish) {
                         this.onFinish(this._tasks);
                     }
+                    // Let's remove successfull tasks
+                    var currentTasks = this._tasks.slice();
+                    for (var _i = 0, currentTasks_1 = currentTasks; _i < currentTasks_1.length; _i++) {
+                        var task = currentTasks_1[_i];
+                        if (task.taskState === AssetTaskState.DONE) {
+                            var index = this._tasks.indexOf(task);
+                            if (index > -1) {
+                                this._tasks.splice(index, 1);
+                            }
+                        }
+                    }
                     this.onTasksDoneObservable.notifyObservers(this._tasks);
                 }
                 catch (e) {

File diff suppressed because it is too large
+ 48 - 48
dist/preview release/babylon.worker.js


+ 33 - 11
dist/preview release/es6.js

@@ -8178,6 +8178,14 @@ var BABYLON;
             return observer;
         };
         /**
+         * Create a new Observer with the specified callback and unregisters after the next notification
+         * @param callback the callback that will be executed for that Observer
+         * @returns the new observer created for the callback
+         */
+        Observable.prototype.addOnce = function (callback) {
+            return this.add(callback, undefined, undefined, undefined, true);
+        };
+        /**
          * Remove an Observer from the Observable object
          * @param observer the instance of the Observer to remove
          * @returns false if it doesn't belong to this Observable
@@ -28281,6 +28289,19 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * This function will remove the local cached buffer data from texture.
+         * It will save memory but will prevent the texture from being rebuilt
+         */
+        Scene.prototype.cleanCachedTextureBuffer = function () {
+            for (var _i = 0, _a = this.textures; _i < _a.length; _i++) {
+                var baseTexture = _a[_i];
+                var buffer = baseTexture._buffer;
+                if (buffer) {
+                    baseTexture._buffer = null;
+                }
+            }
+        };
         // Octrees
         /**
          * Get the world extend vectors with an optional filter
@@ -46935,7 +46956,7 @@ var BABYLON;
         ], PBRMaterial.prototype, "useRadianceOcclusion", void 0);
         __decorate([
             BABYLON.serialize(),
-            BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
+            BABYLON.expandToProperty("_markAllSubMeshesAsMiscDirty")
         ], PBRMaterial.prototype, "unlit", void 0);
         return PBRMaterial;
     }(BABYLON.PBRBaseMaterial));
@@ -94532,18 +94553,8 @@ var BABYLON;
             return task;
         };
         AssetsManager.prototype._decreaseWaitingTasksCount = function (task) {
-            var _this = this;
             this._waitingTasksCount--;
             try {
-                if (task.taskState === AssetTaskState.DONE) {
-                    // Let's remove successfull tasks
-                    BABYLON.Tools.SetImmediate(function () {
-                        var index = _this._tasks.indexOf(task);
-                        if (index > -1) {
-                            _this._tasks.splice(index, 1);
-                        }
-                    });
-                }
                 if (this.onProgress) {
                     this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
                 }
@@ -94558,6 +94569,17 @@ var BABYLON;
                     if (this.onFinish) {
                         this.onFinish(this._tasks);
                     }
+                    // Let's remove successfull tasks
+                    var currentTasks = this._tasks.slice();
+                    for (var _i = 0, currentTasks_1 = currentTasks; _i < currentTasks_1.length; _i++) {
+                        var task = currentTasks_1[_i];
+                        if (task.taskState === AssetTaskState.DONE) {
+                            var index = this._tasks.indexOf(task);
+                            if (index > -1) {
+                                this._tasks.splice(index, 1);
+                            }
+                        }
+                    }
                     this.onTasksDoneObservable.notifyObservers(this._tasks);
                 }
                 catch (e) {

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/inspector/babylon.inspector.bundle.js


+ 1 - 1
dist/preview release/inspector/babylon.inspector.js

@@ -3799,7 +3799,7 @@ var INSPECTOR;
             title = INSPECTOR.Helpers.CreateDiv('stat-title2', _this._panel);
             title.textContent = "Duration";
             {
-                _this._createStatLabel("Refresh rate (refresh by second)", _this._panel);
+                _this._createStatLabel("Properties refresh rate (per second)", _this._panel);
                 var elemValue = INSPECTOR.Helpers.CreateDiv('stat-value', _this._panel);
                 _this._inputElement = INSPECTOR.Inspector.DOCUMENT.createElement('input');
                 _this._inputElement.value = _this.refreshRate;

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/inspector/babylon.inspector.min.js


+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -251,9 +251,9 @@ var BABYLON;
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
             return new Promise(function (resolve) {
-                _this.onCompleteObservable.add(function () {
+                _this.onCompleteObservable.addOnce(function () {
                     resolve();
-                }, undefined, undefined, undefined, true);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 18 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -505,6 +505,8 @@ declare module BABYLON.GLTF2 {
         _babylonScene: Scene;
         /** @hidden */
         _completePromises: Promise<void>[];
+        /** @hidden */
+        _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
         private _extensions;
@@ -744,10 +746,26 @@ declare module BABYLON.GLTF2.Extensions {
          * Maximum number of LODs to load, starting from the lowest LOD.
          */
         maxLODsToLoad: number;
+        /**
+         * Observable raised when all node LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onNodeLODsLoadedObservable: Observable<number>;
+        /**
+         * Observable raised when all material LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onMaterialLODsLoadedObservable: Observable<number>;
         private _loadingNodeLOD;
         private _loadNodeSignals;
+        private _loadNodePromises;
         private _loadingMaterialLOD;
         private _loadMaterialSignals;
+        private _loadMaterialPromises;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;

+ 57 - 8
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -251,9 +251,9 @@ var BABYLON;
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
             return new Promise(function (resolve) {
-                _this.onCompleteObservable.add(function () {
+                _this.onCompleteObservable.addOnce(function () {
                     resolve();
-                }, undefined, undefined, undefined, true);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -635,6 +635,8 @@ var BABYLON;
             function GLTFLoader() {
                 /** @hidden */
                 this._completePromises = new Array();
+                /** @hidden */
+                this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
                 this._extensions = {};
@@ -816,6 +818,7 @@ var BABYLON;
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
@@ -2131,6 +2134,7 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                this._onReadyObservable.clear();
                 for (var name_4 in this._extensions) {
                     this._extensions[name_4].dispose();
                 }
@@ -2272,25 +2276,66 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function MSFT_lod(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
                      */
                     _this.maxLODsToLoad = Number.MAX_VALUE;
+                    /**
+                     * Observable raised when all node LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onNodeLODsLoadedObservable = new BABYLON.Observable();
+                    /**
+                     * Observable raised when all material LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onMaterialLODsLoadedObservable = new BABYLON.Observable();
                     _this._loadingNodeLOD = null;
                     _this._loadNodeSignals = {};
+                    _this._loadNodePromises = new Array();
                     _this._loadingMaterialLOD = null;
                     _this._loadMaterialSignals = {};
+                    _this._loadMaterialPromises = new Array();
+                    _this._loader._onReadyObservable.addOnce(function () {
+                        var _loop_1 = function (indexLOD) {
+                            Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadNodePromises.length; indexLOD++) {
+                            _loop_1(indexLOD);
+                        }
+                        var _loop_2 = function (indexLOD) {
+                            Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadMaterialPromises.length; indexLOD++) {
+                            _loop_2(indexLOD);
+                        }
+                    });
                     return _this;
                 }
+                MSFT_lod.prototype.dispose = function () {
+                    _super.prototype.dispose.call(this);
+                    this._loadingNodeLOD = null;
+                    this._loadNodeSignals = {};
+                    this._loadingMaterialLOD = null;
+                    this._loadMaterialSignals = {};
+                    this.onMaterialLODsLoadedObservable.clear();
+                    this.onNodeLODsLoadedObservable.clear();
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
-                        var _loop_1 = function (indexLOD) {
+                        var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
@@ -2321,9 +2366,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingNodeLOD = null;
                             }
+                            _this._loadNodePromises[indexLOD] = _this._loadNodePromises[indexLOD] || [];
+                            _this._loadNodePromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
+                            _loop_3(indexLOD);
                         }
                         return firstPromise;
                     });
@@ -2337,7 +2384,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
-                        var _loop_2 = function (indexLOD) {
+                        var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
@@ -2370,9 +2417,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingMaterialLOD = null;
                             }
+                            _this._loadMaterialPromises[indexLOD] = _this._loadMaterialPromises[indexLOD] || [];
+                            _this._loadMaterialPromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
+                            _loop_4(indexLOD);
                         }
                         return firstPromise;
                     });

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 18 - 0
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -1082,6 +1082,8 @@ declare module BABYLON.GLTF2 {
         _babylonScene: Scene;
         /** @hidden */
         _completePromises: Promise<void>[];
+        /** @hidden */
+        _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
         private _extensions;
@@ -1321,10 +1323,26 @@ declare module BABYLON.GLTF2.Extensions {
          * Maximum number of LODs to load, starting from the lowest LOD.
          */
         maxLODsToLoad: number;
+        /**
+         * Observable raised when all node LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onNodeLODsLoadedObservable: Observable<number>;
+        /**
+         * Observable raised when all material LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onMaterialLODsLoadedObservable: Observable<number>;
         private _loadingNodeLOD;
         private _loadNodeSignals;
+        private _loadNodePromises;
         private _loadingMaterialLOD;
         private _loadMaterialSignals;
+        private _loadMaterialPromises;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;

+ 57 - 8
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -251,9 +251,9 @@ var BABYLON;
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
             return new Promise(function (resolve) {
-                _this.onCompleteObservable.add(function () {
+                _this.onCompleteObservable.addOnce(function () {
                     resolve();
-                }, undefined, undefined, undefined, true);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -2851,6 +2851,8 @@ var BABYLON;
             function GLTFLoader() {
                 /** @hidden */
                 this._completePromises = new Array();
+                /** @hidden */
+                this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
                 this._extensions = {};
@@ -3032,6 +3034,7 @@ var BABYLON;
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
@@ -4347,6 +4350,7 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                this._onReadyObservable.clear();
                 for (var name_4 in this._extensions) {
                     this._extensions[name_4].dispose();
                 }
@@ -4488,25 +4492,66 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function MSFT_lod(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
                      */
                     _this.maxLODsToLoad = Number.MAX_VALUE;
+                    /**
+                     * Observable raised when all node LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onNodeLODsLoadedObservable = new BABYLON.Observable();
+                    /**
+                     * Observable raised when all material LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onMaterialLODsLoadedObservable = new BABYLON.Observable();
                     _this._loadingNodeLOD = null;
                     _this._loadNodeSignals = {};
+                    _this._loadNodePromises = new Array();
                     _this._loadingMaterialLOD = null;
                     _this._loadMaterialSignals = {};
+                    _this._loadMaterialPromises = new Array();
+                    _this._loader._onReadyObservable.addOnce(function () {
+                        var _loop_1 = function (indexLOD) {
+                            Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadNodePromises.length; indexLOD++) {
+                            _loop_1(indexLOD);
+                        }
+                        var _loop_2 = function (indexLOD) {
+                            Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadMaterialPromises.length; indexLOD++) {
+                            _loop_2(indexLOD);
+                        }
+                    });
                     return _this;
                 }
+                MSFT_lod.prototype.dispose = function () {
+                    _super.prototype.dispose.call(this);
+                    this._loadingNodeLOD = null;
+                    this._loadNodeSignals = {};
+                    this._loadingMaterialLOD = null;
+                    this._loadMaterialSignals = {};
+                    this.onMaterialLODsLoadedObservable.clear();
+                    this.onNodeLODsLoadedObservable.clear();
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
-                        var _loop_1 = function (indexLOD) {
+                        var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
@@ -4537,9 +4582,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingNodeLOD = null;
                             }
+                            _this._loadNodePromises[indexLOD] = _this._loadNodePromises[indexLOD] || [];
+                            _this._loadNodePromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
+                            _loop_3(indexLOD);
                         }
                         return firstPromise;
                     });
@@ -4553,7 +4600,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
-                        var _loop_2 = function (indexLOD) {
+                        var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
@@ -4586,9 +4633,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingMaterialLOD = null;
                             }
+                            _this._loadMaterialPromises[indexLOD] = _this._loadMaterialPromises[indexLOD] || [];
+                            _this._loadMaterialPromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
+                            _loop_4(indexLOD);
                         }
                         return firstPromise;
                     });

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 18 - 0
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -1178,6 +1178,8 @@ declare module BABYLON.GLTF2 {
         _babylonScene: Scene;
         /** @hidden */
         _completePromises: Promise<void>[];
+        /** @hidden */
+        _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
         private _extensions;
@@ -1417,10 +1419,26 @@ declare module BABYLON.GLTF2.Extensions {
          * Maximum number of LODs to load, starting from the lowest LOD.
          */
         maxLODsToLoad: number;
+        /**
+         * Observable raised when all node LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onNodeLODsLoadedObservable: Observable<number>;
+        /**
+         * Observable raised when all material LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onMaterialLODsLoadedObservable: Observable<number>;
         private _loadingNodeLOD;
         private _loadNodeSignals;
+        private _loadNodePromises;
         private _loadingMaterialLOD;
         private _loadMaterialSignals;
+        private _loadMaterialPromises;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;

+ 57 - 8
dist/preview release/loaders/babylonjs.loaders.js

@@ -1251,9 +1251,9 @@ var BABYLON;
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
             return new Promise(function (resolve) {
-                _this.onCompleteObservable.add(function () {
+                _this.onCompleteObservable.addOnce(function () {
                     resolve();
-                }, undefined, undefined, undefined, true);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -3833,6 +3833,8 @@ var BABYLON;
             function GLTFLoader() {
                 /** @hidden */
                 this._completePromises = new Array();
+                /** @hidden */
+                this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
                 this._extensions = {};
@@ -4014,6 +4016,7 @@ var BABYLON;
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
@@ -5329,6 +5332,7 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                this._onReadyObservable.clear();
                 for (var name_4 in this._extensions) {
                     this._extensions[name_4].dispose();
                 }
@@ -5461,25 +5465,66 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function MSFT_lod(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
                      */
                     _this.maxLODsToLoad = Number.MAX_VALUE;
+                    /**
+                     * Observable raised when all node LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onNodeLODsLoadedObservable = new BABYLON.Observable();
+                    /**
+                     * Observable raised when all material LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onMaterialLODsLoadedObservable = new BABYLON.Observable();
                     _this._loadingNodeLOD = null;
                     _this._loadNodeSignals = {};
+                    _this._loadNodePromises = new Array();
                     _this._loadingMaterialLOD = null;
                     _this._loadMaterialSignals = {};
+                    _this._loadMaterialPromises = new Array();
+                    _this._loader._onReadyObservable.addOnce(function () {
+                        var _loop_1 = function (indexLOD) {
+                            Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadNodePromises.length; indexLOD++) {
+                            _loop_1(indexLOD);
+                        }
+                        var _loop_2 = function (indexLOD) {
+                            Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadMaterialPromises.length; indexLOD++) {
+                            _loop_2(indexLOD);
+                        }
+                    });
                     return _this;
                 }
+                MSFT_lod.prototype.dispose = function () {
+                    _super.prototype.dispose.call(this);
+                    this._loadingNodeLOD = null;
+                    this._loadNodeSignals = {};
+                    this._loadingMaterialLOD = null;
+                    this._loadMaterialSignals = {};
+                    this.onMaterialLODsLoadedObservable.clear();
+                    this.onNodeLODsLoadedObservable.clear();
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
-                        var _loop_1 = function (indexLOD) {
+                        var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
@@ -5510,9 +5555,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingNodeLOD = null;
                             }
+                            _this._loadNodePromises[indexLOD] = _this._loadNodePromises[indexLOD] || [];
+                            _this._loadNodePromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
+                            _loop_3(indexLOD);
                         }
                         return firstPromise;
                     });
@@ -5526,7 +5573,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
-                        var _loop_2 = function (indexLOD) {
+                        var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
@@ -5559,9 +5606,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingMaterialLOD = null;
                             }
+                            _this._loadMaterialPromises[indexLOD] = _this._loadMaterialPromises[indexLOD] || [];
+                            _this._loadMaterialPromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
+                            _loop_4(indexLOD);
                         }
                         return firstPromise;
                     });

File diff suppressed because it is too large
+ 4 - 4
dist/preview release/loaders/babylonjs.loaders.min.js


+ 18 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1185,6 +1185,8 @@ declare module BABYLON.GLTF2 {
         _babylonScene: Scene;
         /** @hidden */
         _completePromises: Promise<void>[];
+        /** @hidden */
+        _onReadyObservable: Observable<IGLTFLoader>;
         private _disposed;
         private _state;
         private _extensions;
@@ -1424,10 +1426,26 @@ declare module BABYLON.GLTF2.Extensions {
          * Maximum number of LODs to load, starting from the lowest LOD.
          */
         maxLODsToLoad: number;
+        /**
+         * Observable raised when all node LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onNodeLODsLoadedObservable: Observable<number>;
+        /**
+         * Observable raised when all material LODs of one level are loaded.
+         * The event data is the index of the loaded LOD starting from zero.
+         * Dispose the loader to cancel the loading of the next level of LODs.
+         */
+        onMaterialLODsLoadedObservable: Observable<number>;
         private _loadingNodeLOD;
         private _loadNodeSignals;
+        private _loadNodePromises;
         private _loadingMaterialLOD;
         private _loadMaterialSignals;
+        private _loadMaterialPromises;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadNodeAsync(context: string, node: _ILoaderNode): Nullable<Promise<void>>;
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;

+ 2 - 1
dist/preview release/viewer/babylon.viewer.d.ts

@@ -612,6 +612,7 @@ declare module BabylonViewer {
             loadId: number;
             loadInfo: BABYLON.GLTF2.IAsset;
             constructor(_viewer: AbstractViewer, modelConfiguration: IModelConfiguration);
+            shadowsRenderedAfterLoad: boolean;
             /**
                 * Set whether this model is enabled or not.
                 */
@@ -1856,7 +1857,7 @@ declare module BabylonViewer {
                 * @param model optionally use the model to configure the camera.
                 */
             protected _configureCamera(cameraConfig?: ICameraConfiguration): void;
-            protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): Promise<BABYLON.Scene> | undefined;
+            protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): void;
             /**
                 * configure the lights.
                 *

File diff suppressed because it is too large
+ 31 - 31
dist/preview release/viewer/babylon.viewer.js


+ 333 - 239
dist/preview release/viewer/babylon.viewer.max.js

@@ -8299,6 +8299,14 @@ var BABYLON;
             return observer;
         };
         /**
+         * Create a new Observer with the specified callback and unregisters after the next notification
+         * @param callback the callback that will be executed for that Observer
+         * @returns the new observer created for the callback
+         */
+        Observable.prototype.addOnce = function (callback) {
+            return this.add(callback, undefined, undefined, undefined, true);
+        };
+        /**
          * Remove an Observer from the Observable object
          * @param observer the instance of the Observer to remove
          * @returns false if it doesn't belong to this Observable
@@ -28402,6 +28410,19 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * This function will remove the local cached buffer data from texture.
+         * It will save memory but will prevent the texture from being rebuilt
+         */
+        Scene.prototype.cleanCachedTextureBuffer = function () {
+            for (var _i = 0, _a = this.textures; _i < _a.length; _i++) {
+                var baseTexture = _a[_i];
+                var buffer = baseTexture._buffer;
+                if (buffer) {
+                    baseTexture._buffer = null;
+                }
+            }
+        };
         // Octrees
         /**
          * Get the world extend vectors with an optional filter
@@ -47056,7 +47077,7 @@ var BABYLON;
         ], PBRMaterial.prototype, "useRadianceOcclusion", void 0);
         __decorate([
             BABYLON.serialize(),
-            BABYLON.expandToProperty("_markAllSubMeshesAsLightsDirty")
+            BABYLON.expandToProperty("_markAllSubMeshesAsMiscDirty")
         ], PBRMaterial.prototype, "unlit", void 0);
         return PBRMaterial;
     }(BABYLON.PBRBaseMaterial));
@@ -94653,18 +94674,8 @@ var BABYLON;
             return task;
         };
         AssetsManager.prototype._decreaseWaitingTasksCount = function (task) {
-            var _this = this;
             this._waitingTasksCount--;
             try {
-                if (task.taskState === AssetTaskState.DONE) {
-                    // Let's remove successfull tasks
-                    BABYLON.Tools.SetImmediate(function () {
-                        var index = _this._tasks.indexOf(task);
-                        if (index > -1) {
-                            _this._tasks.splice(index, 1);
-                        }
-                    });
-                }
                 if (this.onProgress) {
                     this.onProgress(this._waitingTasksCount, this._totalTasksCount, task);
                 }
@@ -94679,6 +94690,17 @@ var BABYLON;
                     if (this.onFinish) {
                         this.onFinish(this._tasks);
                     }
+                    // Let's remove successfull tasks
+                    var currentTasks = this._tasks.slice();
+                    for (var _i = 0, currentTasks_1 = currentTasks; _i < currentTasks_1.length; _i++) {
+                        var task = currentTasks_1[_i];
+                        if (task.taskState === AssetTaskState.DONE) {
+                            var index = this._tasks.indexOf(task);
+                            if (index > -1) {
+                                this._tasks.splice(index, 1);
+                            }
+                        }
+                    }
                     this.onTasksDoneObservable.notifyObservers(this._tasks);
                 }
                 catch (e) {
@@ -99481,6 +99503,7 @@ var ViewerModel = /** @class */ (function () {
         this._loaderDone = false;
         this._animatables = [];
         this._frameRate = 60;
+        this._shadowsRenderedAfterLoad = false;
         this.onLoadedObservable = new babylonjs_1.Observable();
         this.onLoadErrorObservable = new babylonjs_1.Observable();
         this.onLoadProgressObservable = new babylonjs_1.Observable();
@@ -99510,6 +99533,21 @@ var ViewerModel = /** @class */ (function () {
             _this.state = ModelState.COMPLETE;
         });
     }
+    Object.defineProperty(ViewerModel.prototype, "shadowsRenderedAfterLoad", {
+        get: function () {
+            return this._shadowsRenderedAfterLoad;
+        },
+        set: function (rendered) {
+            if (!rendered) {
+                throw new Error("can only be enabled");
+            }
+            else {
+                this._shadowsRenderedAfterLoad = rendered;
+            }
+        },
+        enumerable: true,
+        configurable: true
+    });
     Object.defineProperty(ViewerModel.prototype, "enabled", {
         /**
          * Is this model enabled?
@@ -103237,9 +103275,9 @@ var BABYLON;
         GLTFFileLoader.prototype.whenCompleteAsync = function () {
             var _this = this;
             return new Promise(function (resolve) {
-                _this.onCompleteObservable.add(function () {
+                _this.onCompleteObservable.addOnce(function () {
                     resolve();
-                }, undefined, undefined, undefined, true);
+                });
             });
         };
         Object.defineProperty(GLTFFileLoader.prototype, "loaderState", {
@@ -105819,6 +105857,8 @@ var BABYLON;
             function GLTFLoader() {
                 /** @hidden */
                 this._completePromises = new Array();
+                /** @hidden */
+                this._onReadyObservable = new BABYLON.Observable();
                 this._disposed = false;
                 this._state = null;
                 this._extensions = {};
@@ -106000,6 +106040,7 @@ var BABYLON;
                     }
                     var resultPromise = Promise.all(promises).then(function () {
                         _this._state = BABYLON.GLTFLoaderState.READY;
+                        _this._onReadyObservable.notifyObservers(_this);
                         _this._startAnimations();
                     });
                     resultPromise.then(function () {
@@ -107315,6 +107356,7 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                this._onReadyObservable.clear();
                 for (var name_4 in this._extensions) {
                     this._extensions[name_4].dispose();
                 }
@@ -107447,25 +107489,66 @@ var BABYLON;
              */
             var MSFT_lod = /** @class */ (function (_super) {
                 __extends(MSFT_lod, _super);
-                function MSFT_lod() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function MSFT_lod(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
                     /**
                      * Maximum number of LODs to load, starting from the lowest LOD.
                      */
                     _this.maxLODsToLoad = Number.MAX_VALUE;
+                    /**
+                     * Observable raised when all node LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onNodeLODsLoadedObservable = new BABYLON.Observable();
+                    /**
+                     * Observable raised when all material LODs of one level are loaded.
+                     * The event data is the index of the loaded LOD starting from zero.
+                     * Dispose the loader to cancel the loading of the next level of LODs.
+                     */
+                    _this.onMaterialLODsLoadedObservable = new BABYLON.Observable();
                     _this._loadingNodeLOD = null;
                     _this._loadNodeSignals = {};
+                    _this._loadNodePromises = new Array();
                     _this._loadingMaterialLOD = null;
                     _this._loadMaterialSignals = {};
+                    _this._loadMaterialPromises = new Array();
+                    _this._loader._onReadyObservable.addOnce(function () {
+                        var _loop_1 = function (indexLOD) {
+                            Promise.all(_this._loadNodePromises[indexLOD]).then(function () {
+                                _this.onNodeLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadNodePromises.length; indexLOD++) {
+                            _loop_1(indexLOD);
+                        }
+                        var _loop_2 = function (indexLOD) {
+                            Promise.all(_this._loadMaterialPromises[indexLOD]).then(function () {
+                                _this.onMaterialLODsLoadedObservable.notifyObservers(indexLOD);
+                            });
+                        };
+                        for (var indexLOD = 0; indexLOD < _this._loadMaterialPromises.length; indexLOD++) {
+                            _loop_2(indexLOD);
+                        }
+                    });
                     return _this;
                 }
+                MSFT_lod.prototype.dispose = function () {
+                    _super.prototype.dispose.call(this);
+                    this._loadingNodeLOD = null;
+                    this._loadNodeSignals = {};
+                    this._loadingMaterialLOD = null;
+                    this._loadMaterialSignals = {};
+                    this.onMaterialLODsLoadedObservable.clear();
+                    this.onNodeLODsLoadedObservable.clear();
+                };
                 MSFT_lod.prototype._loadNodeAsync = function (context, node) {
                     var _this = this;
                     return this._loadExtensionAsync(context, node, function (extensionContext, extension) {
                         var firstPromise;
                         var nodeLODs = _this._getLODs(extensionContext, node, _this._loader._gltf.nodes, extension.ids);
-                        var _loop_1 = function (indexLOD) {
+                        var _loop_3 = function (indexLOD) {
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
@@ -107496,9 +107579,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingNodeLOD = null;
                             }
+                            _this._loadNodePromises[indexLOD] = _this._loadNodePromises[indexLOD] || [];
+                            _this._loadNodePromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < nodeLODs.length; indexLOD++) {
-                            _loop_1(indexLOD);
+                            _loop_3(indexLOD);
                         }
                         return firstPromise;
                     });
@@ -107512,7 +107597,7 @@ var BABYLON;
                     return this._loadExtensionAsync(context, material, function (extensionContext, extension) {
                         var firstPromise;
                         var materialLODs = _this._getLODs(extensionContext, material, _this._loader._gltf.materials, extension.ids);
-                        var _loop_2 = function (indexLOD) {
+                        var _loop_4 = function (indexLOD) {
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
@@ -107545,9 +107630,11 @@ var BABYLON;
                                 _this._loader._completePromises.push(promise);
                                 _this._loadingMaterialLOD = null;
                             }
+                            _this._loadMaterialPromises[indexLOD] = _this._loadMaterialPromises[indexLOD] || [];
+                            _this._loadMaterialPromises[indexLOD].push(promise);
                         };
                         for (var indexLOD = 0; indexLOD < materialLODs.length; indexLOD++) {
-                            _loop_2(indexLOD);
+                            _loop_4(indexLOD);
                         }
                         return firstPromise;
                     });
@@ -108164,7 +108251,7 @@ var SceneManager = /** @class */ (function () {
         this._white = babylonjs_1.Color3.White();
         this._processShadows = true;
         this._groundEnabled = true;
-        this._groundMirrorEnabled = false;
+        this._groundMirrorEnabled = true;
         this._defaultRenderingPipelineEnabled = false;
         this._defaultRenderingPipelineShouldBuild = true;
         // default from rendering pipeline
@@ -108212,7 +108299,13 @@ var SceneManager = /** @class */ (function () {
                     // make sure all models are loaded
                     updateShadows();
                 }
-                else if (!(_this.models.every(function (model) { return model.state === viewerModel_1.ModelState.COMPLETE && !model.currentAnimation; }))) {
+                else if (!(_this.models.every(function (model) {
+                    if (!model.shadowsRenderedAfterLoad) {
+                        model.shadowsRenderedAfterLoad = true;
+                        return false;
+                    }
+                    return model.state === viewerModel_1.ModelState.COMPLETE && !model.currentAnimation;
+                }))) {
                     updateShadows();
                 }
             });
@@ -108341,7 +108434,7 @@ var SceneManager = /** @class */ (function () {
             }
             this._groundMirrorEnabled = value;
             if (this.environmentHelper && this.environmentHelper.groundMaterial && this.environmentHelper.groundMirror) {
-                if (value) {
+                if (!value) {
                     this.environmentHelper.groundMaterial.reflectionTexture = null;
                 }
                 else {
@@ -108501,7 +108594,7 @@ var SceneManager = /** @class */ (function () {
         }
     };
     SceneManager.prototype._rebuildPostprocesses = function (configuration) {
-        if (!this.defaultRenderingPipelineEnabled || !configuration_1.getConfigurationKey("scene.imageProcessingConfiguration.isEnabled", this._viewer.configuration)) {
+        if (!this._defaultRenderingPipelineEnabled || !configuration_1.getConfigurationKey("scene.imageProcessingConfiguration.isEnabled", this._viewer.configuration)) {
             if (this._defaultRenderingPipeline) {
                 this._defaultRenderingPipeline.dispose();
                 this._defaultRenderingPipeline = null;
@@ -108832,133 +108925,134 @@ var SceneManager = /** @class */ (function () {
                 delete this.environmentHelper;
             }
             ;
-            return Promise.resolve(this.scene);
         }
-        var options = {
-            createGround: !!groundConfiguration && this._groundEnabled,
-            createSkybox: !!skyboxConifguration,
-            setupImageProcessing: false,
-        };
-        // will that cause problems with model ground configuration?
-        /*if (model) {
-            const boundingInfo = model.rootMesh.getHierarchyBoundingVectors(true);
-            const sizeVec = boundingInfo.max.subtract(boundingInfo.min);
-            const halfSizeVec = sizeVec.scale(0.5);
-            const center = boundingInfo.min.add(halfSizeVec);
-            options.groundYBias = -center.y;
-        }*/
-        if (groundConfiguration) {
-            var groundConfig_1 = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
-            var groundSize = groundConfig_1.size || (typeof skyboxConifguration === 'object' && skyboxConifguration.scale);
-            if (groundSize) {
-                options.groundSize = groundSize;
-            }
-            options.enableGroundShadow = groundConfig_1 === true || groundConfig_1.receiveShadows;
-            if (groundConfig_1.shadowLevel !== undefined) {
-                options.groundShadowLevel = groundConfig_1.shadowLevel;
-            }
-            options.enableGroundMirror = !!groundConfig_1.mirror && this.groundMirrorEnabled;
-            if (groundConfig_1.texture) {
-                options.groundTexture = this.labs.getAssetUrl(groundConfig_1.texture);
-            }
-            if (groundConfig_1.color) {
-                options.groundColor = new babylonjs_1.Color3(groundConfig_1.color.r, groundConfig_1.color.g, groundConfig_1.color.b);
-            }
-            if (groundConfig_1.opacity !== undefined) {
-                options.groundOpacity = groundConfig_1.opacity;
-            }
-            if (groundConfig_1.mirror) {
-                options.enableGroundMirror = true;
-                // to prevent undefines
-                if (typeof groundConfig_1.mirror === "object") {
-                    if (groundConfig_1.mirror.amount !== undefined)
-                        options.groundMirrorAmount = groundConfig_1.mirror.amount;
-                    if (groundConfig_1.mirror.sizeRatio !== undefined)
-                        options.groundMirrorSizeRatio = groundConfig_1.mirror.sizeRatio;
-                    if (groundConfig_1.mirror.blurKernel !== undefined)
-                        options.groundMirrorBlurKernel = groundConfig_1.mirror.blurKernel;
-                    if (groundConfig_1.mirror.fresnelWeight !== undefined)
-                        options.groundMirrorFresnelWeight = groundConfig_1.mirror.fresnelWeight;
-                    if (groundConfig_1.mirror.fallOffDistance !== undefined)
-                        options.groundMirrorFallOffDistance = groundConfig_1.mirror.fallOffDistance;
-                    if (this._defaultPipelineTextureType !== undefined)
-                        options.groundMirrorTextureType = this._defaultPipelineTextureType;
+        else {
+            var options = {
+                createGround: !!groundConfiguration && this._groundEnabled,
+                createSkybox: !!skyboxConifguration,
+                setupImageProcessing: false,
+            };
+            // will that cause problems with model ground configuration?
+            /*if (model) {
+                const boundingInfo = model.rootMesh.getHierarchyBoundingVectors(true);
+                const sizeVec = boundingInfo.max.subtract(boundingInfo.min);
+                const halfSizeVec = sizeVec.scale(0.5);
+                const center = boundingInfo.min.add(halfSizeVec);
+                options.groundYBias = -center.y;
+            }*/
+            if (groundConfiguration) {
+                var groundConfig_1 = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
+                var groundSize = groundConfig_1.size || (typeof skyboxConifguration === 'object' && skyboxConifguration.scale);
+                if (groundSize) {
+                    options.groundSize = groundSize;
+                }
+                options.enableGroundShadow = groundConfig_1 === true || groundConfig_1.receiveShadows;
+                if (groundConfig_1.shadowLevel !== undefined) {
+                    options.groundShadowLevel = groundConfig_1.shadowLevel;
+                }
+                options.enableGroundMirror = !!groundConfig_1.mirror && this.groundMirrorEnabled;
+                if (groundConfig_1.texture) {
+                    options.groundTexture = this.labs.getAssetUrl(groundConfig_1.texture);
+                }
+                if (groundConfig_1.color) {
+                    options.groundColor = new babylonjs_1.Color3(groundConfig_1.color.r, groundConfig_1.color.g, groundConfig_1.color.b);
+                }
+                if (groundConfig_1.opacity !== undefined) {
+                    options.groundOpacity = groundConfig_1.opacity;
+                }
+                if (groundConfig_1.mirror) {
+                    options.enableGroundMirror = true;
+                    // to prevent undefines
+                    if (typeof groundConfig_1.mirror === "object") {
+                        if (groundConfig_1.mirror.amount !== undefined)
+                            options.groundMirrorAmount = groundConfig_1.mirror.amount;
+                        if (groundConfig_1.mirror.sizeRatio !== undefined)
+                            options.groundMirrorSizeRatio = groundConfig_1.mirror.sizeRatio;
+                        if (groundConfig_1.mirror.blurKernel !== undefined)
+                            options.groundMirrorBlurKernel = groundConfig_1.mirror.blurKernel;
+                        if (groundConfig_1.mirror.fresnelWeight !== undefined)
+                            options.groundMirrorFresnelWeight = groundConfig_1.mirror.fresnelWeight;
+                        if (groundConfig_1.mirror.fallOffDistance !== undefined)
+                            options.groundMirrorFallOffDistance = groundConfig_1.mirror.fallOffDistance;
+                        if (this._defaultPipelineTextureType !== undefined)
+                            options.groundMirrorTextureType = this._defaultPipelineTextureType;
+                    }
                 }
             }
-        }
-        var postInitSkyboxMaterial = false;
-        if (skyboxConifguration) {
-            var conf = skyboxConifguration === true ? {} : skyboxConifguration;
-            if (conf.material && conf.material.imageProcessingConfiguration) {
-                options.setupImageProcessing = false; // will be configured later manually.
-            }
-            var skyboxSize = conf.scale;
-            if (skyboxSize) {
-                options.skyboxSize = skyboxSize;
-            }
-            options.sizeAuto = !options.skyboxSize;
-            if (conf.color) {
-                options.skyboxColor = new babylonjs_1.Color3(conf.color.r, conf.color.g, conf.color.b);
-            }
-            if (conf.cubeTexture && conf.cubeTexture.url) {
-                if (typeof conf.cubeTexture.url === "string") {
-                    options.skyboxTexture = this.labs.getAssetUrl(conf.cubeTexture.url);
+            var postInitSkyboxMaterial = false;
+            if (skyboxConifguration) {
+                var conf = skyboxConifguration === true ? {} : skyboxConifguration;
+                if (conf.material && conf.material.imageProcessingConfiguration) {
+                    options.setupImageProcessing = false; // will be configured later manually.
                 }
-                else {
-                    // init later!
+                var skyboxSize = conf.scale;
+                if (skyboxSize) {
+                    options.skyboxSize = skyboxSize;
+                }
+                options.sizeAuto = !options.skyboxSize;
+                if (conf.color) {
+                    options.skyboxColor = new babylonjs_1.Color3(conf.color.r, conf.color.g, conf.color.b);
+                }
+                if (conf.cubeTexture && conf.cubeTexture.url) {
+                    if (typeof conf.cubeTexture.url === "string") {
+                        options.skyboxTexture = this.labs.getAssetUrl(conf.cubeTexture.url);
+                    }
+                    else {
+                        // init later!
+                        postInitSkyboxMaterial = true;
+                    }
+                }
+                if (conf.material) {
                     postInitSkyboxMaterial = true;
                 }
             }
-            if (conf.material) {
-                postInitSkyboxMaterial = true;
-            }
-        }
-        options.setupImageProcessing = false; // TMP
-        if (!this.environmentHelper) {
-            this.environmentHelper = this.scene.createDefaultEnvironment(options);
-        }
-        else {
-            // unlikely, but there might be a new scene! we need to dispose.
-            // get the scene used by the envHelper
-            var scene = this.environmentHelper.rootMesh.getScene();
-            // is it a different scene? Oh no!
-            if (scene !== this.scene) {
-                this.environmentHelper.dispose();
+            options.setupImageProcessing = false; // TMP
+            if (!this.environmentHelper) {
                 this.environmentHelper = this.scene.createDefaultEnvironment(options);
             }
             else {
-                this.environmentHelper.updateOptions(options);
+                // unlikely, but there might be a new scene! we need to dispose.
+                // get the scene used by the envHelper
+                var scene = this.environmentHelper.rootMesh.getScene();
+                // is it a different scene? Oh no!
+                if (scene !== this.scene) {
+                    this.environmentHelper.dispose();
+                    this.environmentHelper = this.scene.createDefaultEnvironment(options);
+                }
+                else {
+                    this.environmentHelper.updateOptions(options);
+                }
             }
-        }
-        if (this.environmentHelper.rootMesh && this._viewer.configuration.scene && this._viewer.configuration.scene.environmentRotationY !== undefined) {
-            this.environmentHelper.rootMesh.rotation.y = this._viewer.configuration.scene.environmentRotationY;
-        }
-        var groundConfig = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
-        if (this.environmentHelper.groundMaterial && groundConfig) {
-            this.environmentHelper.groundMaterial._perceptualColor = this.mainColor;
-            if (groundConfig.material) {
-                helper_1.extendClassWithConfig(this.environmentHelper.groundMaterial, groundConfig.material);
+            if (this.environmentHelper.rootMesh && this._viewer.configuration.scene && this._viewer.configuration.scene.environmentRotationY !== undefined) {
+                this.environmentHelper.rootMesh.rotation.y = this._viewer.configuration.scene.environmentRotationY;
             }
-            if (this.environmentHelper.groundMirror) {
-                var mirrorClearColor = this.environmentHelper.groundMaterial._perceptualColor.toLinearSpace();
-                // TODO user camera exposure value to set the mirror clear color
-                var exposure = Math.pow(2.0, -this.scene.imageProcessingConfiguration.exposure) * Math.PI;
-                mirrorClearColor.scaleToRef(1 / exposure, mirrorClearColor);
-                this.environmentHelper.groundMirror.clearColor.r = babylonjs_1.Scalar.Clamp(mirrorClearColor.r);
-                this.environmentHelper.groundMirror.clearColor.g = babylonjs_1.Scalar.Clamp(mirrorClearColor.g);
-                this.environmentHelper.groundMirror.clearColor.b = babylonjs_1.Scalar.Clamp(mirrorClearColor.b);
-                this.environmentHelper.groundMirror.clearColor.a = 1;
-                if (!this.groundMirrorEnabled) {
-                    this.environmentHelper.groundMaterial.reflectionTexture = null;
+            var groundConfig = (typeof groundConfiguration === 'boolean') ? {} : groundConfiguration;
+            if (this.environmentHelper.groundMaterial && groundConfig) {
+                this.environmentHelper.groundMaterial._perceptualColor = this.mainColor;
+                if (groundConfig.material) {
+                    helper_1.extendClassWithConfig(this.environmentHelper.groundMaterial, groundConfig.material);
+                }
+                if (this.environmentHelper.groundMirror) {
+                    var mirrorClearColor = this.environmentHelper.groundMaterial._perceptualColor.toLinearSpace();
+                    // TODO user camera exposure value to set the mirror clear color
+                    var exposure = Math.pow(2.0, -this.scene.imageProcessingConfiguration.exposure) * Math.PI;
+                    mirrorClearColor.scaleToRef(1 / exposure, mirrorClearColor);
+                    this.environmentHelper.groundMirror.clearColor.r = babylonjs_1.Scalar.Clamp(mirrorClearColor.r);
+                    this.environmentHelper.groundMirror.clearColor.g = babylonjs_1.Scalar.Clamp(mirrorClearColor.g);
+                    this.environmentHelper.groundMirror.clearColor.b = babylonjs_1.Scalar.Clamp(mirrorClearColor.b);
+                    this.environmentHelper.groundMirror.clearColor.a = 1;
+                    if (!this.groundMirrorEnabled) {
+                        this.environmentHelper.groundMaterial.reflectionTexture = null;
+                    }
                 }
             }
-        }
-        var skyboxMaterial = this.environmentHelper.skyboxMaterial;
-        if (skyboxMaterial) {
-            skyboxMaterial._perceptualColor = this.mainColor;
-            if (postInitSkyboxMaterial) {
-                if (typeof skyboxConifguration === 'object' && skyboxConifguration.material) {
-                    helper_1.extendClassWithConfig(skyboxMaterial, skyboxConifguration.material);
+            var skyboxMaterial = this.environmentHelper.skyboxMaterial;
+            if (skyboxMaterial) {
+                skyboxMaterial._perceptualColor = this.mainColor;
+                if (postInitSkyboxMaterial) {
+                    if (typeof skyboxConifguration === 'object' && skyboxConifguration.material) {
+                        helper_1.extendClassWithConfig(skyboxMaterial, skyboxConifguration.material);
+                    }
                 }
             }
         }
@@ -108987,124 +109081,124 @@ var SceneManager = /** @class */ (function () {
         if (!Object.keys(lightsConfiguration).length) {
             if (!this.scene.lights.length)
                 this.scene.createDefaultLight(true);
-            return;
-        }
-        ;
-        var lightsAvailable = this.scene.lights.map(function (light) { return light.name; });
-        // compare to the global (!) configuration object and dispose unneeded:
-        var lightsToConfigure = Object.keys(this._viewer.configuration.lights || []);
-        if (Object.keys(lightsToConfigure).length !== lightsAvailable.length) {
-            lightsAvailable.forEach(function (lName) {
-                if (lightsToConfigure.indexOf(lName) === -1) {
-                    _this.scene.getLightByName(lName).dispose();
-                }
-            });
         }
-        Object.keys(lightsConfiguration).forEach(function (name, idx) {
-            var lightConfig = { type: 0 };
-            if (typeof lightsConfiguration[name] === 'object') {
-                lightConfig = lightsConfiguration[name];
-            }
-            lightConfig.name = name;
-            var light;
-            // light is not already available
-            if (lightsAvailable.indexOf(name) === -1) {
-                var constructor = babylonjs_1.Light.GetConstructorFromName(lightConfig.type, lightConfig.name, _this.scene);
-                if (!constructor)
-                    return;
-                light = constructor();
+        else {
+            var lightsAvailable_1 = this.scene.lights.map(function (light) { return light.name; });
+            // compare to the global (!) configuration object and dispose unneeded:
+            var lightsToConfigure_1 = Object.keys(this._viewer.configuration.lights || []);
+            if (Object.keys(lightsToConfigure_1).length !== lightsAvailable_1.length) {
+                lightsAvailable_1.forEach(function (lName) {
+                    if (lightsToConfigure_1.indexOf(lName) === -1) {
+                        _this.scene.getLightByName(lName).dispose();
+                    }
+                });
             }
-            else {
-                // available? get it from the scene
-                light = _this.scene.getLightByName(name);
-                lightsAvailable = lightsAvailable.filter(function (ln) { return ln !== name; });
-                if (lightConfig.type !== undefined && light.getTypeID() !== lightConfig.type) {
-                    light.dispose();
+            Object.keys(lightsConfiguration).forEach(function (name, idx) {
+                var lightConfig = { type: 0 };
+                if (typeof lightsConfiguration[name] === 'object') {
+                    lightConfig = lightsConfiguration[name];
+                }
+                lightConfig.name = name;
+                var light;
+                // light is not already available
+                if (lightsAvailable_1.indexOf(name) === -1) {
                     var constructor = babylonjs_1.Light.GetConstructorFromName(lightConfig.type, lightConfig.name, _this.scene);
                     if (!constructor)
                         return;
                     light = constructor();
                 }
-            }
-            // if config set the light to false, dispose it.
-            if (lightsConfiguration[name] === false) {
-                light.dispose();
-                return;
-            }
-            //enabled
-            var enabled = lightConfig.enabled !== undefined ? lightConfig.enabled : !lightConfig.disabled;
-            light.setEnabled(enabled);
-            helper_1.extendClassWithConfig(light, lightConfig);
-            //position. Some lights don't support shadows
-            if (light instanceof babylonjs_1.ShadowLight) {
-                // set default values
-                light.shadowMinZ = light.shadowMinZ || 0.2;
-                light.shadowMaxZ = Math.min(10, light.shadowMaxZ || 10); //large far clips reduce shadow depth precision
-                if (lightConfig.target) {
-                    if (light.setDirectionToTarget) {
-                        var target = babylonjs_1.Vector3.Zero().copyFrom(lightConfig.target);
-                        light.setDirectionToTarget(target);
+                else {
+                    // available? get it from the scene
+                    light = _this.scene.getLightByName(name);
+                    lightsAvailable_1 = lightsAvailable_1.filter(function (ln) { return ln !== name; });
+                    if (lightConfig.type !== undefined && light.getTypeID() !== lightConfig.type) {
+                        light.dispose();
+                        var constructor = babylonjs_1.Light.GetConstructorFromName(lightConfig.type, lightConfig.name, _this.scene);
+                        if (!constructor)
+                            return;
+                        light = constructor();
                     }
                 }
-                else if (lightConfig.direction) {
-                    var direction = babylonjs_1.Vector3.Zero().copyFrom(lightConfig.direction);
-                    light.direction = direction;
-                }
-                var isShadowEnabled = false;
-                if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
-                    light.shadowFrustumSize = lightConfig.shadowFrustumSize || 2;
-                    isShadowEnabled = true;
+                // if config set the light to false, dispose it.
+                if (lightsConfiguration[name] === false) {
+                    light.dispose();
+                    return;
                 }
-                else if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_SPOTLIGHT) {
-                    var spotLight = light;
-                    if (lightConfig.spotAngle !== undefined) {
-                        spotLight.angle = lightConfig.spotAngle * Math.PI / 180;
+                //enabled
+                var enabled = lightConfig.enabled !== undefined ? lightConfig.enabled : !lightConfig.disabled;
+                light.setEnabled(enabled);
+                helper_1.extendClassWithConfig(light, lightConfig);
+                //position. Some lights don't support shadows
+                if (light instanceof babylonjs_1.ShadowLight) {
+                    // set default values
+                    light.shadowMinZ = light.shadowMinZ || 0.2;
+                    light.shadowMaxZ = Math.min(10, light.shadowMaxZ || 10); //large far clips reduce shadow depth precision
+                    if (lightConfig.target) {
+                        if (light.setDirectionToTarget) {
+                            var target = babylonjs_1.Vector3.Zero().copyFrom(lightConfig.target);
+                            light.setDirectionToTarget(target);
+                        }
                     }
-                    if (spotLight.angle && lightConfig.shadowFieldOfView) {
-                        spotLight.shadowAngleScale = lightConfig.shadowFieldOfView / spotLight.angle;
+                    else if (lightConfig.direction) {
+                        var direction = babylonjs_1.Vector3.Zero().copyFrom(lightConfig.direction);
+                        light.direction = direction;
                     }
-                    isShadowEnabled = true;
-                }
-                else if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_POINTLIGHT) {
-                    if (lightConfig.shadowFieldOfView) {
-                        light.shadowAngle = lightConfig.shadowFieldOfView * Math.PI / 180;
+                    var isShadowEnabled = false;
+                    if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
+                        light.shadowFrustumSize = lightConfig.shadowFrustumSize || 2;
+                        isShadowEnabled = true;
                     }
-                    isShadowEnabled = true;
-                }
-                var shadowGenerator_1 = light.getShadowGenerator();
-                if (isShadowEnabled && lightConfig.shadowEnabled && _this._maxShadows) {
-                    var bufferSize = lightConfig.shadowBufferSize || 256;
-                    if (!shadowGenerator_1) {
-                        shadowGenerator_1 = new babylonjs_1.ShadowGenerator(bufferSize, light);
+                    else if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_SPOTLIGHT) {
+                        var spotLight = light;
+                        if (lightConfig.spotAngle !== undefined) {
+                            spotLight.angle = lightConfig.spotAngle * Math.PI / 180;
+                        }
+                        if (spotLight.angle && lightConfig.shadowFieldOfView) {
+                            spotLight.shadowAngleScale = lightConfig.shadowFieldOfView / spotLight.angle;
+                        }
+                        isShadowEnabled = true;
+                    }
+                    else if (light.getTypeID() === BABYLON.Light.LIGHTTYPEID_POINTLIGHT) {
+                        if (lightConfig.shadowFieldOfView) {
+                            light.shadowAngle = lightConfig.shadowFieldOfView * Math.PI / 180;
+                        }
+                        isShadowEnabled = true;
+                    }
+                    var shadowGenerator_1 = light.getShadowGenerator();
+                    if (isShadowEnabled && lightConfig.shadowEnabled && _this._maxShadows) {
+                        var bufferSize = lightConfig.shadowBufferSize || 256;
+                        if (!shadowGenerator_1) {
+                            shadowGenerator_1 = new babylonjs_1.ShadowGenerator(bufferSize, light);
+                        }
+                        var blurKernel = _this.getBlurKernel(light, bufferSize);
+                        shadowGenerator_1.bias = _this._shadowGeneratorBias;
+                        shadowGenerator_1.blurKernel = blurKernel;
+                        //override defaults
+                        helper_1.extendClassWithConfig(shadowGenerator_1, lightConfig.shadowConfig || {});
+                        // add the focues meshes to the shadow list
+                        _this._viewer.onModelLoadedObservable.add(function (model) {
+                            _this._updateShadowRenderList(shadowGenerator_1, model);
+                        });
+                        //if (model) {
+                        _this._updateShadowRenderList(shadowGenerator_1);
+                        //}
+                    }
+                    else if (shadowGenerator_1) {
+                        shadowGenerator_1.dispose();
                     }
-                    var blurKernel = _this.getBlurKernel(light, bufferSize);
-                    shadowGenerator_1.bias = _this._shadowGeneratorBias;
-                    shadowGenerator_1.blurKernel = blurKernel;
-                    //override defaults
-                    helper_1.extendClassWithConfig(shadowGenerator_1, lightConfig.shadowConfig || {});
-                    // add the focues meshes to the shadow list
-                    _this._viewer.onModelLoadedObservable.add(function (model) {
-                        _this._updateShadowRenderList(shadowGenerator_1, model);
-                    });
-                    //if (model) {
-                    _this._updateShadowRenderList(shadowGenerator_1);
-                    //}
-                }
-                else if (shadowGenerator_1) {
-                    shadowGenerator_1.dispose();
                 }
-            }
-        });
-        // render priority
-        var globalLightsConfiguration = this._viewer.configuration.lights || {};
-        Object.keys(globalLightsConfiguration).sort().forEach(function (name, idx) {
-            var configuration = globalLightsConfiguration[name];
-            var light = _this.scene.getLightByName(name);
-            // sanity check
-            if (!light)
-                return;
-            light.renderPriority = -idx;
-        });
+            });
+            // render priority
+            var globalLightsConfiguration_1 = this._viewer.configuration.lights || {};
+            Object.keys(globalLightsConfiguration_1).sort().forEach(function (name, idx) {
+                var configuration = globalLightsConfiguration_1[name];
+                var light = _this.scene.getLightByName(name);
+                // sanity check
+                if (!light)
+                    return;
+                light.renderPriority = -idx;
+            });
+        }
         this.onLightsConfiguredObservable.notifyObservers({
             sceneManager: this,
             object: this.scene.lights,

+ 2 - 1
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -612,6 +612,7 @@ declare module 'babylonjs-viewer/model/viewerModel' {
             loadId: number;
             loadInfo: GLTF2.IAsset;
             constructor(_viewer: AbstractViewer, modelConfiguration: IModelConfiguration);
+            shadowsRenderedAfterLoad: boolean;
             /**
                 * Set whether this model is enabled or not.
                 */
@@ -1856,7 +1857,7 @@ declare module 'babylonjs-viewer/viewer/sceneManager' {
                 * @param model optionally use the model to configure the camera.
                 */
             protected _configureCamera(cameraConfig?: ICameraConfiguration): void;
-            protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): Promise<Scene> | undefined;
+            protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): void;
             /**
                 * configure the lights.
                 *

+ 1 - 1
inspector/src/tabs/StatsTab.ts

@@ -159,7 +159,7 @@ module INSPECTOR {
             title = Helpers.CreateDiv('stat-title2', this._panel);
             title.textContent = "Duration";
             {
-                this._createStatLabel("Refresh rate (refresh by second)", this._panel);
+                this._createStatLabel("Properties refresh rate (per second)", this._panel);
                 let elemValue = Helpers.CreateDiv('stat-value', this._panel);
                 this._inputElement = Inspector.DOCUMENT.createElement('input');
                 this._inputElement.value = this.refreshRate;

+ 2 - 1
src/Materials/Textures/babylon.texture.ts

@@ -106,7 +106,8 @@
         private _cachedProjectionMatrixId: number;
         private _cachedCoordinatesMode: number;
         public _samplingMode: number;
-        private _buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
+        /** @hidden */
+        public _buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
         private _deleteBuffer: boolean;
         protected _format: Nullable<number>;
         private _delayedOnLoad: Nullable<() => void>;

+ 12 - 11
src/Tools/babylon.assetsManager.ts

@@ -836,17 +836,6 @@ module BABYLON {
             this._waitingTasksCount--;
 
             try {
-                if (task.taskState === AssetTaskState.DONE) {
-                    // Let's remove successfull tasks
-                    Tools.SetImmediate(() => {
-                        let index = this._tasks.indexOf(task);
-
-                        if (index > -1) {
-                            this._tasks.splice(index, 1);
-                        }
-                    });
-                }
-
                 if (this.onProgress) {
                     this.onProgress(
                         this._waitingTasksCount,
@@ -873,6 +862,18 @@ module BABYLON {
                         this.onFinish(this._tasks);
                     }
 
+                    // Let's remove successfull tasks
+                    var currentTasks = this._tasks.slice();
+                    for (var task of currentTasks) {
+                        if (task.taskState === AssetTaskState.DONE) {                  
+                            let index = this._tasks.indexOf(task);
+
+                            if (index > -1) {
+                                this._tasks.splice(index, 1);
+                            }
+                        }
+                    }
+
                     this.onTasksDoneObservable.notifyObservers(this._tasks);
                 } catch (e) {
                     Tools.Error("Error running tasks-done callbacks.");

+ 15 - 0
src/babylon.scene.ts

@@ -5397,6 +5397,21 @@
             }
         }
 
+        /**
+         * This function will remove the local cached buffer data from texture.
+         * It will save memory but will prevent the texture from being rebuilt
+         */
+        public cleanCachedTextureBuffer(): void {
+            for (var baseTexture of this.textures) {
+                let buffer = (<Texture>baseTexture)._buffer;
+
+                if (buffer) {
+                    (<Texture>baseTexture)._buffer = null;
+                }
+            }
+        }
+        
+
         // Octrees
 
         /**