David Catuhe 7 年之前
父節點
當前提交
036e511952

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


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


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


+ 269 - 93
dist/preview release/babylon.max.js

@@ -9526,6 +9526,68 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.promise.js.map
 
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Helper class to push actions to a pool of workers.
+     */
+    var WorkerPool = /** @class */ (function () {
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        function WorkerPool(workers) {
+            this._pendingActions = new Array();
+            this._workerInfos = workers.map(function (worker) { return ({
+                worker: worker,
+                active: false
+            }); });
+        }
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        WorkerPool.prototype.dispose = function () {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                workerInfo.worker.terminate();
+            }
+            delete this._workerInfos;
+            delete this._pendingActions;
+        };
+        /**
+         * Pushes an action to the worker pool. If all the workers are active, the action will be
+         * pended until a worker has completed its action.
+         * @param action The action to perform. Call onComplete when the action is complete.
+         */
+        WorkerPool.prototype.push = function (action) {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                if (!workerInfo.active) {
+                    this._execute(workerInfo, action);
+                    return;
+                }
+            }
+            this._pendingActions.push(action);
+        };
+        WorkerPool.prototype._execute = function (workerInfo, action) {
+            var _this = this;
+            workerInfo.active = true;
+            action(workerInfo.worker, function () {
+                workerInfo.active = false;
+                var nextAction = _this._pendingActions.shift();
+                if (nextAction) {
+                    _this._execute(workerInfo, nextAction);
+                }
+            });
+        };
+        return WorkerPool;
+    }());
+    BABYLON.WorkerPool = WorkerPool;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.workerPool.js.map
+
 var BABYLON;
 (function (BABYLON) {
     var _AlphaState = /** @class */ (function () {
@@ -21337,6 +21399,7 @@ var BABYLON;
             this._useAlternateCameraConfiguration = false;
             this._alternateRendering = false;
             this.requireLightSorting = false;
+            this._depthRenderer = {};
             this._activeMeshesFrozen = false;
             this._tempPickingRay = BABYLON.Ray ? BABYLON.Ray.Zero() : null;
             this._engine = engine || BABYLON.Engine.LastCreatedEngine;
@@ -24115,8 +24178,8 @@ var BABYLON;
                 }
             }
             // Depth renderer
-            if (this._depthRenderer) {
-                this._renderTargets.push(this._depthRenderer.getDepthMap());
+            for (var key in this._depthRenderer) {
+                this._renderTargets.push(this._depthRenderer[key].getDepthMap());
             }
             // Geometry renderer
             if (this._geometryBufferRenderer) {
@@ -24285,19 +24348,32 @@ var BABYLON;
                 this.soundTracks[i].switchPanningModelToEqualPower();
             }
         };
-        Scene.prototype.enableDepthRenderer = function () {
-            if (this._depthRenderer) {
-                return this._depthRenderer;
+        /**
+         * Creates a depth renderer a given camera which contains a depth map which can be used for post processing.
+         * @param camera The camera to create the depth renderer on (default: scene's active camera)
+         * @returns the created depth renderer
+         */
+        Scene.prototype.enableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera) {
+                throw "No camera available to enable depth renderer";
             }
-            this._depthRenderer = new BABYLON.DepthRenderer(this);
-            return this._depthRenderer;
+            if (!this._depthRenderer[camera.id]) {
+                this._depthRenderer[camera.id] = new BABYLON.DepthRenderer(this, BABYLON.Engine.TEXTURETYPE_FLOAT, camera);
+            }
+            return this._depthRenderer[camera.id];
         };
-        Scene.prototype.disableDepthRenderer = function () {
-            if (!this._depthRenderer) {
+        /**
+         * Disables a depth renderer for a given camera
+         * @param camera The camera to disable the depth renderer on (default: scene's active camera)
+         */
+        Scene.prototype.disableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera || !this._depthRenderer[camera.id]) {
                 return;
             }
-            this._depthRenderer.dispose();
-            this._depthRenderer = null;
+            this._depthRenderer[camera.id].dispose();
+            delete this._depthRenderer[camera.id];
         };
         Scene.prototype.enableGeometryBufferRenderer = function (ratio) {
             if (ratio === void 0) { ratio = 1; }
@@ -24335,8 +24411,8 @@ var BABYLON;
             this.importedMeshesFiles = new Array();
             this.stopAllAnimations();
             this.resetCachedMaterial();
-            if (this._depthRenderer) {
-                this._depthRenderer.dispose();
+            for (var key in this._depthRenderer) {
+                this._depthRenderer[key].dispose();
             }
             if (this._gamepadManager) {
                 this._gamepadManager.dispose();
@@ -24502,7 +24578,7 @@ var BABYLON;
         /**
          * Get the world extend vectors with an optional filter
          *
-         * @param {(mesh: AbstractMesh) => boolean} [filterPredicate] the predicate - which meshes should be included when calculating the world size
+         * @param filterPredicate the predicate - which meshes should be included when calculating the world size
          * @returns {{ min: Vector3; max: Vector3 }} min and max vectors
          */
         Scene.prototype.getWorldExtends = function (filterPredicate) {
@@ -56399,96 +56475,167 @@ var BABYLON;
      * Draco compression (https://google.github.io/draco/)
      */
     var DracoCompression = /** @class */ (function () {
-        function DracoCompression() {
+        /**
+         * Constructor
+         * @param numWorkers The number of workers for async operations
+         */
+        function DracoCompression(numWorkers) {
+            if (numWorkers === void 0) { numWorkers = (navigator.hardwareConcurrency || 4); }
+            var workers = new Array(numWorkers);
+            for (var i = 0; i < workers.length; i++) {
+                var worker = new Worker(DracoCompression._WorkerBlobUrl);
+                worker.postMessage({ id: "initDecoder", url: DracoCompression.DecoderUrl });
+                workers[i] = worker;
+            }
+            this._workerPool = new BABYLON.WorkerPool(workers);
         }
-        Object.defineProperty(DracoCompression, "IsSupported", {
-            /**
-             * Returns whether Draco compression is supported.
-             */
-            get: function () {
-                return BABYLON.Tools.IsWindowObjectExist() && !!window.DracoDecoderModule;
-            },
-            enumerable: true,
-            configurable: true
-        });
         /**
-         * Decodes Draco compressed data to vertex data.
+         * Stop all async operations and release resources.
+         */
+        DracoCompression.prototype.dispose = function () {
+            this._workerPool.dispose();
+            delete this._workerPool;
+        };
+        /**
+         * Decode Draco compressed mesh data to vertex data.
          * @param data The array buffer view for the Draco compression data
          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns The decoded vertex data
-         */
-        DracoCompression.Decode = function (data, attributes) {
-            var dracoModule = new DracoDecoderModule();
-            var buffer = new dracoModule.DecoderBuffer();
-            buffer.Init(data, data.byteLength);
-            var decoder = new dracoModule.Decoder();
-            var geometry;
-            var status;
-            var vertexData = new BABYLON.VertexData();
-            try {
-                var type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case dracoModule.TRIANGULAR_MESH:
-                        geometry = new dracoModule.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case dracoModule.POINT_CLOUD:
-                        geometry = new dracoModule.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error("Invalid geometry type " + type);
-                }
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
-                var numPoints = geometry.num_points();
-                if (type === dracoModule.TRIANGULAR_MESH) {
-                    var numFaces = geometry.num_faces();
-                    var faceIndices = new dracoModule.DracoInt32Array();
-                    try {
-                        vertexData.indices = new Uint32Array(numFaces * 3);
-                        for (var i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            var offset = i * 3;
-                            vertexData.indices[offset + 0] = faceIndices.GetValue(0);
-                            vertexData.indices[offset + 1] = faceIndices.GetValue(1);
-                            vertexData.indices[offset + 2] = faceIndices.GetValue(2);
+         * @returns A promise that resolves with the decoded vertex data
+         */
+        DracoCompression.prototype.decodeMeshAsync = function (data, attributes) {
+            var _this = this;
+            return new Promise(function (resolve, reject) {
+                _this._workerPool.push(function (worker, onComplete) {
+                    var vertexData = new BABYLON.VertexData();
+                    var onError = function (error) {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
+                    var onMessage = function (message) {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
+                        }
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
                         }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
+                        }
+                    };
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+                    var dataCopy = new Uint8Array(data.byteLength);
+                    dataCopy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
+                    worker.postMessage({ id: "decodeMesh", data: dataCopy, attributes: attributes }, [dataCopy.buffer]);
+                });
+            });
+        };
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        DracoCompression._Worker = function () {
+            // self is actually a DedicatedWorkerGlobalScope
+            var _self = self;
+            var decodeMesh = function (data, attributes) {
+                var dracoModule = new DracoDecoderModule();
+                var buffer = new dracoModule.DecoderBuffer();
+                buffer.Init(data, data.byteLength);
+                var decoder = new dracoModule.Decoder();
+                var geometry;
+                var status;
+                try {
+                    var type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case dracoModule.TRIANGULAR_MESH:
+                            geometry = new dracoModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case dracoModule.POINT_CLOUD:
+                            geometry = new dracoModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error("Invalid geometry type " + type);
                     }
-                    finally {
-                        dracoModule.destroy(faceIndices);
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
-                }
-                for (var kind in attributes) {
-                    var uniqueId = attributes[kind];
-                    var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    var dracoData = new dracoModule.DracoFloat32Array();
-                    try {
-                        if (attribute.num_components() !== BABYLON.VertexBuffer.DeduceStride(kind)) {
-                            throw new Error("Unsupported number of components for " + kind);
+                    var numPoints = geometry.num_points();
+                    if (type === dracoModule.TRIANGULAR_MESH) {
+                        var numFaces = geometry.num_faces();
+                        var faceIndices = new dracoModule.DracoInt32Array();
+                        try {
+                            var indices = new Uint32Array(numFaces * 3);
+                            for (var i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                var offset = i * 3;
+                                indices[offset + 0] = faceIndices.GetValue(0);
+                                indices[offset + 1] = faceIndices.GetValue(1);
+                                indices[offset + 2] = faceIndices.GetValue(2);
+                            }
+                            _self.postMessage({ id: "indices", value: indices }, [indices.buffer]);
                         }
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        var babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (var i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                        finally {
+                            dracoModule.destroy(faceIndices);
                         }
-                        vertexData.set(babylonData, kind);
                     }
-                    finally {
-                        dracoModule.destroy(dracoData);
+                    for (var kind in attributes) {
+                        var uniqueId = attributes[kind];
+                        var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        var dracoData = new dracoModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            var babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (var i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            dracoModule.destroy(dracoData);
+                        }
                     }
                 }
-            }
-            finally {
-                if (geometry) {
-                    dracoModule.destroy(geometry);
+                finally {
+                    if (geometry) {
+                        dracoModule.destroy(geometry);
+                    }
+                    dracoModule.destroy(decoder);
+                    dracoModule.destroy(buffer);
+                }
+                _self.postMessage("done");
+            };
+            _self.onmessage = function (event) {
+                switch (event.data.id) {
+                    case "initDecoder": {
+                        importScripts(event.data.url);
+                        break;
+                    }
+                    case "decodeMesh": {
+                        decodeMesh(event.data.data, event.data.attributes);
+                        break;
+                    }
+                }
+            };
+        };
+        DracoCompression._GetDefaultDecoderUrl = function () {
+            for (var i = 0; i < document.scripts.length; i++) {
+                if (document.scripts[i].type === "text/x-draco-decoder") {
+                    return document.scripts[i].src;
                 }
-                dracoModule.destroy(decoder);
-                dracoModule.destroy(buffer);
             }
-            return vertexData;
+            return null;
         };
+        /**
+         * Gets the url to the draco decoder if available.
+         */
+        DracoCompression.DecoderUrl = DracoCompression._GetDefaultDecoderUrl();
+        DracoCompression._WorkerBlobUrl = URL.createObjectURL(new Blob(["(" + DracoCompression._Worker.toString() + ")()"], { type: "application/javascript" }));
         return DracoCompression;
     }());
     BABYLON.DracoCompression = DracoCompression;
@@ -66367,11 +66514,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
     var DepthRenderer = /** @class */ (function () {
-        function DepthRenderer(scene, type) {
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         */
+        function DepthRenderer(scene, type, camera) {
             if (type === void 0) { type = BABYLON.Engine.TEXTURETYPE_FLOAT; }
+            if (camera === void 0) { camera = null; }
             var _this = this;
             this._scene = scene;
+            this._camera = camera;
             var engine = scene.getEngine();
             // Render target
             this._depthMap = new BABYLON.RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
@@ -66380,6 +66539,10 @@ var BABYLON;
             this._depthMap.refreshRate = 1;
             this._depthMap.renderParticles = false;
             this._depthMap.renderList = null;
+            // Camera to get depth map from to support multiple concurrent cameras
+            this._depthMap.activeCamera = this._camera;
+            this._depthMap.ignoreCameraViewport = true;
+            this._depthMap.useCameraPostProcesses = false;
             // set default depth value to 1.0 (far away)
             this._depthMap.onClearObservable.add(function (engine) {
                 engine.clear(new BABYLON.Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
@@ -66401,11 +66564,12 @@ var BABYLON;
                     return;
                 }
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
-                if (_this.isReady(subMesh, hardwareInstancedRendering) && scene.activeCamera) {
+                var camera = _this._camera || scene.activeCamera;
+                if (_this.isReady(subMesh, hardwareInstancedRendering) && camera) {
                     engine.enableEffect(_this._effect);
                     mesh._bind(subMesh, _this._effect, BABYLON.Material.TriangleFillMode);
                     _this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-                    _this._effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.minZ + scene.activeCamera.maxZ);
+                    _this._effect.setFloat2("depthValues", camera.minZ, camera.minZ + camera.maxZ);
                     // Alpha test
                     if (material && material.needAlphaTesting()) {
                         var alphaTexture = material.getAlphaTestTexture();
@@ -66439,6 +66603,12 @@ var BABYLON;
                 }
             };
         }
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
         DepthRenderer.prototype.isReady = function (subMesh, useInstances) {
             var material = subMesh.getMaterial();
             if (material.disableDepthWrite) {
@@ -66489,10 +66659,16 @@ var BABYLON;
             }
             return this._effect.isReady();
         };
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
         DepthRenderer.prototype.getDepthMap = function () {
             return this._depthMap;
         };
-        // Methods
+        /**
+         * Disposes of the depth renderer.
+         */
         DepthRenderer.prototype.dispose = function () {
             this._depthMap.dispose();
         };

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


File diff suppressed because it is too large
+ 2720 - 2639
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


+ 310 - 107
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -9526,6 +9526,68 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.promise.js.map
 
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Helper class to push actions to a pool of workers.
+     */
+    var WorkerPool = /** @class */ (function () {
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        function WorkerPool(workers) {
+            this._pendingActions = new Array();
+            this._workerInfos = workers.map(function (worker) { return ({
+                worker: worker,
+                active: false
+            }); });
+        }
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        WorkerPool.prototype.dispose = function () {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                workerInfo.worker.terminate();
+            }
+            delete this._workerInfos;
+            delete this._pendingActions;
+        };
+        /**
+         * Pushes an action to the worker pool. If all the workers are active, the action will be
+         * pended until a worker has completed its action.
+         * @param action The action to perform. Call onComplete when the action is complete.
+         */
+        WorkerPool.prototype.push = function (action) {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                if (!workerInfo.active) {
+                    this._execute(workerInfo, action);
+                    return;
+                }
+            }
+            this._pendingActions.push(action);
+        };
+        WorkerPool.prototype._execute = function (workerInfo, action) {
+            var _this = this;
+            workerInfo.active = true;
+            action(workerInfo.worker, function () {
+                workerInfo.active = false;
+                var nextAction = _this._pendingActions.shift();
+                if (nextAction) {
+                    _this._execute(workerInfo, nextAction);
+                }
+            });
+        };
+        return WorkerPool;
+    }());
+    BABYLON.WorkerPool = WorkerPool;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.workerPool.js.map
+
 var BABYLON;
 (function (BABYLON) {
     var _AlphaState = /** @class */ (function () {
@@ -21337,6 +21399,7 @@ var BABYLON;
             this._useAlternateCameraConfiguration = false;
             this._alternateRendering = false;
             this.requireLightSorting = false;
+            this._depthRenderer = {};
             this._activeMeshesFrozen = false;
             this._tempPickingRay = BABYLON.Ray ? BABYLON.Ray.Zero() : null;
             this._engine = engine || BABYLON.Engine.LastCreatedEngine;
@@ -24115,8 +24178,8 @@ var BABYLON;
                 }
             }
             // Depth renderer
-            if (this._depthRenderer) {
-                this._renderTargets.push(this._depthRenderer.getDepthMap());
+            for (var key in this._depthRenderer) {
+                this._renderTargets.push(this._depthRenderer[key].getDepthMap());
             }
             // Geometry renderer
             if (this._geometryBufferRenderer) {
@@ -24285,19 +24348,32 @@ var BABYLON;
                 this.soundTracks[i].switchPanningModelToEqualPower();
             }
         };
-        Scene.prototype.enableDepthRenderer = function () {
-            if (this._depthRenderer) {
-                return this._depthRenderer;
+        /**
+         * Creates a depth renderer a given camera which contains a depth map which can be used for post processing.
+         * @param camera The camera to create the depth renderer on (default: scene's active camera)
+         * @returns the created depth renderer
+         */
+        Scene.prototype.enableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera) {
+                throw "No camera available to enable depth renderer";
             }
-            this._depthRenderer = new BABYLON.DepthRenderer(this);
-            return this._depthRenderer;
+            if (!this._depthRenderer[camera.id]) {
+                this._depthRenderer[camera.id] = new BABYLON.DepthRenderer(this, BABYLON.Engine.TEXTURETYPE_FLOAT, camera);
+            }
+            return this._depthRenderer[camera.id];
         };
-        Scene.prototype.disableDepthRenderer = function () {
-            if (!this._depthRenderer) {
+        /**
+         * Disables a depth renderer for a given camera
+         * @param camera The camera to disable the depth renderer on (default: scene's active camera)
+         */
+        Scene.prototype.disableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera || !this._depthRenderer[camera.id]) {
                 return;
             }
-            this._depthRenderer.dispose();
-            this._depthRenderer = null;
+            this._depthRenderer[camera.id].dispose();
+            delete this._depthRenderer[camera.id];
         };
         Scene.prototype.enableGeometryBufferRenderer = function (ratio) {
             if (ratio === void 0) { ratio = 1; }
@@ -24335,8 +24411,8 @@ var BABYLON;
             this.importedMeshesFiles = new Array();
             this.stopAllAnimations();
             this.resetCachedMaterial();
-            if (this._depthRenderer) {
-                this._depthRenderer.dispose();
+            for (var key in this._depthRenderer) {
+                this._depthRenderer[key].dispose();
             }
             if (this._gamepadManager) {
                 this._gamepadManager.dispose();
@@ -24499,21 +24575,27 @@ var BABYLON;
             }
         };
         // Octrees
-        Scene.prototype.getWorldExtends = function () {
+        /**
+         * Get the world extend vectors with an optional filter
+         *
+         * @param filterPredicate the predicate - which meshes should be included when calculating the world size
+         * @returns {{ min: Vector3; max: Vector3 }} min and max vectors
+         */
+        Scene.prototype.getWorldExtends = function (filterPredicate) {
             var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
-            for (var index = 0; index < this.meshes.length; index++) {
-                var mesh = this.meshes[index];
+            filterPredicate = filterPredicate || (function () { return true; });
+            this.meshes.filter(filterPredicate).forEach(function (mesh) {
                 mesh.computeWorldMatrix(true);
                 if (!mesh.subMeshes || mesh.subMeshes.length === 0 || mesh.infiniteDistance) {
-                    continue;
+                    return;
                 }
                 var boundingInfo = mesh.getBoundingInfo();
                 var minBox = boundingInfo.boundingBox.minimumWorld;
                 var maxBox = boundingInfo.boundingBox.maximumWorld;
                 BABYLON.Tools.CheckExtends(minBox, min, max);
                 BABYLON.Tools.CheckExtends(maxBox, min, max);
-            }
+            });
             return {
                 min: min,
                 max: max
@@ -55710,96 +55792,167 @@ var BABYLON;
      * Draco compression (https://google.github.io/draco/)
      */
     var DracoCompression = /** @class */ (function () {
-        function DracoCompression() {
+        /**
+         * Constructor
+         * @param numWorkers The number of workers for async operations
+         */
+        function DracoCompression(numWorkers) {
+            if (numWorkers === void 0) { numWorkers = (navigator.hardwareConcurrency || 4); }
+            var workers = new Array(numWorkers);
+            for (var i = 0; i < workers.length; i++) {
+                var worker = new Worker(DracoCompression._WorkerBlobUrl);
+                worker.postMessage({ id: "initDecoder", url: DracoCompression.DecoderUrl });
+                workers[i] = worker;
+            }
+            this._workerPool = new BABYLON.WorkerPool(workers);
         }
-        Object.defineProperty(DracoCompression, "IsSupported", {
-            /**
-             * Returns whether Draco compression is supported.
-             */
-            get: function () {
-                return BABYLON.Tools.IsWindowObjectExist() && !!window.DracoDecoderModule;
-            },
-            enumerable: true,
-            configurable: true
-        });
         /**
-         * Decodes Draco compressed data to vertex data.
+         * Stop all async operations and release resources.
+         */
+        DracoCompression.prototype.dispose = function () {
+            this._workerPool.dispose();
+            delete this._workerPool;
+        };
+        /**
+         * Decode Draco compressed mesh data to vertex data.
          * @param data The array buffer view for the Draco compression data
          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns The decoded vertex data
-         */
-        DracoCompression.Decode = function (data, attributes) {
-            var dracoModule = new DracoDecoderModule();
-            var buffer = new dracoModule.DecoderBuffer();
-            buffer.Init(data, data.byteLength);
-            var decoder = new dracoModule.Decoder();
-            var geometry;
-            var status;
-            var vertexData = new BABYLON.VertexData();
-            try {
-                var type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case dracoModule.TRIANGULAR_MESH:
-                        geometry = new dracoModule.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case dracoModule.POINT_CLOUD:
-                        geometry = new dracoModule.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error("Invalid geometry type " + type);
-                }
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
-                var numPoints = geometry.num_points();
-                if (type === dracoModule.TRIANGULAR_MESH) {
-                    var numFaces = geometry.num_faces();
-                    var faceIndices = new dracoModule.DracoInt32Array();
-                    try {
-                        vertexData.indices = new Uint32Array(numFaces * 3);
-                        for (var i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            var offset = i * 3;
-                            vertexData.indices[offset + 0] = faceIndices.GetValue(0);
-                            vertexData.indices[offset + 1] = faceIndices.GetValue(1);
-                            vertexData.indices[offset + 2] = faceIndices.GetValue(2);
+         * @returns A promise that resolves with the decoded vertex data
+         */
+        DracoCompression.prototype.decodeMeshAsync = function (data, attributes) {
+            var _this = this;
+            return new Promise(function (resolve, reject) {
+                _this._workerPool.push(function (worker, onComplete) {
+                    var vertexData = new BABYLON.VertexData();
+                    var onError = function (error) {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
+                    var onMessage = function (message) {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
+                        }
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
+                        }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
                         }
+                    };
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+                    var dataCopy = new Uint8Array(data.byteLength);
+                    dataCopy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
+                    worker.postMessage({ id: "decodeMesh", data: dataCopy, attributes: attributes }, [dataCopy.buffer]);
+                });
+            });
+        };
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        DracoCompression._Worker = function () {
+            // self is actually a DedicatedWorkerGlobalScope
+            var _self = self;
+            var decodeMesh = function (data, attributes) {
+                var dracoModule = new DracoDecoderModule();
+                var buffer = new dracoModule.DecoderBuffer();
+                buffer.Init(data, data.byteLength);
+                var decoder = new dracoModule.Decoder();
+                var geometry;
+                var status;
+                try {
+                    var type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case dracoModule.TRIANGULAR_MESH:
+                            geometry = new dracoModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case dracoModule.POINT_CLOUD:
+                            geometry = new dracoModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error("Invalid geometry type " + type);
                     }
-                    finally {
-                        dracoModule.destroy(faceIndices);
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
-                }
-                for (var kind in attributes) {
-                    var uniqueId = attributes[kind];
-                    var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    var dracoData = new dracoModule.DracoFloat32Array();
-                    try {
-                        if (attribute.num_components() !== BABYLON.VertexBuffer.DeduceStride(kind)) {
-                            throw new Error("Unsupported number of components for " + kind);
+                    var numPoints = geometry.num_points();
+                    if (type === dracoModule.TRIANGULAR_MESH) {
+                        var numFaces = geometry.num_faces();
+                        var faceIndices = new dracoModule.DracoInt32Array();
+                        try {
+                            var indices = new Uint32Array(numFaces * 3);
+                            for (var i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                var offset = i * 3;
+                                indices[offset + 0] = faceIndices.GetValue(0);
+                                indices[offset + 1] = faceIndices.GetValue(1);
+                                indices[offset + 2] = faceIndices.GetValue(2);
+                            }
+                            _self.postMessage({ id: "indices", value: indices }, [indices.buffer]);
                         }
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        var babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (var i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                        finally {
+                            dracoModule.destroy(faceIndices);
                         }
-                        vertexData.set(babylonData, kind);
                     }
-                    finally {
-                        dracoModule.destroy(dracoData);
+                    for (var kind in attributes) {
+                        var uniqueId = attributes[kind];
+                        var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        var dracoData = new dracoModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            var babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (var i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            dracoModule.destroy(dracoData);
+                        }
                     }
                 }
-            }
-            finally {
-                if (geometry) {
-                    dracoModule.destroy(geometry);
+                finally {
+                    if (geometry) {
+                        dracoModule.destroy(geometry);
+                    }
+                    dracoModule.destroy(decoder);
+                    dracoModule.destroy(buffer);
+                }
+                _self.postMessage("done");
+            };
+            _self.onmessage = function (event) {
+                switch (event.data.id) {
+                    case "initDecoder": {
+                        importScripts(event.data.url);
+                        break;
+                    }
+                    case "decodeMesh": {
+                        decodeMesh(event.data.data, event.data.attributes);
+                        break;
+                    }
+                }
+            };
+        };
+        DracoCompression._GetDefaultDecoderUrl = function () {
+            for (var i = 0; i < document.scripts.length; i++) {
+                if (document.scripts[i].type === "text/x-draco-decoder") {
+                    return document.scripts[i].src;
                 }
-                dracoModule.destroy(decoder);
-                dracoModule.destroy(buffer);
             }
-            return vertexData;
+            return null;
         };
+        /**
+         * Gets the url to the draco decoder if available.
+         */
+        DracoCompression.DecoderUrl = DracoCompression._GetDefaultDecoderUrl();
+        DracoCompression._WorkerBlobUrl = URL.createObjectURL(new Blob(["(" + DracoCompression._Worker.toString() + ")()"], { type: "application/javascript" }));
         return DracoCompression;
     }());
     BABYLON.DracoCompression = DracoCompression;
@@ -65678,11 +65831,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
     var DepthRenderer = /** @class */ (function () {
-        function DepthRenderer(scene, type) {
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         */
+        function DepthRenderer(scene, type, camera) {
             if (type === void 0) { type = BABYLON.Engine.TEXTURETYPE_FLOAT; }
+            if (camera === void 0) { camera = null; }
             var _this = this;
             this._scene = scene;
+            this._camera = camera;
             var engine = scene.getEngine();
             // Render target
             this._depthMap = new BABYLON.RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
@@ -65691,6 +65856,10 @@ var BABYLON;
             this._depthMap.refreshRate = 1;
             this._depthMap.renderParticles = false;
             this._depthMap.renderList = null;
+            // Camera to get depth map from to support multiple concurrent cameras
+            this._depthMap.activeCamera = this._camera;
+            this._depthMap.ignoreCameraViewport = true;
+            this._depthMap.useCameraPostProcesses = false;
             // set default depth value to 1.0 (far away)
             this._depthMap.onClearObservable.add(function (engine) {
                 engine.clear(new BABYLON.Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
@@ -65712,11 +65881,12 @@ var BABYLON;
                     return;
                 }
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
-                if (_this.isReady(subMesh, hardwareInstancedRendering) && scene.activeCamera) {
+                var camera = _this._camera || scene.activeCamera;
+                if (_this.isReady(subMesh, hardwareInstancedRendering) && camera) {
                     engine.enableEffect(_this._effect);
                     mesh._bind(subMesh, _this._effect, BABYLON.Material.TriangleFillMode);
                     _this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-                    _this._effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.minZ + scene.activeCamera.maxZ);
+                    _this._effect.setFloat2("depthValues", camera.minZ, camera.minZ + camera.maxZ);
                     // Alpha test
                     if (material && material.needAlphaTesting()) {
                         var alphaTexture = material.getAlphaTestTexture();
@@ -65750,6 +65920,12 @@ var BABYLON;
                 }
             };
         }
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
         DepthRenderer.prototype.isReady = function (subMesh, useInstances) {
             var material = subMesh.getMaterial();
             if (material.disableDepthWrite) {
@@ -65800,10 +65976,16 @@ var BABYLON;
             }
             return this._effect.isReady();
         };
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
         DepthRenderer.prototype.getDepthMap = function () {
             return this._depthMap;
         };
-        // Methods
+        /**
+         * Disposes of the depth renderer.
+         */
         DepthRenderer.prototype.dispose = function () {
             this._depthMap.dispose();
         };
@@ -88997,13 +89179,16 @@ var BABYLON;
          * Get the scene sizes according to the setup.
          */
         EnvironmentHelper.prototype._getSceneSize = function () {
+            var _this = this;
             var groundSize = this._options.groundSize;
             var skyboxSize = this._options.skyboxSize;
             var rootPosition = this._options.rootPosition;
             if (!this._scene.meshes || this._scene.meshes.length === 1) {
                 return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition };
             }
-            var sceneExtends = this._scene.getWorldExtends();
+            var sceneExtends = this._scene.getWorldExtends(function (mesh) {
+                return (mesh !== _this._ground && mesh !== _this._rootMesh && mesh !== _this._skybox);
+            });
             var sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
             if (this._options.sizeAuto) {
                 if (this._scene.activeCamera instanceof BABYLON.ArcRotateCamera &&
@@ -93370,6 +93555,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
@@ -93379,8 +93567,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_3 = _a[_i];
-                    var extension = this._extensions[name_3];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {
@@ -93411,6 +93599,9 @@ var BABYLON;
                 this.enabled = true;
                 this._loader = loader;
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -93620,15 +93811,26 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -93665,7 +93867,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
@@ -93676,9 +93881,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));

File diff suppressed because it is too large
+ 312 - 109
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff suppressed because it is too large
+ 271 - 95
dist/preview release/es6.js


+ 5 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -360,11 +360,12 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
@@ -416,6 +417,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
 }

+ 27 - 9
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1812,6 +1812,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
@@ -1821,8 +1824,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_3 = _a[_i];
-                    var extension = this._extensions[name_3];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {
@@ -1853,6 +1856,9 @@ var BABYLON;
                 this.enabled = true;
                 this._loader = loader;
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -2080,15 +2086,26 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -2125,7 +2142,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
@@ -2136,9 +2156,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));

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


+ 5 - 1
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -915,11 +915,12 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
@@ -971,6 +972,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
 }

+ 27 - 9
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3988,6 +3988,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
@@ -3997,8 +4000,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_3 = _a[_i];
-                    var extension = this._extensions[name_3];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {
@@ -4029,6 +4032,9 @@ var BABYLON;
                 this.enabled = true;
                 this._loader = loader;
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -4256,15 +4262,26 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -4301,7 +4318,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
@@ -4312,9 +4332,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));

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


+ 27 - 9
dist/preview release/loaders/babylonjs.loaders.js

@@ -4956,6 +4956,9 @@ var BABYLON;
                 delete this._gltf;
                 delete this._babylonScene;
                 this._completePromises.length = 0;
+                for (var name_3 in this._extensions) {
+                    this._extensions[name_3].dispose();
+                }
                 this._extensions = {};
                 delete this._rootBabylonMesh;
                 delete this._progressCallback;
@@ -4965,8 +4968,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_3 = _a[_i];
-                    var extension = this._extensions[name_3];
+                    var name_4 = _a[_i];
+                    var extension = this._extensions[name_4];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {
@@ -4997,6 +5000,9 @@ var BABYLON;
                 this.enabled = true;
                 this._loader = loader;
             }
+            GLTFLoaderExtension.prototype.dispose = function () {
+                delete this._loader;
+            };
             // #region Overridable Methods
             /** Override this method to modify the default behavior for loading scenes. */
             GLTFLoaderExtension.prototype._loadSceneAsync = function (context, node) { return null; };
@@ -5206,15 +5212,26 @@ var BABYLON;
     (function (GLTF2) {
         var Extensions;
         (function (Extensions) {
-            // https://github.com/KhronosGroup/glTF/pull/874
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression
             var NAME = "KHR_draco_mesh_compression";
             var KHR_draco_mesh_compression = /** @class */ (function (_super) {
                 __extends(KHR_draco_mesh_compression, _super);
-                function KHR_draco_mesh_compression() {
-                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                function KHR_draco_mesh_compression(loader) {
+                    var _this = _super.call(this, loader) || this;
                     _this.name = NAME;
+                    _this._dracoCompression = null;
+                    // Disable extension if decoder is not available.
+                    if (!BABYLON.DracoCompression.DecoderUrl) {
+                        _this.enabled = false;
+                    }
                     return _this;
                 }
+                KHR_draco_mesh_compression.prototype.dispose = function () {
+                    if (this._dracoCompression) {
+                        this._dracoCompression.dispose();
+                    }
+                    _super.prototype.dispose.call(this);
+                };
                 KHR_draco_mesh_compression.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) {
                     var _this = this;
                     return this._loadExtensionAsync(context, primitive, function (extensionContext, extension) {
@@ -5251,7 +5268,10 @@ var BABYLON;
                         var bufferView = GLTF2.GLTFLoader._GetProperty(extensionContext, _this._loader._gltf.bufferViews, extension.bufferView);
                         return _this._loader._loadBufferViewAsync("#/bufferViews/" + bufferView._index, bufferView).then(function (data) {
                             try {
-                                return BABYLON.DracoCompression.Decode(data, attributes);
+                                if (!_this._dracoCompression) {
+                                    _this._dracoCompression = new BABYLON.DracoCompression();
+                                }
+                                return _this._dracoCompression.decodeMeshAsync(data, attributes);
                             }
                             catch (e) {
                                 throw new Error(context + ": " + e.message);
@@ -5262,9 +5282,7 @@ var BABYLON;
                 return KHR_draco_mesh_compression;
             }(GLTF2.GLTFLoaderExtension));
             Extensions.KHR_draco_mesh_compression = KHR_draco_mesh_compression;
-            if (BABYLON.DracoCompression.IsSupported) {
-                GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
-            }
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_draco_mesh_compression(loader); });
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));

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


+ 5 - 1
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1016,11 +1016,12 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension {
+    abstract class GLTFLoaderExtension implements IGLTFLoaderExtension, IDisposable {
         enabled: boolean;
         readonly abstract name: string;
         protected _loader: GLTFLoader;
         constructor(loader: GLTFLoader);
+        dispose(): void;
         /** Override this method to modify the default behavior for loading scenes. */
         protected _loadSceneAsync(context: string, node: ILoaderScene): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading nodes. */
@@ -1072,6 +1073,9 @@ declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class KHR_draco_mesh_compression extends GLTFLoaderExtension {
         readonly name: string;
+        private _dracoCompression;
+        constructor(loader: GLTFLoader);
+        dispose(): void;
         protected _loadVertexDataAsync(context: string, primitive: ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<VertexData>>;
     }
 }

+ 2 - 17
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 7253,
+  "errors": 7241,
   "babylon.typedoc.json": {
-    "errors": 7253,
+    "errors": 7241,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -27635,11 +27635,6 @@
             "MissingText": true
           }
         },
-        "disableDepthRenderer": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "disableGeometryBufferRenderer": {
           "Comments": {
             "MissingText": true
@@ -27660,11 +27655,6 @@
             "MissingText": true
           }
         },
-        "enableDepthRenderer": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "enableGeometryBufferRenderer": {
           "Comments": {
             "MissingText": true
@@ -28216,11 +28206,6 @@
             "MissingText": true
           }
         },
-        "getWorldExtends": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "incrementRenderId": {
           "Comments": {
             "MissingText": true

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


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

@@ -9596,6 +9596,68 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.promise.js.map
 
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Helper class to push actions to a pool of workers.
+     */
+    var WorkerPool = /** @class */ (function () {
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        function WorkerPool(workers) {
+            this._pendingActions = new Array();
+            this._workerInfos = workers.map(function (worker) { return ({
+                worker: worker,
+                active: false
+            }); });
+        }
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        WorkerPool.prototype.dispose = function () {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                workerInfo.worker.terminate();
+            }
+            delete this._workerInfos;
+            delete this._pendingActions;
+        };
+        /**
+         * Pushes an action to the worker pool. If all the workers are active, the action will be
+         * pended until a worker has completed its action.
+         * @param action The action to perform. Call onComplete when the action is complete.
+         */
+        WorkerPool.prototype.push = function (action) {
+            for (var _i = 0, _a = this._workerInfos; _i < _a.length; _i++) {
+                var workerInfo = _a[_i];
+                if (!workerInfo.active) {
+                    this._execute(workerInfo, action);
+                    return;
+                }
+            }
+            this._pendingActions.push(action);
+        };
+        WorkerPool.prototype._execute = function (workerInfo, action) {
+            var _this = this;
+            workerInfo.active = true;
+            action(workerInfo.worker, function () {
+                workerInfo.active = false;
+                var nextAction = _this._pendingActions.shift();
+                if (nextAction) {
+                    _this._execute(workerInfo, nextAction);
+                }
+            });
+        };
+        return WorkerPool;
+    }());
+    BABYLON.WorkerPool = WorkerPool;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.workerPool.js.map
+
 var BABYLON;
 (function (BABYLON) {
     var _AlphaState = /** @class */ (function () {
@@ -21407,6 +21469,7 @@ var BABYLON;
             this._useAlternateCameraConfiguration = false;
             this._alternateRendering = false;
             this.requireLightSorting = false;
+            this._depthRenderer = {};
             this._activeMeshesFrozen = false;
             this._tempPickingRay = BABYLON.Ray ? BABYLON.Ray.Zero() : null;
             this._engine = engine || BABYLON.Engine.LastCreatedEngine;
@@ -24185,8 +24248,8 @@ var BABYLON;
                 }
             }
             // Depth renderer
-            if (this._depthRenderer) {
-                this._renderTargets.push(this._depthRenderer.getDepthMap());
+            for (var key in this._depthRenderer) {
+                this._renderTargets.push(this._depthRenderer[key].getDepthMap());
             }
             // Geometry renderer
             if (this._geometryBufferRenderer) {
@@ -24355,19 +24418,32 @@ var BABYLON;
                 this.soundTracks[i].switchPanningModelToEqualPower();
             }
         };
-        Scene.prototype.enableDepthRenderer = function () {
-            if (this._depthRenderer) {
-                return this._depthRenderer;
+        /**
+         * Creates a depth renderer a given camera which contains a depth map which can be used for post processing.
+         * @param camera The camera to create the depth renderer on (default: scene's active camera)
+         * @returns the created depth renderer
+         */
+        Scene.prototype.enableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera) {
+                throw "No camera available to enable depth renderer";
             }
-            this._depthRenderer = new BABYLON.DepthRenderer(this);
-            return this._depthRenderer;
+            if (!this._depthRenderer[camera.id]) {
+                this._depthRenderer[camera.id] = new BABYLON.DepthRenderer(this, BABYLON.Engine.TEXTURETYPE_FLOAT, camera);
+            }
+            return this._depthRenderer[camera.id];
         };
-        Scene.prototype.disableDepthRenderer = function () {
-            if (!this._depthRenderer) {
+        /**
+         * Disables a depth renderer for a given camera
+         * @param camera The camera to disable the depth renderer on (default: scene's active camera)
+         */
+        Scene.prototype.disableDepthRenderer = function (camera) {
+            camera = camera || this.activeCamera;
+            if (!camera || !this._depthRenderer[camera.id]) {
                 return;
             }
-            this._depthRenderer.dispose();
-            this._depthRenderer = null;
+            this._depthRenderer[camera.id].dispose();
+            delete this._depthRenderer[camera.id];
         };
         Scene.prototype.enableGeometryBufferRenderer = function (ratio) {
             if (ratio === void 0) { ratio = 1; }
@@ -24405,8 +24481,8 @@ var BABYLON;
             this.importedMeshesFiles = new Array();
             this.stopAllAnimations();
             this.resetCachedMaterial();
-            if (this._depthRenderer) {
-                this._depthRenderer.dispose();
+            for (var key in this._depthRenderer) {
+                this._depthRenderer[key].dispose();
             }
             if (this._gamepadManager) {
                 this._gamepadManager.dispose();
@@ -24569,21 +24645,27 @@ var BABYLON;
             }
         };
         // Octrees
-        Scene.prototype.getWorldExtends = function () {
+        /**
+         * Get the world extend vectors with an optional filter
+         *
+         * @param filterPredicate the predicate - which meshes should be included when calculating the world size
+         * @returns {{ min: Vector3; max: Vector3 }} min and max vectors
+         */
+        Scene.prototype.getWorldExtends = function (filterPredicate) {
             var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var max = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
-            for (var index = 0; index < this.meshes.length; index++) {
-                var mesh = this.meshes[index];
+            filterPredicate = filterPredicate || (function () { return true; });
+            this.meshes.filter(filterPredicate).forEach(function (mesh) {
                 mesh.computeWorldMatrix(true);
                 if (!mesh.subMeshes || mesh.subMeshes.length === 0 || mesh.infiniteDistance) {
-                    continue;
+                    return;
                 }
                 var boundingInfo = mesh.getBoundingInfo();
                 var minBox = boundingInfo.boundingBox.minimumWorld;
                 var maxBox = boundingInfo.boundingBox.maximumWorld;
                 BABYLON.Tools.CheckExtends(minBox, min, max);
                 BABYLON.Tools.CheckExtends(maxBox, min, max);
-            }
+            });
             return {
                 min: min,
                 max: max
@@ -56463,96 +56545,167 @@ var BABYLON;
      * Draco compression (https://google.github.io/draco/)
      */
     var DracoCompression = /** @class */ (function () {
-        function DracoCompression() {
+        /**
+         * Constructor
+         * @param numWorkers The number of workers for async operations
+         */
+        function DracoCompression(numWorkers) {
+            if (numWorkers === void 0) { numWorkers = (navigator.hardwareConcurrency || 4); }
+            var workers = new Array(numWorkers);
+            for (var i = 0; i < workers.length; i++) {
+                var worker = new Worker(DracoCompression._WorkerBlobUrl);
+                worker.postMessage({ id: "initDecoder", url: DracoCompression.DecoderUrl });
+                workers[i] = worker;
+            }
+            this._workerPool = new BABYLON.WorkerPool(workers);
         }
-        Object.defineProperty(DracoCompression, "IsSupported", {
-            /**
-             * Returns whether Draco compression is supported.
-             */
-            get: function () {
-                return BABYLON.Tools.IsWindowObjectExist() && !!window.DracoDecoderModule;
-            },
-            enumerable: true,
-            configurable: true
-        });
         /**
-         * Decodes Draco compressed data to vertex data.
+         * Stop all async operations and release resources.
+         */
+        DracoCompression.prototype.dispose = function () {
+            this._workerPool.dispose();
+            delete this._workerPool;
+        };
+        /**
+         * Decode Draco compressed mesh data to vertex data.
          * @param data The array buffer view for the Draco compression data
          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns The decoded vertex data
-         */
-        DracoCompression.Decode = function (data, attributes) {
-            var dracoModule = new DracoDecoderModule();
-            var buffer = new dracoModule.DecoderBuffer();
-            buffer.Init(data, data.byteLength);
-            var decoder = new dracoModule.Decoder();
-            var geometry;
-            var status;
-            var vertexData = new BABYLON.VertexData();
-            try {
-                var type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case dracoModule.TRIANGULAR_MESH:
-                        geometry = new dracoModule.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case dracoModule.POINT_CLOUD:
-                        geometry = new dracoModule.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error("Invalid geometry type " + type);
-                }
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
-                var numPoints = geometry.num_points();
-                if (type === dracoModule.TRIANGULAR_MESH) {
-                    var numFaces = geometry.num_faces();
-                    var faceIndices = new dracoModule.DracoInt32Array();
-                    try {
-                        vertexData.indices = new Uint32Array(numFaces * 3);
-                        for (var i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            var offset = i * 3;
-                            vertexData.indices[offset + 0] = faceIndices.GetValue(0);
-                            vertexData.indices[offset + 1] = faceIndices.GetValue(1);
-                            vertexData.indices[offset + 2] = faceIndices.GetValue(2);
+         * @returns A promise that resolves with the decoded vertex data
+         */
+        DracoCompression.prototype.decodeMeshAsync = function (data, attributes) {
+            var _this = this;
+            return new Promise(function (resolve, reject) {
+                _this._workerPool.push(function (worker, onComplete) {
+                    var vertexData = new BABYLON.VertexData();
+                    var onError = function (error) {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
+                    var onMessage = function (message) {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
+                        }
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
+                        }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
                         }
+                    };
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+                    var dataCopy = new Uint8Array(data.byteLength);
+                    dataCopy.set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
+                    worker.postMessage({ id: "decodeMesh", data: dataCopy, attributes: attributes }, [dataCopy.buffer]);
+                });
+            });
+        };
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        DracoCompression._Worker = function () {
+            // self is actually a DedicatedWorkerGlobalScope
+            var _self = self;
+            var decodeMesh = function (data, attributes) {
+                var dracoModule = new DracoDecoderModule();
+                var buffer = new dracoModule.DecoderBuffer();
+                buffer.Init(data, data.byteLength);
+                var decoder = new dracoModule.Decoder();
+                var geometry;
+                var status;
+                try {
+                    var type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case dracoModule.TRIANGULAR_MESH:
+                            geometry = new dracoModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case dracoModule.POINT_CLOUD:
+                            geometry = new dracoModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error("Invalid geometry type " + type);
                     }
-                    finally {
-                        dracoModule.destroy(faceIndices);
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
-                }
-                for (var kind in attributes) {
-                    var uniqueId = attributes[kind];
-                    var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    var dracoData = new dracoModule.DracoFloat32Array();
-                    try {
-                        if (attribute.num_components() !== BABYLON.VertexBuffer.DeduceStride(kind)) {
-                            throw new Error("Unsupported number of components for " + kind);
+                    var numPoints = geometry.num_points();
+                    if (type === dracoModule.TRIANGULAR_MESH) {
+                        var numFaces = geometry.num_faces();
+                        var faceIndices = new dracoModule.DracoInt32Array();
+                        try {
+                            var indices = new Uint32Array(numFaces * 3);
+                            for (var i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                var offset = i * 3;
+                                indices[offset + 0] = faceIndices.GetValue(0);
+                                indices[offset + 1] = faceIndices.GetValue(1);
+                                indices[offset + 2] = faceIndices.GetValue(2);
+                            }
+                            _self.postMessage({ id: "indices", value: indices }, [indices.buffer]);
                         }
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        var babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (var i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                        finally {
+                            dracoModule.destroy(faceIndices);
                         }
-                        vertexData.set(babylonData, kind);
                     }
-                    finally {
-                        dracoModule.destroy(dracoData);
+                    for (var kind in attributes) {
+                        var uniqueId = attributes[kind];
+                        var attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        var dracoData = new dracoModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            var babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (var i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            dracoModule.destroy(dracoData);
+                        }
                     }
                 }
-            }
-            finally {
-                if (geometry) {
-                    dracoModule.destroy(geometry);
+                finally {
+                    if (geometry) {
+                        dracoModule.destroy(geometry);
+                    }
+                    dracoModule.destroy(decoder);
+                    dracoModule.destroy(buffer);
+                }
+                _self.postMessage("done");
+            };
+            _self.onmessage = function (event) {
+                switch (event.data.id) {
+                    case "initDecoder": {
+                        importScripts(event.data.url);
+                        break;
+                    }
+                    case "decodeMesh": {
+                        decodeMesh(event.data.data, event.data.attributes);
+                        break;
+                    }
+                }
+            };
+        };
+        DracoCompression._GetDefaultDecoderUrl = function () {
+            for (var i = 0; i < document.scripts.length; i++) {
+                if (document.scripts[i].type === "text/x-draco-decoder") {
+                    return document.scripts[i].src;
                 }
-                dracoModule.destroy(decoder);
-                dracoModule.destroy(buffer);
             }
-            return vertexData;
+            return null;
         };
+        /**
+         * Gets the url to the draco decoder if available.
+         */
+        DracoCompression.DecoderUrl = DracoCompression._GetDefaultDecoderUrl();
+        DracoCompression._WorkerBlobUrl = URL.createObjectURL(new Blob(["(" + DracoCompression._Worker.toString() + ")()"], { type: "application/javascript" }));
         return DracoCompression;
     }());
     BABYLON.DracoCompression = DracoCompression;
@@ -66431,11 +66584,23 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
     var DepthRenderer = /** @class */ (function () {
-        function DepthRenderer(scene, type) {
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         */
+        function DepthRenderer(scene, type, camera) {
             if (type === void 0) { type = BABYLON.Engine.TEXTURETYPE_FLOAT; }
+            if (camera === void 0) { camera = null; }
             var _this = this;
             this._scene = scene;
+            this._camera = camera;
             var engine = scene.getEngine();
             // Render target
             this._depthMap = new BABYLON.RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
@@ -66444,6 +66609,10 @@ var BABYLON;
             this._depthMap.refreshRate = 1;
             this._depthMap.renderParticles = false;
             this._depthMap.renderList = null;
+            // Camera to get depth map from to support multiple concurrent cameras
+            this._depthMap.activeCamera = this._camera;
+            this._depthMap.ignoreCameraViewport = true;
+            this._depthMap.useCameraPostProcesses = false;
             // set default depth value to 1.0 (far away)
             this._depthMap.onClearObservable.add(function (engine) {
                 engine.clear(new BABYLON.Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
@@ -66465,11 +66634,12 @@ var BABYLON;
                     return;
                 }
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
-                if (_this.isReady(subMesh, hardwareInstancedRendering) && scene.activeCamera) {
+                var camera = _this._camera || scene.activeCamera;
+                if (_this.isReady(subMesh, hardwareInstancedRendering) && camera) {
                     engine.enableEffect(_this._effect);
                     mesh._bind(subMesh, _this._effect, BABYLON.Material.TriangleFillMode);
                     _this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-                    _this._effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.minZ + scene.activeCamera.maxZ);
+                    _this._effect.setFloat2("depthValues", camera.minZ, camera.minZ + camera.maxZ);
                     // Alpha test
                     if (material && material.needAlphaTesting()) {
                         var alphaTexture = material.getAlphaTestTexture();
@@ -66503,6 +66673,12 @@ var BABYLON;
                 }
             };
         }
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
         DepthRenderer.prototype.isReady = function (subMesh, useInstances) {
             var material = subMesh.getMaterial();
             if (material.disableDepthWrite) {
@@ -66553,10 +66729,16 @@ var BABYLON;
             }
             return this._effect.isReady();
         };
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
         DepthRenderer.prototype.getDepthMap = function () {
             return this._depthMap;
         };
-        // Methods
+        /**
+         * Disposes of the depth renderer.
+         */
         DepthRenderer.prototype.dispose = function () {
             this._depthMap.dispose();
         };
@@ -90152,13 +90334,16 @@ var BABYLON;
          * Get the scene sizes according to the setup.
          */
         EnvironmentHelper.prototype._getSceneSize = function () {
+            var _this = this;
             var groundSize = this._options.groundSize;
             var skyboxSize = this._options.skyboxSize;
             var rootPosition = this._options.rootPosition;
             if (!this._scene.meshes || this._scene.meshes.length === 1) {
                 return { groundSize: groundSize, skyboxSize: skyboxSize, rootPosition: rootPosition };
             }
-            var sceneExtends = this._scene.getWorldExtends();
+            var sceneExtends = this._scene.getWorldExtends(function (mesh) {
+                return (mesh !== _this._ground && mesh !== _this._rootMesh && mesh !== _this._skybox);
+            });
             var sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
             if (this._options.sizeAuto) {
                 if (this._scene.activeCamera instanceof BABYLON.ArcRotateCamera &&
@@ -90789,8 +90974,9 @@ var DefaultViewer = (function (_super) {
         this.containerElement.style.position = 'relative';
         this.containerElement.style.display = 'flex';
     };
-    DefaultViewer.prototype.configureModel = function (modelConfiguration) {
-        _super.prototype.configureModel.call(this, modelConfiguration);
+    DefaultViewer.prototype.configureModel = function (modelConfiguration, focusMeshes) {
+        if (focusMeshes === void 0) { focusMeshes = this.scene.meshes; }
+        _super.prototype.configureModel.call(this, modelConfiguration, focusMeshes);
         var navbar = this.templateManager.getTemplate('navBar');
         if (!navbar)
             return;
@@ -91257,6 +91443,7 @@ var AbstractViewer = (function () {
         }
     };
     AbstractViewer.prototype.configureCamera = function (cameraConfig, focusMeshes) {
+        var _this = this;
         if (focusMeshes === void 0) { focusMeshes = this.scene.meshes; }
         if (!this.scene.activeCamera) {
             this.scene.createDefaultCamera(true, true, true);
@@ -91277,7 +91464,9 @@ var AbstractViewer = (function () {
             }
         }
         ;
-        var sceneExtends = this.scene.getWorldExtends();
+        var sceneExtends = this.scene.getWorldExtends(function (mesh) {
+            return !_this.environmentHelper || (mesh !== _this.environmentHelper.ground && mesh !== _this.environmentHelper.rootMesh && mesh !== _this.environmentHelper.skybox);
+        });
         var sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         var sceneDiagonalLenght = sceneDiagonal.length();
         if (isFinite(sceneDiagonalLenght))
@@ -91531,11 +91720,31 @@ var AbstractViewer = (function () {
         var _this = this;
         if (model === void 0) { model = this.configuration.model; }
         if (clearScene === void 0) { clearScene = true; }
-        if (!model.url) {
+        var modelUrl = (typeof model === 'string') ? model : model.url;
+        if (!modelUrl) {
             return Promise.resolve(this.scene);
         }
-        this.configuration.model = model;
-        var modelUrl = (typeof model === 'string') ? model : model.url;
+        if (this.isLoading) {
+            this.nextLoading = function () {
+                delete _this.nextLoading;
+                _this.loadModel(model, clearScene);
+            };
+            return Promise.resolve(this.scene);
+        }
+        this.isLoading = true;
+        if ((typeof model === 'string')) {
+            if (this.configuration.model && typeof this.configuration.model === 'object') {
+                this.configuration.model.url = model;
+            }
+        }
+        else {
+            if (this.configuration.model) {
+                deepmerge(this.configuration.model, model);
+            }
+            else {
+                this.configuration.model = model;
+            }
+        }
         var parts = modelUrl.split('/');
         var filename = parts.pop();
         var base = parts.join('/') + '/';
@@ -91545,13 +91754,18 @@ var AbstractViewer = (function () {
                 return _this.initScene();
             if (clearScene) {
                 scene.meshes.forEach(function (mesh) {
-                    mesh.dispose();
+                    if (babylonjs_1.Tags.MatchesQuery(mesh, "viewerMesh")) {
+                        mesh.dispose();
+                    }
                 });
             }
             return scene;
         }).then(function () {
             return new Promise(function (resolve, reject) {
                 _this.lastUsedLoader = babylonjs_1.SceneLoader.ImportMesh(undefined, base, filename, _this.scene, function (meshes) {
+                    meshes.forEach(function (mesh) {
+                        babylonjs_1.Tags.AddTagsTo(mesh, "viewerMesh");
+                    });
                     resolve(meshes);
                 }, function (progressEvent) {
                     _this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
@@ -91565,19 +91779,23 @@ var AbstractViewer = (function () {
         }).then(function (meshes) {
             return _this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
                 .then(function () {
-                _this.configureModel(model, meshes);
+                _this.configureModel(_this.configuration.model || model, meshes);
                 _this.configureLights(_this.configuration.lights);
                 if (_this.configuration.camera) {
                     _this.configureCamera(_this.configuration.camera, meshes);
                 }
                 return _this.initEnvironment(meshes);
             }).then(function () {
+                _this.isLoading = false;
+                if (_this.nextLoading) {
+                    return _this.nextLoading();
+                }
                 return _this.scene;
             });
         });
     };
     AbstractViewer.prototype.initEnvironment = function (focusMeshes) {
-        if (focusMeshes === void 0) { focusMeshes = []; }
+        if (focusMeshes === void 0) { focusMeshes = this.scene.meshes; }
         this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
         return Promise.resolve(this.scene);
     };
@@ -104613,7 +104831,10 @@ var Template = (function () {
     };
     Template.prototype.show = function (visibilityFunction) {
         var _this = this;
+        if (this.isHiding)
+            return Promise.resolve(this);
         return Promise.resolve().then(function () {
+            _this.isShowing = true;
             if (visibilityFunction) {
                 return visibilityFunction(_this);
             }
@@ -104623,13 +104844,17 @@ var Template = (function () {
             }
         }).then(function () {
             _this.isShown = true;
+            _this.isShowing = false;
             _this.onStateChange.notifyObservers(_this);
             return _this;
         });
     };
     Template.prototype.hide = function (visibilityFunction) {
         var _this = this;
+        if (this.isShowing)
+            return Promise.resolve(this);
         return Promise.resolve().then(function () {
+            _this.isHiding = true;
             if (visibilityFunction) {
                 return visibilityFunction(_this);
             }
@@ -104639,6 +104864,7 @@ var Template = (function () {
             }
         }).then(function () {
             _this.isShown = false;
+            _this.isHiding = false;
             _this.onStateChange.notifyObservers(_this);
             return _this;
         });