Преглед на файлове

Merge pull request #6122 from BabylonJS/master

Nightly
David Catuhe преди 6 години
родител
ревизия
a7221c190b
променени са 49 файла, в които са добавени 1699 реда и са изтрити 1563 реда
  1. 85 93
      Playground/babylon.d.txt
  2. 82 94
      dist/preview release/babylon.d.ts
  3. 2 2
      dist/preview release/babylon.js
  4. 546 495
      dist/preview release/babylon.max.js
  5. 1 1
      dist/preview release/babylon.max.js.map
  6. 165 192
      dist/preview release/babylon.module.d.ts
  7. 39 39
      dist/preview release/gui/babylon.gui.js
  8. 1 1
      dist/preview release/gui/babylon.gui.js.map
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  10. 0 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  11. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  12. 13 6
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  13. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  14. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  15. 13 6
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  17. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  18. 3 1
      dist/preview release/loaders/babylonjs.loaders.d.ts
  19. 13 6
      dist/preview release/loaders/babylonjs.loaders.js
  20. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  21. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  22. 7 2
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  23. 1 1
      dist/preview release/packagesSizeBaseLine.json
  24. 165 192
      dist/preview release/viewer/babylon.module.d.ts
  25. 5 19
      dist/preview release/viewer/babylon.viewer.d.ts
  26. 18 22
      dist/preview release/viewer/babylon.viewer.js
  27. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  28. 5 22
      dist/preview release/viewer/babylon.viewer.module.d.ts
  29. 7 2
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  30. 8 2
      dist/preview release/what's new.md
  31. 0 1
      inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx
  32. 11 7
      loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts
  33. 7 0
      loaders/src/glTF/2.0/glTFLoader.ts
  34. 91 0
      sandbox/debug.html
  35. 1 1
      sandbox/index.js
  36. 52 19
      src/Cameras/arcRotateCamera.ts
  37. 23 0
      src/Debug/physicsViewer.ts
  38. 22 130
      src/Engines/engine.ts
  39. 0 8
      src/Instrumentation/sceneInstrumentation.ts
  40. 0 1
      src/Materials/Textures/index.ts
  41. 3 17
      src/Materials/Textures/internalTexture.ts
  42. 0 30
      src/Materials/Textures/internalTextureTracker.ts
  43. 21 0
      src/Maths/math.ts
  44. 237 122
      src/Meshes/Compression/dracoCompression.ts
  45. 8 0
      src/Meshes/abstractMesh.ts
  46. 16 15
      src/Meshes/transformNode.ts
  47. 2 1
      src/Misc/dds.ts
  48. 11 0
      src/Misc/tools.ts
  49. 3 0
      src/Physics/Plugins/ammoJSPlugin.ts

+ 85 - 93
Playground/babylon.d.txt

@@ -3255,6 +3255,14 @@ declare module BABYLON {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6134,38 +6142,10 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
private static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
          * The source of the texture data is unknown
@@ -6291,17 +6271,8 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
invertVScale: boolean;
-        /** @hidden */
initialSlot: number;
-        /** @hidden */
designatedSlot: number;
+        /** @hidden */
associatedChannel: number;
         /** @hidden */
dataSource: number;
         /** @hidden */
buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob>;
         /** @hidden */
bufferView: Nullable<ArrayBufferView>;
@@ -23647,6 +23618,10 @@ declare module BABYLON {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -26800,12 +26775,6 @@ declare module BABYLON {
         /** @hidden */
badOS: boolean;
         /** @hidden */
badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -26853,7 +26822,6 @@ declare module BABYLON {
         private _colorWrite;
         private _loadingScreen;
         /** @hidden */
drawCalls: PerfCounter;
-        /** @hidden */
textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -26936,8 +26904,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -28181,10 +28147,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
         /** @hidden */
bindTexture(channel: number, texture: Nullable<InternalTexture>): void;
@@ -30582,6 +30544,12 @@ declare module BABYLON {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -34311,6 +34279,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -34525,8 +34506,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -40203,6 +40182,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -40227,6 +40207,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -45678,10 +45659,6 @@ declare module BABYLON {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -48533,6 +48510,31 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      */
     export interface IDracoCompressionConfiguration {
@@ -48593,7 +48595,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -48606,25 +48608,38 @@ declare module BABYLON {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module BABYLON {
@@ -55216,31 +55231,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      */
     export class ScreenshotTools {
@@ -60819,10 +60809,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */

+ 82 - 94
dist/preview release/babylon.d.ts

@@ -3257,6 +3257,14 @@ declare module BABYLON {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6158,38 +6166,10 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
@@ -6316,20 +6296,10 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         _invertVScale: boolean;
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         _dataSource: number;
         /** @hidden */
@@ -24026,6 +23996,10 @@ declare module BABYLON {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -27251,12 +27225,6 @@ declare module BABYLON {
         /** @hidden */
         _badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -27305,8 +27273,6 @@ declare module BABYLON {
         private _loadingScreen;
         /** @hidden */
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -27389,8 +27355,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -28652,10 +28616,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -31112,6 +31072,12 @@ declare module BABYLON {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -34906,6 +34872,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -35124,8 +35103,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -40846,6 +40823,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -40870,6 +40848,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -46353,10 +46332,6 @@ declare module BABYLON {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -49222,6 +49197,31 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      */
     export interface IDracoCompressionConfiguration {
@@ -49282,7 +49282,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -49295,25 +49295,38 @@ declare module BABYLON {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module BABYLON {
@@ -55959,31 +55972,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      */
     export class ScreenshotTools {

Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/babylon.js


Файловите разлики са ограничени, защото са твърде много
+ 546 - 495
dist/preview release/babylon.max.js


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 165 - 192
dist/preview release/babylon.module.d.ts

@@ -3258,6 +3258,14 @@ declare module "babylonjs/Maths/math" {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6175,47 +6183,17 @@ declare module "babylonjs/Instrumentation/timeToken" {
         _timeElapsedQueryEnded: boolean;
     }
 }
-declare module "babylonjs/Materials/Textures/internalTextureTracker" {
-    import { Nullable } from "babylonjs/types";
-    /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
 declare module "babylonjs/Materials/Textures/internalTexture" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Nullable, int } from "babylonjs/types";
     import { SphericalPolynomial } from "babylonjs/Maths/sphericalPolynomial";
-    import { IInternalTextureTracker } from "babylonjs/Materials/Textures/internalTextureTracker";
     import { Engine } from "babylonjs/Engines/engine";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
@@ -6342,20 +6320,10 @@ declare module "babylonjs/Materials/Textures/internalTexture" {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         _invertVScale: boolean;
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         _dataSource: number;
         /** @hidden */
@@ -24663,6 +24631,10 @@ declare module "babylonjs/Meshes/abstractMesh" {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -27972,12 +27944,6 @@ declare module "babylonjs/Engines/engine" {
         /** @hidden */
         _badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -28026,8 +27992,6 @@ declare module "babylonjs/Engines/engine" {
         private _loadingScreen;
         /** @hidden */
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -28110,8 +28074,6 @@ declare module "babylonjs/Engines/engine" {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -29373,10 +29335,6 @@ declare module "babylonjs/Engines/engine" {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -31877,6 +31835,12 @@ declare module "babylonjs/Misc/tools" {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -35838,6 +35802,19 @@ declare module "babylonjs/Cameras/arcRotateCamera" {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -36056,8 +36033,6 @@ declare module "babylonjs/Cameras/arcRotateCamera" {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -42283,6 +42258,7 @@ declare module "babylonjs/Debug/physicsViewer" {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -42307,6 +42283,7 @@ declare module "babylonjs/Debug/physicsViewer" {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -48223,10 +48200,6 @@ declare module "babylonjs/Instrumentation/sceneInstrumentation" {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -51335,7 +51308,6 @@ declare module "babylonjs/Materials/Textures/index" {
     export * from "babylonjs/Materials/Textures/hdrCubeTexture";
     export * from "babylonjs/Materials/Textures/internalTexture";
     export * from "babylonjs/Materials/Textures/internalTextureLoader";
-    export * from "babylonjs/Materials/Textures/internalTextureTracker";
     export * from "babylonjs/Materials/Textures/Loaders/index";
     export * from "babylonjs/Materials/Textures/mirrorTexture";
     export * from "babylonjs/Materials/Textures/multiRenderTarget";
@@ -51371,6 +51343,32 @@ declare module "babylonjs/Maths/index" {
     export * from "babylonjs/Maths/math";
     export * from "babylonjs/Maths/sphericalPolynomial";
 }
+declare module "babylonjs/Misc/workerPool" {
+    import { IDisposable } from "babylonjs/scene";
+    /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
 declare module "babylonjs/Meshes/Compression/dracoCompression" {
     import { IDisposable } from "babylonjs/scene";
     import { VertexData } from "babylonjs/Meshes/mesh.vertexData";
@@ -51435,7 +51433,7 @@ declare module "babylonjs/Meshes/Compression/dracoCompression" {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -51448,25 +51446,38 @@ declare module "babylonjs/Meshes/Compression/dracoCompression" {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module "babylonjs/Meshes/Compression/index" {
@@ -58638,32 +58649,6 @@ declare module "babylonjs/Misc/videoRecorder" {
         private _handleStop;
     }
 }
-declare module "babylonjs/Misc/workerPool" {
-    import { IDisposable } from "babylonjs/scene";
-    /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
 declare module "babylonjs/Misc/screenshotTools" {
     import { Camera } from "babylonjs/Cameras/camera";
     import { Engine } from "babylonjs/Engines/engine";
@@ -62696,6 +62681,14 @@ declare module BABYLON {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -65597,38 +65590,10 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
@@ -65755,20 +65720,10 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         _invertVScale: boolean;
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         _dataSource: number;
         /** @hidden */
@@ -83465,6 +83420,10 @@ declare module BABYLON {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -86690,12 +86649,6 @@ declare module BABYLON {
         /** @hidden */
         _badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -86744,8 +86697,6 @@ declare module BABYLON {
         private _loadingScreen;
         /** @hidden */
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -86828,8 +86779,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -88091,10 +88040,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -90551,6 +90496,12 @@ declare module BABYLON {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -94345,6 +94296,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -94563,8 +94527,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -100285,6 +100247,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -100309,6 +100272,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -105792,10 +105756,6 @@ declare module BABYLON {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -108661,6 +108621,31 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      */
     export interface IDracoCompressionConfiguration {
@@ -108721,7 +108706,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -108734,25 +108719,38 @@ declare module BABYLON {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module BABYLON {
@@ -115398,31 +115396,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      */
     export class ScreenshotTools {

+ 39 - 39
dist/preview release/gui/babylon.gui.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -355,7 +355,7 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -498,7 +498,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
@@ -1619,7 +1619,7 @@ var Button = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -1800,7 +1800,7 @@ var Checkbox = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3247,7 +3247,7 @@ var ColorPicker = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3652,7 +3652,7 @@ var Container = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -6212,7 +6212,7 @@ var Grid = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
@@ -6987,7 +6987,7 @@ var InputPassword = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -7996,7 +7996,7 @@ var InputText = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8264,7 +8264,7 @@ var Line = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -8531,7 +8531,7 @@ var MultiLine = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -8876,7 +8876,7 @@ var Rectangle = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScrollViewer", function() { return ScrollViewer; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Events/pointerEvents */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Events/pointerEvents */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Events_pointerEvents__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _rectangle__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../rectangle */ "./2D/controls/rectangle.ts");
 /* harmony import */ var _grid__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../grid */ "./2D/controls/grid.ts");
@@ -9967,7 +9967,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -10862,7 +10862,7 @@ var Slider = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -11120,7 +11120,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -11560,7 +11560,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -11935,7 +11935,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -12159,7 +12159,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -12292,7 +12292,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -12435,7 +12435,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -12742,7 +12742,7 @@ var ValueAndUnit = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -12785,7 +12785,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -12962,7 +12962,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -13119,7 +13119,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
@@ -13513,7 +13513,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -13598,7 +13598,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -14074,7 +14074,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -14129,7 +14129,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -14256,7 +14256,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -14341,7 +14341,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -14466,7 +14466,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -14657,7 +14657,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
@@ -14924,7 +14924,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -15246,7 +15246,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentPixelShader';
@@ -15268,7 +15268,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentVertexShader';
@@ -15291,7 +15291,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math */ "babylonjs/Misc/tools");
 /* harmony import */ var babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -15585,14 +15585,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/observable":
+/***/ "babylonjs/Misc/tools":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__;
 
 /***/ })
 

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


+ 0 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -39188,7 +39188,6 @@ var StatisticsTabComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active bones", value: scene.getActiveBones().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Active particles", value: scene.getActiveParticles().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Draw calls", value: sceneInstrumentation.drawCallsCounter.current.toString() }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Texture collisions", value: sceneInstrumentation.textureCollisionsCounter.current.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total lights", value: scene.lights.length.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total vertices", value: scene.getTotalVertices().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total materials", value: scene.materials.length.toString() }),

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 13 - 6
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -277,13 +277,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
     }
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         delete this._loader;
     };
@@ -324,10 +325,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
@@ -1570,6 +1572,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
@@ -1577,6 +1582,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
             }

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 13 - 6
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2826,13 +2826,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
     }
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         delete this._loader;
     };
@@ -2873,10 +2874,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
@@ -4119,6 +4121,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
@@ -4126,6 +4131,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
             }

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -1545,10 +1545,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */

+ 13 - 6
dist/preview release/loaders/babylonjs.loaders.js

@@ -4158,13 +4158,14 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
         this.name = NAME;
         /** Defines whether this extension is enabled. */
         this.enabled = babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"].DecoderAvailable;
+        this._dracoCompressionOwned = false;
         this._loader = loader;
     }
     /** @hidden */
     KHR_draco_mesh_compression.prototype.dispose = function () {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
         delete this._loader;
     };
@@ -4205,10 +4206,11 @@ var KHR_draco_mesh_compression = /** @class */ (function () {
             var bufferView = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext, _this._loader.gltf.bufferViews, extension.bufferView);
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = _this._loader.loadBufferViewAsync("#/bufferViews/" + bufferView.index, bufferView).then(function (data) {
-                    if (!_this._dracoCompression) {
-                        _this._dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                    if (!_this.dracoCompression) {
+                        _this.dracoCompression = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["DracoCompression"]();
+                        _this._dracoCompressionOwned = true;
                     }
-                    return _this._dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
+                    return _this.dracoCompression.decodeMeshAsync(data, attributes).then(function (babylonVertexData) {
                         var babylonGeometry = new babylonjs_Meshes_Compression_dracoCompression__WEBPACK_IMPORTED_MODULE_0__["Geometry"](babylonMesh.name, _this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;
@@ -5451,6 +5453,9 @@ var GLTFLoader = /** @class */ (function () {
             _this._setState(_glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoaderState"].LOADING);
             _this._extensionsOnLoading();
             var promises = new Array();
+            // Block the marking of materials dirty until the scene is loaded.
+            var oldBlockMaterialDirtyMechanism = _this._babylonScene.blockMaterialDirtyMechanism;
+            _this._babylonScene.blockMaterialDirtyMechanism = true;
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
@@ -5458,6 +5463,8 @@ var GLTFLoader = /** @class */ (function () {
                 var scene = ArrayItem.Get("/scene", _this._gltf.scenes, _this._gltf.scene || 0);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
+            // Restore the blocking of material dirty.
+            _this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
             if (_this._parent.compileMaterials) {
                 promises.push(_this._compileMaterialsAsync());
             }

Файловите разлики са ограничени, защото са твърде много
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 7 - 2
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1628,6 +1628,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/EXT_lights_image_based" {
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
+    import { DracoCompression } from "babylonjs/Meshes/Compression/dracoCompression";
     import { Nullable } from "babylonjs/types";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Mesh } from "babylonjs/Meshes/mesh";
@@ -1640,10 +1641,12 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */
@@ -3784,10 +3787,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"engineOnly":308951,"sceneOnly":510921,"minGridMaterial":634690,"minStandardMaterial":758509}
+{"engineOnly":306992,"sceneOnly":509059,"minGridMaterial":632828,"minStandardMaterial":756647}

+ 165 - 192
dist/preview release/viewer/babylon.module.d.ts

@@ -3258,6 +3258,14 @@ declare module "babylonjs/Maths/math" {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -6175,47 +6183,17 @@ declare module "babylonjs/Instrumentation/timeToken" {
         _timeElapsedQueryEnded: boolean;
     }
 }
-declare module "babylonjs/Materials/Textures/internalTextureTracker" {
-    import { Nullable } from "babylonjs/types";
-    /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
 declare module "babylonjs/Materials/Textures/internalTexture" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Nullable, int } from "babylonjs/types";
     import { SphericalPolynomial } from "babylonjs/Maths/sphericalPolynomial";
-    import { IInternalTextureTracker } from "babylonjs/Materials/Textures/internalTextureTracker";
     import { Engine } from "babylonjs/Engines/engine";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
@@ -6342,20 +6320,10 @@ declare module "babylonjs/Materials/Textures/internalTexture" {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         _invertVScale: boolean;
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         _dataSource: number;
         /** @hidden */
@@ -24663,6 +24631,10 @@ declare module "babylonjs/Meshes/abstractMesh" {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -27972,12 +27944,6 @@ declare module "babylonjs/Engines/engine" {
         /** @hidden */
         _badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -28026,8 +27992,6 @@ declare module "babylonjs/Engines/engine" {
         private _loadingScreen;
         /** @hidden */
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -28110,8 +28074,6 @@ declare module "babylonjs/Engines/engine" {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -29373,10 +29335,6 @@ declare module "babylonjs/Engines/engine" {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -31877,6 +31835,12 @@ declare module "babylonjs/Misc/tools" {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -35838,6 +35802,19 @@ declare module "babylonjs/Cameras/arcRotateCamera" {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -36056,8 +36033,6 @@ declare module "babylonjs/Cameras/arcRotateCamera" {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -42283,6 +42258,7 @@ declare module "babylonjs/Debug/physicsViewer" {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -42307,6 +42283,7 @@ declare module "babylonjs/Debug/physicsViewer" {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -48223,10 +48200,6 @@ declare module "babylonjs/Instrumentation/sceneInstrumentation" {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -51335,7 +51308,6 @@ declare module "babylonjs/Materials/Textures/index" {
     export * from "babylonjs/Materials/Textures/hdrCubeTexture";
     export * from "babylonjs/Materials/Textures/internalTexture";
     export * from "babylonjs/Materials/Textures/internalTextureLoader";
-    export * from "babylonjs/Materials/Textures/internalTextureTracker";
     export * from "babylonjs/Materials/Textures/Loaders/index";
     export * from "babylonjs/Materials/Textures/mirrorTexture";
     export * from "babylonjs/Materials/Textures/multiRenderTarget";
@@ -51371,6 +51343,32 @@ declare module "babylonjs/Maths/index" {
     export * from "babylonjs/Maths/math";
     export * from "babylonjs/Maths/sphericalPolynomial";
 }
+declare module "babylonjs/Misc/workerPool" {
+    import { IDisposable } from "babylonjs/scene";
+    /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
 declare module "babylonjs/Meshes/Compression/dracoCompression" {
     import { IDisposable } from "babylonjs/scene";
     import { VertexData } from "babylonjs/Meshes/mesh.vertexData";
@@ -51435,7 +51433,7 @@ declare module "babylonjs/Meshes/Compression/dracoCompression" {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -51448,25 +51446,38 @@ declare module "babylonjs/Meshes/Compression/dracoCompression" {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module "babylonjs/Meshes/Compression/index" {
@@ -58638,32 +58649,6 @@ declare module "babylonjs/Misc/videoRecorder" {
         private _handleStop;
     }
 }
-declare module "babylonjs/Misc/workerPool" {
-    import { IDisposable } from "babylonjs/scene";
-    /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
 declare module "babylonjs/Misc/screenshotTools" {
     import { Camera } from "babylonjs/Cameras/camera";
     import { Engine } from "babylonjs/Engines/engine";
@@ -62696,6 +62681,14 @@ declare module BABYLON {
          */
         static RotationAxisToRef(axis: DeepImmutable<Vector3>, angle: number, result: Matrix): void;
         /**
+         * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+         * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+         * @param from defines the vector to align
+         * @param to defines the vector to align to
+         * @param result defines the target matrix
+         */
+        static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void;
+        /**
          * Creates a rotation matrix
          * @param yaw defines the yaw angle in radians (Y axis)
          * @param pitch defines the pitch angle in radians (X axis)
@@ -65597,38 +65590,10 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Internal interface used to track InternalTexture already bound to the GL context
-     */
-    export interface IInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-    /**
-     * Internal class used by the engine to get list of InternalTexture already bound to the GL context
-     */
-    export class DummyInternalTextureTracker {
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
-    }
-}
-declare module BABYLON {
-    /**
      * Class used to store data associated with WebGL texture data for the engine
      * This class should not be used directly
      */
-    export class InternalTexture implements IInternalTextureTracker {
+    export class InternalTexture {
         /** hidden */
         static _UpdateRGBDAsync: (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: SphericalPolynomial | null, lodScale: number, lodOffset: number) => Promise<void>;
         /**
@@ -65755,20 +65720,10 @@ declare module BABYLON {
          * Gets a boolean indicating if the texture is inverted on Y axis
          */
         invertY: boolean;
-        /**
-         * Gets or set the previous tracker in the list
-         */
-        previous: Nullable<IInternalTextureTracker>;
-        /**
-         * Gets or set the next tracker in the list
-         */
-        next: Nullable<IInternalTextureTracker>;
         /** @hidden */
         _invertVScale: boolean;
         /** @hidden */
-        _initialSlot: number;
-        /** @hidden */
-        _designatedSlot: number;
+        _associatedChannel: number;
         /** @hidden */
         _dataSource: number;
         /** @hidden */
@@ -83465,6 +83420,10 @@ declare module BABYLON {
          */
         alwaysSelectAsActiveMesh: boolean;
         /**
+         * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+         */
+        doNotSyncBoundingInfo: boolean;
+        /**
          * Gets or sets the current action manager
          * @see http://doc.babylonjs.com/how_to/how_to_use_actions
          */
@@ -86690,12 +86649,6 @@ declare module BABYLON {
         /** @hidden */
         _badDesktopOS: boolean;
         /**
-         * Gets or sets a value indicating if we want to disable texture binding optimization.
-         * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-         * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-         */
-        disableTextureBindingOptimization: boolean;
-        /**
          * Gets the audio engine
          * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
          * @ignorenaming
@@ -86744,8 +86697,6 @@ declare module BABYLON {
         private _loadingScreen;
         /** @hidden */
         _drawCalls: PerfCounter;
-        /** @hidden */
-        _textureCollisions: PerfCounter;
         private _glVersion;
         private _glRenderer;
         private _glVendor;
@@ -86828,8 +86779,6 @@ declare module BABYLON {
         private _currentInstanceLocations;
         private _currentInstanceBuffers;
         private _textureUnits;
-        private _firstBoundInternalTextureTracker;
-        private _lastBoundInternalTextureTracker;
         private _workingCanvas;
         private _workingContext;
         private _rescalePostProcess;
@@ -88091,10 +88040,6 @@ declare module BABYLON {
          * @param effect defines the effect to bind
          */
         bindSamplers(effect: Effect): void;
-        private _moveBoundTextureOnTop;
-        private _getCorrectTextureChannel;
-        private _linkTrackers;
-        private _removeDesignatedSlot;
         private _activateCurrentTexture;
         /** @hidden */
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate?: boolean, force?: boolean): boolean;
@@ -90551,6 +90496,12 @@ declare module BABYLON {
         */
         static DecodeBase64(uri: string): ArrayBuffer;
         /**
+         * Gets the absolute url.
+         * @param url the input url
+         * @return the absolute url
+         */
+        static GetAbsoluteUrl(url: string): string;
+        /**
          * No log
          */
         static readonly NoneLogLevel: number;
@@ -94345,6 +94296,19 @@ declare module BABYLON {
          * Define the current local position of the camera in the scene
          */
         position: Vector3;
+        protected _upVector: Vector3;
+        protected _upToYMatrix: Matrix;
+        protected _YToUpMatrix: Matrix;
+        /**
+         * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+         * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+         * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+         */
+        upVector: Vector3;
+        /**
+         * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+         */
+        setMatUp(): void;
         /**
          * Current inertia value on the longitudinal axis.
          * The bigger this number the longer it will take for the camera to stop.
@@ -94563,8 +94527,6 @@ declare module BABYLON {
         protected _collisionTriggered: boolean;
         protected _targetBoundingCenter: Nullable<Vector3>;
         private _computationVector;
-        private _tempAxisVector;
-        private _tempAxisRotationMatrix;
         /**
          * Instantiates a new ArcRotateCamera in a given scene
          * @param name Defines the name of the camera
@@ -100285,6 +100247,7 @@ declare module BABYLON.Debug {
         private _utilityLayer;
         private _debugBoxMesh;
         private _debugSphereMesh;
+        private _debugCylinderMesh;
         private _debugMaterial;
         private _debugMeshMeshes;
         /**
@@ -100309,6 +100272,7 @@ declare module BABYLON.Debug {
         private _getDebugMaterial;
         private _getDebugBoxMesh;
         private _getDebugSphereMesh;
+        private _getDebugCylinderMesh;
         private _getDebugMeshMesh;
         private _getDebugMesh;
         /** Releases all resources */
@@ -105792,10 +105756,6 @@ declare module BABYLON {
          */
         readonly drawCallsCounter: PerfCounter;
         /**
-         * Gets the perf counter used for texture collisions
-         */
-        readonly textureCollisionsCounter: PerfCounter;
-        /**
          * Instantiates a new scene instrumentation.
          * This class can be used to get instrumentation data from a Babylon engine
          * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -108661,6 +108621,31 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to push actions to a pool of workers.
+     */
+    export class WorkerPool implements IDisposable {
+        private _workerInfos;
+        private _pendingActions;
+        /**
+         * Constructor
+         * @param workers Array of workers to use for actions
+         */
+        constructor(workers: Array<Worker>);
+        /**
+         * Terminates all workers and clears any pending actions.
+         */
+        dispose(): void;
+        /**
+         * 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.
+         */
+        push(action: (worker: Worker, onComplete: () => void) => void): void;
+        private _execute;
+    }
+}
+declare module BABYLON {
+    /**
      * Configuration for Draco compression
      */
     export interface IDracoCompressionConfiguration {
@@ -108721,7 +108706,7 @@ declare module BABYLON {
      * @see https://www.babylonjs-playground.com/#N3EK4B#0
      */
     export class DracoCompression implements IDisposable {
-        private static _DecoderModulePromise;
+        private _workerPoolPromise;
         /**
          * The configuration. Defaults to the following urls:
          * - wasmUrl: "https://preview.babylonjs.com/draco_wasm_wrapper_gltf.js"
@@ -108734,25 +108719,38 @@ declare module BABYLON {
          */
         static readonly DecoderAvailable: boolean;
         /**
+         * Default number of workers to create when creating the draco compression object.
+         */
+        static DefaultNumWorkers: number;
+        private static GetDefaultNumWorkers;
+        /**
          * Constructor
+         * @param numWorkers The number of workers for async operations
          */
-        constructor();
+        constructor(numWorkers?: number);
         /**
          * Stop all async operations and release resources.
          */
         dispose(): void;
         /**
-         * Decode Draco compressed mesh data to vertex data.
-         * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
-         * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
-         * @returns A promise that resolves with the decoded vertex data
+         * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+         * @returns a promise that resolves when ready
          */
+        whenReadyAsync(): Promise<void>;
+        /**
+          * Decode Draco compressed mesh data to vertex data.
+          * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
+          * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
+          * @returns A promise that resolves with the decoded vertex data
+          */
         decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: {
             [kind: string]: number;
         }): Promise<VertexData>;
-        private static _GetDecoderModule;
-        private static _LoadScriptAsync;
-        private static _LoadFileAsync;
+        /**
+         * The worker function that gets converted to a blob url to pass into a worker.
+         */
+        private static _Worker;
+        private _loadDecoderWasmBinaryAsync;
     }
 }
 declare module BABYLON {
@@ -115398,31 +115396,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Helper class to push actions to a pool of workers.
-     */
-    export class WorkerPool implements IDisposable {
-        private _workerInfos;
-        private _pendingActions;
-        /**
-         * Constructor
-         * @param workers Array of workers to use for actions
-         */
-        constructor(workers: Array<Worker>);
-        /**
-         * Terminates all workers and clears any pending actions.
-         */
-        dispose(): void;
-        /**
-         * 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.
-         */
-        push(action: (worker: Worker, onComplete: () => void) => void): void;
-        private _execute;
-    }
-}
-declare module BABYLON {
-    /**
      * Class containing a set of static utilities functions for screenshots
      */
     export class ScreenshotTools {

+ 5 - 19
dist/preview release/viewer/babylon.viewer.d.ts

@@ -197,11 +197,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -218,11 +218,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -951,7 +951,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1594,20 +1594,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {
             /**
                 * Environment map texture path in relative to the asset folder.

Файловите разлики са ограничени, защото са твърде много
+ 18 - 22
dist/preview release/viewer/babylon.viewer.js


Файловите разлики са ограничени, защото са твърде много
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 5 - 22
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -230,11 +230,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -251,11 +251,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -1031,14 +1031,13 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1738,22 +1737,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

+ 7 - 2
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -1628,6 +1628,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/EXT_lights_image_based" {
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression" {
+    import { DracoCompression } from "babylonjs/Meshes/Compression/dracoCompression";
     import { Nullable } from "babylonjs/types";
     import { Geometry } from "babylonjs/Meshes/geometry";
     import { Mesh } from "babylonjs/Meshes/mesh";
@@ -1640,10 +1641,12 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_draco_mesh_compression
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */
@@ -3784,10 +3787,12 @@ declare module BABYLON.GLTF2.Loader.Extensions {
     export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
         /** The name of this extension. */
         readonly name: string;
+        /** The draco compression used to decode vertex data. */
+        dracoCompression?: DracoCompression;
         /** Defines whether this extension is enabled. */
         enabled: boolean;
         private _loader;
-        private _dracoCompression?;
+        private _dracoCompressionOwned;
         /** @hidden */
         constructor(loader: GLTFLoader);
         /** @hidden */

+ 8 - 2
dist/preview release/what's new.md

@@ -135,6 +135,11 @@
 - Added customShaderNameResolve to PBRMaterialBase to allow subclasses to specify custom shader information [MackeyK24](https://github.com/mackeyk24))
 - Added PBRCustomMaterial to material library to allow easy subclassing of PBR materials [MackeyK24](https://github.com/mackeyk24))
 - Added `auto-exposure` support in `StandardRenderingPipeline` when `HDR` is enabled ([julien-moreau](https://github.com/julien-moreau))
+- Add `EquiRectangularCubeTexture` class to enable the usage of browser-canvas supported images as `CubeTexture`'s ([Dennis Dervisis](https://github.com/ddervisis))
+- Add `EquiRectangularCubeTextureAssetTask` to be able to load `EquiRectangularCubeTextures`s via Asset Manager ([Dennis Dervisis](https://github.com/ddervisis))
+- Added `Matrix.RotationAlignToRef` method to obtain rotation matrix from one vector to another ([sable](https://github.com/thscott))
+- ArcRotateCamera will now cache the necessary matrices when modifying its upVector, instead of calculating them each time they're needed ([sable](https://github.com/thscott))
+- Update `DracoCompression` to use web workers ([bghgary](https://github.com/bghgary))
 
 ### OBJ Loader
 - Add color vertex support (not part of standard) ([brianzinn](https://github.com/brianzinn))
@@ -150,8 +155,7 @@
 - Skinned meshes now behave as intended by glTF ([bghgary](https://github.com/bghgary))
   - Skinned meshes now set an override mesh instead of reparenting to the `__root__` transform node
   - Loaded bones are linked with the transform node created for the corresponding glTF node
-- Add `EquiRectangularCubeTexture` class to enable the usage of browser-canvas supported images as `CubeTexture`'s ([Dennis Dervisis](https://github.com/ddervisis))
-- Add `EquiRectangularCubeTextureAssetTask` to be able to load `EquiRectangularCubeTextures`s via Asset Manager ([Dennis Dervisis](https://github.com/ddervisis))
+- Improve load performance by blocking material dirtying during load ([bghgary](https://github.com/bghgary))
 
 ### glTF Serializer
 
@@ -219,6 +223,8 @@
 - Fix `mesh.visibility` not working properly when certain material properties are set that changes the interpretation of alpha (e.g. refraction, specular over alpha, etc.) ([bghgary](https://github.com/bghgary))
 - Fix material and texture leak when loading/removing GLTF/obj/babylon files with AssetContainer ([TrevorDev](https://github.com/TrevorDev))
 - Avoid exception when removing impostor during cannon world step ([TrevorDev](https://github.com/TrevorDev))
+- Fix ArcRotateCamera divide by zero error (when looking along up axis) in rebuildAnglesAndRadius ([sable](https://github.com/thscott))
+- Fix ArcRotateCamera rebuildAnglesAndRadius when upVector modified ([sable](https://github.com/thscott))
 
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))

+ 0 - 1
inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx

@@ -82,7 +82,6 @@ export class StatisticsTabComponent extends PaneComponent {
                     <TextLineComponent label="Active bones" value={scene.getActiveBones().toString()} />
                     <TextLineComponent label="Active particles" value={scene.getActiveParticles().toString()} />
                     <TextLineComponent label="Draw calls" value={sceneInstrumentation.drawCallsCounter.current.toString()} />
-                    <TextLineComponent label="Texture collisions" value={sceneInstrumentation.textureCollisionsCounter.current.toString()} />
                     <TextLineComponent label="Total lights" value={scene.lights.length.toString()} />
                     <TextLineComponent label="Total vertices" value={scene.getTotalVertices().toString()} />
                     <TextLineComponent label="Total materials" value={scene.materials.length.toString()} />

+ 11 - 7
loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts

@@ -27,11 +27,14 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
     /** The name of this extension. */
     public readonly name = NAME;
 
+    /** The draco compression used to decode vertex data. */
+    public dracoCompression?: DracoCompression;
+
     /** Defines whether this extension is enabled. */
     public enabled = DracoCompression.DecoderAvailable;
 
     private _loader: GLTFLoader;
-    private _dracoCompression?: DracoCompression;
+    private _dracoCompressionOwned = false;
 
     /** @hidden */
     constructor(loader: GLTFLoader) {
@@ -40,9 +43,9 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
 
     /** @hidden */
     public dispose(): void {
-        if (this._dracoCompression) {
-            this._dracoCompression.dispose();
-            delete this._dracoCompression;
+        if (this.dracoCompression && this._dracoCompressionOwned) {
+            this.dracoCompression.dispose();
+            delete this.dracoCompression;
         }
 
         delete this._loader;
@@ -90,11 +93,12 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension {
             var bufferView = ArrayItem.Get(extensionContext, this._loader.gltf.bufferViews, extension.bufferView) as IBufferViewDraco;
             if (!bufferView._dracoBabylonGeometry) {
                 bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`#/bufferViews/${bufferView.index}`, bufferView).then((data) => {
-                    if (!this._dracoCompression) {
-                        this._dracoCompression = new DracoCompression();
+                    if (!this.dracoCompression) {
+                        this.dracoCompression = new DracoCompression();
+                        this._dracoCompressionOwned = true;
                     }
 
-                    return this._dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
+                    return this.dracoCompression.decodeMeshAsync(data, attributes).then((babylonVertexData) => {
                         const babylonGeometry = new Geometry(babylonMesh.name, this._loader.babylonScene);
                         babylonVertexData.applyToGeometry(babylonGeometry);
                         return babylonGeometry;

+ 7 - 0
loaders/src/glTF/2.0/glTFLoader.ts

@@ -273,6 +273,10 @@ export class GLTFLoader implements IGLTFLoader {
 
             const promises = new Array<Promise<any>>();
 
+            // Block the marking of materials dirty until the scene is loaded.
+            const oldBlockMaterialDirtyMechanism = this._babylonScene.blockMaterialDirtyMechanism;
+            this._babylonScene.blockMaterialDirtyMechanism = true;
+
             if (nodes) {
                 promises.push(this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
@@ -281,6 +285,9 @@ export class GLTFLoader implements IGLTFLoader {
                 promises.push(this.loadSceneAsync(`/scenes/${scene.index}`, scene));
             }
 
+            // Restore the blocking of material dirty.
+            this._babylonScene.blockMaterialDirtyMechanism = oldBlockMaterialDirtyMechanism;
+
             if (this._parent.compileMaterials) {
                 promises.push(this._compileMaterialsAsync());
             }

+ 91 - 0
sandbox/debug.html

@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+    <title>BabylonJS Sandbox - View glTF, glb, obj and babylon files</title>
+    <meta name="description" content="Viewer for glTF, glb, obj and babylon files powered by BabylonJS" />
+    <meta name="keywords"
+        content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
+    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
+
+    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
+    <link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
+    <link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
+    <link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
+    <link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
+    <link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
+    <link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
+    <link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
+    <link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
+    <link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
+    <link rel="icon" type="image/png" sizes="192x192"
+        href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
+    <link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
+    <link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
+    <link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
+    <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
+    <meta name="msapplication-TileColor" content="#ffffff">
+    <meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
+    <meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
+    <meta name="theme-color" content="#ffffff">
+
+    <link href="index.css" rel="stylesheet" />
+    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+    <script src="https://playground.babylonjs.com/js/libs/split.js"></script>
+
+    <script src="https://preview.babylonjs.com/ammo.js"></script>
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://preview.babylonjs.com/gltf_validator.js"></script>
+    <script src="https://preview.babylonjs.com/babylon.max.js"></script>
+    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
+    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.js"></script>
+    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.js"></script>
+</head>
+
+<body>
+    <div id="root">
+        <p id="droptext">Drag and drop gltf, glb, obj or babylon files to view them</p>
+        <div id="canvasZone">
+            <canvas id="renderCanvas" touch-action="none"></canvas>
+        </div>
+        <div id="footer" class="footer">
+            <div id="animationBar">
+                <div class="dropdown">
+                    <div id="dropdownBtn">
+                        <img src="Assets/Icon_Up.svg" id="chevronUp">
+                        <img src="Assets/Icon_Down.svg" id="chevronDown">
+                        <span id="dropdownLabel"></span>
+                    </div>
+                    <div id="dropdownContent">
+                    </div>
+                </div>
+                <div class="row">
+                    <button id="playBtn" class="pause">
+                        <img id="playImg" src="Assets/Icon_Play.svg">
+                        <img id="pauseImg" src="Assets/Icon_Pause.svg">
+                    </button>
+                    <input id="slider" type="range" min="0" max="100" value="0" step="any">
+                </div>
+            </div>
+            <div class="footerRight">
+                <a href="javascript:void(null);" id="btnInspector" class="hidden"><img src="./Assets/Icon_EditModel.svg"
+                        alt="Display inspector" title="Display inspector" /></a>
+                <a href="javascript:void(null);">
+                    <div class="custom-upload"
+                        title="Open your scene from your hard drive (.babylon, .gltf, .glb, .obj)">
+                        <input type="file" id="files" multiple />
+                    </div>
+                </a>
+            </div>
+        </div>
+        <div id="logo">
+        </div>
+        <div id="errorZone"></div>
+    </div>
+    <script src="index.js"></script>
+</body>
+
+</html>

+ 1 - 1
sandbox/index.js

@@ -112,7 +112,7 @@ if (BABYLON.Engine.isSupported()) {
             }
             currentGroup = babylonScene.animationGroups[0];
             currentGroupIndex = 0;
-            document.getElementById(formatId(currentGroup.name + "-" + currentGroupIndex)).click();
+            currentGroup.play(true);
         }
 
         // Sync the slider with the current frame

+ 52 - 19
src/Cameras/arcRotateCamera.ts

@@ -74,6 +74,45 @@ export class ArcRotateCamera extends TargetCamera {
         this.setPosition(newPosition);
     }
 
+    @serializeAsVector3("upVector")
+    protected _upVector = Vector3.Up();
+
+    protected _upToYMatrix: Matrix;
+    protected _YToUpMatrix: Matrix;
+
+    /**
+     * The vector the camera should consider as up. (default is Vector3(0, 1, 0) as returned by Vector3.Up())
+     * Setting this will copy the given vector to the camera's upVector, and set rotation matrices to and from Y up.
+     * DO NOT set the up vector using copyFrom or copyFromFloats, as this bypasses setting the above matrices.
+     */
+    set upVector(vec: Vector3) {
+        if (!this._upToYMatrix) {
+            this._YToUpMatrix = new Matrix();
+            this._upToYMatrix = new Matrix();
+
+            this._upVector = Vector3.Zero();
+        }
+
+        vec.normalize();
+        this._upVector.copyFrom(vec);
+        this.setMatUp();
+    }
+
+    get upVector() {
+        return this._upVector;
+    }
+
+    /**
+     * Sets the Y-up to camera up-vector rotation matrix, and the up-vector to Y-up rotation matrix.
+     */
+    public setMatUp() {
+        // from y-up to custom-up (used in _getViewMatrix)
+        Matrix.RotationAlignToRef(Vector3.UpReadOnly, this._upVector, this._YToUpMatrix);
+
+        // from custom-up to y-up (used in rebuildAnglesAndRadius)
+        Matrix.RotationAlignToRef(this._upVector, Vector3.UpReadOnly, this._upToYMatrix);
+    }
+
     /**
      * Current inertia value on the longitudinal axis.
      * The bigger this number the longer it will take for the camera to stop.
@@ -574,8 +613,6 @@ export class ArcRotateCamera extends TargetCamera {
     protected _targetBoundingCenter: Nullable<Vector3>;
 
     private _computationVector: Vector3 = Vector3.Zero();
-    private _tempAxisVector: Vector3;
-    private _tempAxisRotationMatrix: Matrix;
 
     /**
      * Instantiates a new ArcRotateCamera in a given scene
@@ -859,6 +896,12 @@ export class ArcRotateCamera extends TargetCamera {
      */
     public rebuildAnglesAndRadius(): void {
         this._position.subtractToRef(this._getTargetPosition(), this._computationVector);
+
+        // need to rotate to Y up equivalent if up vector not Axis.Y
+        if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
+            Vector3.TransformCoordinatesToRef(this._computationVector, this._upToYMatrix, this._computationVector);
+        }
+
         this.radius = this._computationVector.length();
 
         if (this.radius === 0) {
@@ -866,7 +909,11 @@ export class ArcRotateCamera extends TargetCamera {
         }
 
         // Alpha
-        this.alpha = Math.acos(this._computationVector.x / Math.sqrt(Math.pow(this._computationVector.x, 2) + Math.pow(this._computationVector.z, 2)));
+        if (this._computationVector.x === 0 && this._computationVector.z === 0) {
+            this.alpha = Math.PI / 2; // avoid division by zero when looking along up axis, and set to acos(0)
+        } else {
+            this.alpha = Math.acos(this._computationVector.x / Math.sqrt(Math.pow(this._computationVector.x, 2) + Math.pow(this._computationVector.z, 2)));
+        }
 
         if (this._computationVector.z < 0) {
             this.alpha = 2 * Math.PI - this.alpha;
@@ -942,22 +989,8 @@ export class ArcRotateCamera extends TargetCamera {
         this._computationVector.copyFromFloats(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb);
 
         // Rotate according to up vector
-        if (this.upVector.x !== 0 || this.upVector.y !== 1.0 || this.upVector.z !== 0) {
-
-            if (!this._tempAxisVector) {
-                this._tempAxisVector = new Vector3();
-                this._tempAxisRotationMatrix = new Matrix();
-            }
-
-            Vector3.CrossToRef(Vector3.Up(), this.upVector, this._tempAxisVector);
-            this._tempAxisVector.normalize();
-
-            let angle = Math.acos(Vector3.Dot(Vector3.UpReadOnly, this.upVector));
-
-            Matrix.RotationAxisToRef(this._tempAxisVector, angle, this._tempAxisRotationMatrix);
-
-            this._tempAxisVector.copyFrom(this._computationVector);
-            Vector3.TransformCoordinatesToRef(this._tempAxisVector, this._tempAxisRotationMatrix, this._computationVector);
+        if (this._upVector.x !== 0 || this._upVector.y !== 1.0 || this._upVector.z !== 0) {
+            Vector3.TransformCoordinatesToRef(this._computationVector, this._YToUpMatrix, this._computationVector);
         }
 
         target.addToRef(this._computationVector, this._newPosition);

+ 23 - 0
src/Debug/physicsViewer.ts

@@ -11,6 +11,7 @@ import { StandardMaterial } from "../Materials/standardMaterial";
 import { IPhysicsEnginePlugin } from "../Physics/IPhysicsEngine";
 import { PhysicsImpostor } from "../Physics/physicsImpostor";
 import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
+import { CylinderBuilder } from '../Meshes/Builders/cylinderBuilder';
 
 /**
      * Used to show the physics impostor around the specific mesh
@@ -32,6 +33,7 @@ export class PhysicsViewer {
 
     private _debugBoxMesh: Mesh;
     private _debugSphereMesh: Mesh;
+    private _debugCylinderMesh: Mesh;
     private _debugMaterial: StandardMaterial;
     private _debugMeshMeshes = new Array<Mesh>();
 
@@ -196,6 +198,17 @@ export class PhysicsViewer {
         return this._debugSphereMesh.createInstance('physicsBodyBoxViewInstance');
     }
 
+    private _getDebugCylinderMesh(scene: Scene): AbstractMesh {
+        if (!this._debugCylinderMesh) {
+            this._debugCylinderMesh = CylinderBuilder.CreateCylinder('physicsBodyCylinderViewMesh', { diameterTop: 1, diameterBottom: 1, height: 1 }, scene);
+            this._debugCylinderMesh.rotationQuaternion = Quaternion.Identity();
+            this._debugCylinderMesh.material = this._getDebugMaterial(scene);
+            this._debugCylinderMesh.setEnabled(false);
+        }
+
+        return this._debugCylinderMesh.createInstance('physicsBodyBoxViewInstance');
+    }
+
     private _getDebugMeshMesh(mesh: Mesh, scene: Scene): AbstractMesh {
         var wireframeOver = new Mesh(mesh.name, scene, null, mesh);
         wireframeOver.position = Vector3.Zero();
@@ -247,6 +260,13 @@ export class PhysicsViewer {
                     });
                 }
                 break;
+            case PhysicsImpostor.CylinderImpostor:
+                mesh = this._getDebugCylinderMesh(utilityLayerScene);
+                var bi = impostor.object.getBoundingInfo();
+                mesh.scaling.x = bi.boundingBox.maximum.x - bi.boundingBox.minimum.x;
+                mesh.scaling.y = bi.boundingBox.maximum.y - bi.boundingBox.minimum.y;
+                mesh.scaling.z = bi.boundingBox.maximum.z - bi.boundingBox.minimum.z;
+                break;
         }
         return mesh;
     }
@@ -264,6 +284,9 @@ export class PhysicsViewer {
         if (this._debugSphereMesh) {
             this._debugSphereMesh.dispose();
         }
+        if (this._debugCylinderMesh) {
+            this._debugCylinderMesh.dispose();
+        }
         if (this._debugMaterial) {
             this._debugMaterial.dispose();
         }

+ 22 - 130
src/Engines/engine.ts

@@ -13,7 +13,6 @@ import { VertexBuffer } from "../Meshes/buffer";
 import { UniformBuffer } from "../Materials/uniformBuffer";
 import { Effect, EffectCreationOptions, EffectFallbacks } from "../Materials/effect";
 import { Material } from "../Materials/material";
-import { IInternalTextureTracker, DummyInternalTextureTracker } from "../Materials/Textures/internalTextureTracker";
 import { IInternalTextureLoader } from "../Materials/Textures/internalTextureLoader";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
@@ -246,9 +245,6 @@ export class Engine {
         { key: "Chrome\/63\.0", capture: "63\\.0\\.3239\\.(\\d+)", captureConstraint: 108, targets: ["uniformBuffer"] },
         { key: "Firefox\/58", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
         { key: "Firefox\/59", capture: null, captureConstraint: null, targets: ["uniformBuffer"] },
-        { key: "Macintosh", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
-        { key: "iPhone", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
-        { key: "iPad", capture: null, captureConstraint: null, targets: ["textureBindingOptimization"] },
         { key: "Chrome\/72.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/73.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
         { key: "Chrome\/74.+?Mobile", capture: null, captureConstraint: null, targets: ["vao"] },
@@ -735,13 +731,6 @@ export class Engine {
     public _badDesktopOS = false;
 
     /**
-     * Gets or sets a value indicating if we want to disable texture binding optimization.
-     * This could be required on some buggy drivers which wants to have textures bound in a progressive order.
-     * By default Babylon.js will try to let textures bound where they are and only update the samplers to point where the texture is
-     */
-    public disableTextureBindingOptimization = false;
-
-    /**
      * Gets the audio engine
      * @see http://doc.babylonjs.com/how_to/playing_sounds_and_music
      * @ignorenaming
@@ -802,8 +791,6 @@ export class Engine {
 
     /** @hidden */
     public _drawCalls = new PerfCounter();
-    /** @hidden */
-    public _textureCollisions = new PerfCounter();
 
     private _glVersion: string;
     private _glRenderer: string;
@@ -908,8 +895,6 @@ export class Engine {
     private _currentInstanceLocations = new Array<number>();
     private _currentInstanceBuffers = new Array<WebGLBuffer>();
     private _textureUnits: Int32Array;
-    private _firstBoundInternalTextureTracker = new DummyInternalTextureTracker();
-    private _lastBoundInternalTextureTracker = new DummyInternalTextureTracker();
 
     private _workingCanvas: Nullable<HTMLCanvasElement>;
     private _workingContext: Nullable<CanvasRenderingContext2D>;
@@ -1090,9 +1075,6 @@ export class Engine {
                                 case "vao":
                                     this.disableVertexArrayObjects = true;
                                     break;
-                                case "textureBindingOptimization":
-                                    this.disableTextureBindingOptimization = true;
-                                    break;
                             }
                         }
                     }
@@ -1311,8 +1293,6 @@ export class Engine {
             this._currentBufferPointers[i] = new BufferPointer();
         }
 
-        this._linkTrackers(this._firstBoundInternalTextureTracker, this._lastBoundInternalTextureTracker);
-
         // Load WebVR Devices
         if (options.autoEnableWebVR) {
             this.initWebVR();
@@ -1605,20 +1585,9 @@ export class Engine {
             if (!this._boundTexturesCache.hasOwnProperty(key)) {
                 continue;
             }
-            let boundTexture = this._boundTexturesCache[key];
-            if (boundTexture) {
-                this._removeDesignatedSlot(boundTexture);
-            }
             this._boundTexturesCache[key] = null;
         }
 
-        if (!this.disableTextureBindingOptimization) {
-            this._nextFreeTextureSlots = [];
-            for (let slot = 0; slot < this._maxSimultaneousTextures; slot++) {
-                this._nextFreeTextureSlots.push(slot);
-            }
-        }
-
         this._currentTextureChannel = -1;
     }
 
@@ -2810,7 +2779,11 @@ export class Engine {
                 if (data instanceof ArrayBuffer) {
                     data = new Uint8Array(data, byteOffset, byteLength);
                 } else {
-                    data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
+                    let offset = data.byteOffset + byteOffset;
+
+                    if (offset || byteLength !== data.byteLength) {
+                        data = new Uint8Array(data.buffer, offset, byteLength);
+                    }
                 }
 
                 this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
@@ -6396,79 +6369,6 @@ export class Engine {
         this._currentEffect = null;
     }
 
-    private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
-        if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
-            return;
-        }
-
-        // Remove
-        this._linkTrackers(internalTexture.previous, internalTexture.next);
-
-        // Bind last to it
-        this._linkTrackers(this._lastBoundInternalTextureTracker.previous, internalTexture);
-
-        // Bind to dummy
-        this._linkTrackers(internalTexture, this._lastBoundInternalTextureTracker);
-    }
-
-    private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>): number {
-        if (!internalTexture) {
-            return -1;
-        }
-
-        internalTexture._initialSlot = channel;
-
-        if (this.disableTextureBindingOptimization) { // We want texture sampler ID === texture channel
-            if (channel !== internalTexture._designatedSlot) {
-                this._textureCollisions.addCount(1, false);
-            }
-        } else {
-            if (channel !== internalTexture._designatedSlot) {
-                if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
-                    return internalTexture._designatedSlot;
-                } else {
-                    // No slot for this texture, let's pick a new one (if we find a free slot)
-                    if (this._nextFreeTextureSlots.length) {
-                        return this._nextFreeTextureSlots[0];
-                    }
-
-                    // We need to recycle the oldest bound texture, sorry.
-                    this._textureCollisions.addCount(1, false);
-                    return this._removeDesignatedSlot(<InternalTexture>this._firstBoundInternalTextureTracker.next);
-                }
-            }
-        }
-
-        return channel;
-    }
-
-    private _linkTrackers(previous: Nullable<IInternalTextureTracker>, next: Nullable<IInternalTextureTracker>) {
-        previous!.next = next;
-        next!.previous = previous;
-    }
-
-    private _removeDesignatedSlot(internalTexture: InternalTexture): number {
-        let currentSlot = internalTexture._designatedSlot;
-        if (currentSlot === -1) {
-            return -1;
-        }
-
-        internalTexture._designatedSlot = -1;
-
-        if (this.disableTextureBindingOptimization) {
-            return -1;
-        }
-
-        // Remove from bound list
-        this._linkTrackers(internalTexture.previous, internalTexture.next);
-
-        // Free the slot
-        this._boundTexturesCache[currentSlot] = null;
-        this._nextFreeTextureSlots.push(currentSlot);
-
-        return currentSlot;
-    }
-
     private _activateCurrentTexture() {
         if (this._currentTextureChannel !== this._activeChannel) {
             this._gl.activeTexture(this._gl.TEXTURE0 + this._activeChannel);
@@ -6479,18 +6379,14 @@ export class Engine {
     /** @hidden */
     public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, forTextureDataUpdate = false, force = false): boolean {
         var wasPreviouslyBound = false;
-        if (forTextureDataUpdate && texture && texture._designatedSlot > -1) {
-            this._activeChannel = texture._designatedSlot;
+        let isTextureForRendering = texture && texture._associatedChannel > -1;
+        if (forTextureDataUpdate && isTextureForRendering) {
+            this._activeChannel = texture!._associatedChannel;
         }
 
         let currentTextureBound = this._boundTexturesCache[this._activeChannel];
-        let isTextureForRendering = texture && texture._initialSlot > -1;
 
         if (currentTextureBound !== texture || force) {
-            if (currentTextureBound) {
-                this._removeDesignatedSlot(currentTextureBound);
-            }
-
             this._activateCurrentTexture();
 
             if (texture && texture.isMultiview) {
@@ -6502,17 +6398,7 @@ export class Engine {
             this._boundTexturesCache[this._activeChannel] = texture;
 
             if (texture) {
-                if (!this.disableTextureBindingOptimization) {
-                    let slotIndex = this._nextFreeTextureSlots.indexOf(this._activeChannel);
-                    if (slotIndex > -1) {
-                        this._nextFreeTextureSlots.splice(slotIndex, 1);
-                    }
-
-                    this._linkTrackers(this._lastBoundInternalTextureTracker.previous, texture);
-                    this._linkTrackers(texture, this._lastBoundInternalTextureTracker);
-                }
-
-                texture._designatedSlot = this._activeChannel;
+                texture._associatedChannel = this._activeChannel;
             }
         } else if (forTextureDataUpdate) {
             wasPreviouslyBound = true;
@@ -6520,7 +6406,7 @@ export class Engine {
         }
 
         if (isTextureForRendering && !forTextureDataUpdate) {
-            this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
+            this._bindSamplerUniformToChannel(texture!._associatedChannel, this._activeChannel);
         }
 
         return wasPreviouslyBound;
@@ -6533,7 +6419,7 @@ export class Engine {
         }
 
         if (texture) {
-            channel = this._getCorrectTextureChannel(channel, texture);
+            texture._associatedChannel = channel;
         }
 
         this._activeChannel = channel;
@@ -6674,15 +6560,14 @@ export class Engine {
             internalTexture = this.emptyTexture;
         }
 
-        if (!isPartOfTextureArray) {
-            channel = this._getCorrectTextureChannel(channel, internalTexture);
+        if (!isPartOfTextureArray && internalTexture) {
+            internalTexture._associatedChannel = channel;
         }
 
         let needToBind = true;
         if (this._boundTexturesCache[channel] === internalTexture) {
-            this._moveBoundTextureOnTop(internalTexture);
             if (!isPartOfTextureArray) {
-                this._bindSamplerUniformToChannel(internalTexture._initialSlot, channel);
+                this._bindSamplerUniformToChannel(internalTexture._associatedChannel, channel);
             }
 
             needToBind = false;
@@ -6765,7 +6650,14 @@ export class Engine {
             this._textureUnits = new Int32Array(textures.length);
         }
         for (let i = 0; i < textures.length; i++) {
-            this._textureUnits[i] = this._getCorrectTextureChannel(channel + i, textures[i].getInternalTexture());
+            let texture = textures[i].getInternalTexture();
+
+            if (texture) {
+                this._textureUnits[channel + i] = channel + i;
+                texture._associatedChannel = channel + i;
+            } else {
+                this._textureUnits[channel + i] = -1;
+            }
         }
         this._gl.uniform1iv(uniform, this._textureUnits);
 

+ 0 - 8
src/Instrumentation/sceneInstrumentation.ts

@@ -459,13 +459,6 @@ export class SceneInstrumentation implements IDisposable {
     }
 
     /**
-     * Gets the perf counter used for texture collisions
-     */
-    public get textureCollisionsCounter(): PerfCounter {
-        return this.scene.getEngine()._textureCollisions;
-    }
-
-    /**
      * Instantiates a new scene instrumentation.
      * This class can be used to get instrumentation data from a Babylon engine
      * @see http://doc.babylonjs.com/how_to/optimizing_your_scene#sceneinstrumentation
@@ -508,7 +501,6 @@ export class SceneInstrumentation implements IDisposable {
             }
 
             this.scene.getEngine()._drawCalls.fetchNewFrame();
-            this.scene.getEngine()._textureCollisions.fetchNewFrame();
         });
 
         // After render

+ 0 - 1
src/Materials/Textures/index.ts

@@ -6,7 +6,6 @@ export * from "./equiRectangularCubeTexture";
 export * from "./hdrCubeTexture";
 export * from "./internalTexture";
 export * from "./internalTextureLoader";
-export * from "./internalTextureTracker";
 export * from "./Loaders/index";
 export * from "./mirrorTexture";
 export * from "./multiRenderTarget";

+ 3 - 17
src/Materials/Textures/internalTexture.ts

@@ -2,7 +2,6 @@ import { Observable } from "../../Misc/observable";
 import { Nullable, int } from "../../types";
 import { SphericalPolynomial } from "../../Maths/sphericalPolynomial";
 import { RenderTargetCreationOptions } from "../../Materials/Textures/renderTargetCreationOptions";
-import { IInternalTextureTracker } from "../../Materials/Textures/internalTextureTracker";
 import { _TimeToken } from "../../Instrumentation/timeToken";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
 import { Constants } from "../../Engines/constants";
@@ -15,7 +14,7 @@ declare type BaseTexture = import("../../Materials/Textures/baseTexture").BaseTe
  * Class used to store data associated with WebGL texture data for the engine
  * This class should not be used directly
  */
-export class InternalTexture implements IInternalTextureTracker {
+export class InternalTexture {
 
     /** hidden */
     public static _UpdateRGBDAsync = (internalTexture: InternalTexture, data: ArrayBufferView[][], sphericalPolynomial: Nullable<SphericalPolynomial>, lodScale: number, lodOffset: number): Promise<void> => {
@@ -148,22 +147,11 @@ export class InternalTexture implements IInternalTextureTracker {
      */
     public invertY: boolean;
 
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    public previous: Nullable<IInternalTextureTracker> = null;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    public next: Nullable<IInternalTextureTracker> = null;
-
     // Private
     /** @hidden */
     public _invertVScale = false;
     /** @hidden */
-    public _initialSlot = -1;
-    /** @hidden */
-    public _designatedSlot = -1;
+    public _associatedChannel = -1;
     /** @hidden */
     public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
     /** @hidden */
@@ -225,7 +213,7 @@ export class InternalTexture implements IInternalTextureTracker {
     /** @hidden */
     public _colorTextureArray: Nullable<WebGLTexture>;
     /** @hidden */
-    public _depthStencilTextureArray:  Nullable<WebGLTexture>;
+    public _depthStencilTextureArray: Nullable<WebGLTexture>;
 
     // The following three fields helps sharing generated fixed LODs for texture filtering
     // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
@@ -468,8 +456,6 @@ export class InternalTexture implements IInternalTextureTracker {
         if (this._references === 0) {
             this._engine._releaseTexture(this);
             this._webGLTexture = null;
-            this.previous = null;
-            this.next = null;
         }
     }
 }

+ 0 - 30
src/Materials/Textures/internalTextureTracker.ts

@@ -1,30 +0,0 @@
-import { Nullable } from "../../types";
-import { _TimeToken } from "../../Instrumentation/timeToken";
-import { _DepthCullingState, _StencilState, _AlphaState } from "../../States/index";
-/**
- * Internal interface used to track InternalTexture already bound to the GL context
- */
-export interface IInternalTextureTracker {
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    previous: Nullable<IInternalTextureTracker>;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    next: Nullable<IInternalTextureTracker>;
-}
-
-/**
- * Internal class used by the engine to get list of InternalTexture already bound to the GL context
- */
-export class DummyInternalTextureTracker {
-    /**
-     * Gets or set the previous tracker in the list
-     */
-    public previous: Nullable<IInternalTextureTracker> = null;
-    /**
-     * Gets or set the next tracker in the list
-     */
-    public next: Nullable<IInternalTextureTracker> = null;
-}

+ 21 - 0
src/Maths/math.ts

@@ -5477,6 +5477,27 @@ export class Matrix {
     }
 
     /**
+     * Takes normalised vectors and returns a rotation matrix to align "from" with "to".
+     * Taken from http://www.iquilezles.org/www/articles/noacos/noacos.htm
+     * @param from defines the vector to align
+     * @param to defines the vector to align to
+     * @param result defines the target matrix
+     */
+    public static RotationAlignToRef(from: DeepImmutable<Vector3>, to: DeepImmutable<Vector3>, result: Matrix): void {
+        const v = Vector3.Cross(to, from);
+        const c = Vector3.Dot(to, from);
+        const k = 1 / (1 + c);
+
+        const m = result._m;
+        m[0]  = v.x * v.x * k + c;   m[1]  = v.y * v.x * k - v.z; m[2]  = v.z * v.x * k + v.y; m[3]  = 0;
+        m[4]  = v.x * v.y * k + v.z; m[5]  = v.y * v.y * k + c;   m[6]  = v.z * v.y * k - v.x; m[7]  = 0;
+        m[8]  = v.x * v.z * k - v.y; m[9]  = v.y * v.z * k + v.x; m[10] = v.z * v.z * k + c;   m[11] = 0;
+        m[12] = 0;               m[13] = 0;               m[14] = 0;               m[15] = 1;
+
+        result._markAsUpdated();
+    }
+
+    /**
      * Creates a rotation matrix
      * @param yaw defines the yaw angle in radians (Y axis)
      * @param pitch defines the pitch angle in radians (X axis)

+ 237 - 122
src/Meshes/Compression/dracoCompression.ts

@@ -1,4 +1,5 @@
 import { Tools } from "../../Misc/tools";
+import { WorkerPool } from '../../Misc/workerPool';
 import { Nullable } from "../../types";
 import { IDisposable } from "../../scene";
 import { VertexData } from "../../Meshes/mesh.vertexData";
@@ -6,6 +7,8 @@ import { VertexData } from "../../Meshes/mesh.vertexData";
 declare var DracoDecoderModule: any;
 declare var WebAssembly: any;
 
+declare function importScripts(...urls: string[]): void;
+
 /**
  * Configuration for Draco compression
  */
@@ -70,7 +73,7 @@ export interface IDracoCompressionConfiguration {
  * @see https://www.babylonjs-playground.com/#N3EK4B#0
  */
 export class DracoCompression implements IDisposable {
-    private static _DecoderModulePromise: Promise<any>;
+    private _workerPoolPromise: Promise<WorkerPool>;
 
     /**
      * The configuration. Defaults to the following urls:
@@ -109,18 +112,94 @@ export class DracoCompression implements IDisposable {
     }
 
     /**
+     * Default number of workers to create when creating the draco compression object.
+     */
+    public static DefaultNumWorkers = DracoCompression.GetDefaultNumWorkers();
+
+    private static GetDefaultNumWorkers(): number {
+        const hardwareConcurrency = navigator && navigator.hardwareConcurrency;
+        if (!hardwareConcurrency) {
+            return 1;
+        }
+
+        // Use 50% of the available logical processors but capped at 4.
+        return Math.min(Math.floor(hardwareConcurrency * 0.5), 4);
+    }
+
+    /**
      * Constructor
+     * @param numWorkers The number of workers for async operations
      */
-    constructor() {
+    constructor(numWorkers = DracoCompression.DefaultNumWorkers) {
+        if (!URL || !URL.createObjectURL) {
+            throw new Error("Object URLs are not available");
+        }
+
+        if (!Worker) {
+            throw new Error("Workers are not available");
+        }
+
+        this._workerPoolPromise = this._loadDecoderWasmBinaryAsync().then((decoderWasmBinary) => {
+            const workerBlobUrl = URL.createObjectURL(new Blob([`(${DracoCompression._Worker.toString()})()`], { type: "application/javascript" }));
+            const workerPromises = new Array<Promise<Worker>>(numWorkers);
+            for (let i = 0; i < workerPromises.length; i++) {
+                workerPromises[i] = new Promise((resolve, reject) => {
+                    const decoder = DracoCompression.Configuration.decoder;
+                    if (decoder) {
+                        const worker = new Worker(workerBlobUrl);
+                        const onError = (error: ErrorEvent) => {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            reject(error);
+                        };
+
+                        const onMessage = (message: MessageEvent) => {
+                            if (message.data === "done") {
+                                worker.removeEventListener("error", onError);
+                                worker.removeEventListener("message", onMessage);
+                                resolve(worker);
+                            }
+                        };
+
+                        worker.addEventListener("error", onError);
+                        worker.addEventListener("message", onMessage);
+
+                        worker.postMessage({
+                            id: "initDecoder",
+                            decoderWasmUrl: decoder.wasmUrl ? Tools.GetAbsoluteUrl(decoder.wasmUrl) : null,
+                            decoderWasmBinary: decoderWasmBinary,
+                            fallbackUrl: decoder.fallbackUrl ? Tools.GetAbsoluteUrl(decoder.fallbackUrl) : null
+                        });
+                    }
+                });
+            }
+
+            return Promise.all(workerPromises).then((workers) => {
+                return new WorkerPool(workers);
+            });
+        });
     }
 
     /**
      * Stop all async operations and release resources.
      */
     public dispose(): void {
+        this._workerPoolPromise.then((workerPool) => {
+            workerPool.dispose();
+        });
+
+        delete this._workerPoolPromise;
     }
 
     /**
+     * Returns a promise that resolves when ready. Call this manually to ensure draco compression is ready before use.
+     * @returns a promise that resolves when ready
+     */
+    public whenReadyAsync(): Promise<void> {
+        return this._workerPoolPromise.then(() => { });
+    }
+
+   /**
      * Decode Draco compressed mesh data to vertex data.
      * @param data The ArrayBuffer or ArrayBufferView for the Draco compression data
      * @param attributes A map of attributes from vertex buffer kinds to Draco unique ids
@@ -129,148 +208,184 @@ export class DracoCompression implements IDisposable {
     public decodeMeshAsync(data: ArrayBuffer | ArrayBufferView, attributes: { [kind: string]: number }): Promise<VertexData> {
         const dataView = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
 
-        return DracoCompression._GetDecoderModule().then((wrappedModule) => {
-            const module = wrappedModule.module;
-            const vertexData = new VertexData();
-
-            const buffer = new module.DecoderBuffer();
-            buffer.Init(dataView, dataView.byteLength);
-
-            const decoder = new module.Decoder();
-            let geometry: any;
-            let status: any;
-
-            try {
-                const type = decoder.GetEncodedGeometryType(buffer);
-                switch (type) {
-                    case module.TRIANGULAR_MESH:
-                        geometry = new module.Mesh();
-                        status = decoder.DecodeBufferToMesh(buffer, geometry);
-                        break;
-                    case module.POINT_CLOUD:
-                        geometry = new module.PointCloud();
-                        status = decoder.DecodeBufferToPointCloud(buffer, geometry);
-                        break;
-                    default:
-                        throw new Error(`Invalid geometry type ${type}`);
-                }
+        return this._workerPoolPromise.then((workerPool) => {
+            return new Promise<VertexData>((resolve, reject) => {
+                workerPool.push((worker, onComplete) => {
+                    const vertexData = new VertexData();
 
-                if (!status.ok() || !geometry.ptr) {
-                    throw new Error(status.error_msg());
-                }
+                    const onError = (error: ErrorEvent) => {
+                        worker.removeEventListener("error", onError);
+                        worker.removeEventListener("message", onMessage);
+                        reject(error);
+                        onComplete();
+                    };
 
-                const numPoints = geometry.num_points();
-
-                if (type === module.TRIANGULAR_MESH) {
-                    const numFaces = geometry.num_faces();
-                    const faceIndices = new module.DracoInt32Array();
-                    try {
-                        const indices = new Uint32Array(numFaces * 3);
-                        for (let i = 0; i < numFaces; i++) {
-                            decoder.GetFaceFromMesh(geometry, i, faceIndices);
-                            const offset = i * 3;
-                            indices[offset + 0] = faceIndices.GetValue(0);
-                            indices[offset + 1] = faceIndices.GetValue(1);
-                            indices[offset + 2] = faceIndices.GetValue(2);
+                    const onMessage = (message: MessageEvent) => {
+                        if (message.data === "done") {
+                            worker.removeEventListener("error", onError);
+                            worker.removeEventListener("message", onMessage);
+                            resolve(vertexData);
+                            onComplete();
                         }
-                        vertexData.indices = indices;
-                    }
-                    finally {
-                        module.destroy(faceIndices);
-                    }
-                }
-
-                for (const kind in attributes) {
-                    const uniqueId = attributes[kind];
-                    const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
-                    const dracoData = new module.DracoFloat32Array();
-                    try {
-                        decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
-                        const babylonData = new Float32Array(numPoints * attribute.num_components());
-                        for (let i = 0; i < babylonData.length; i++) {
-                            babylonData[i] = dracoData.GetValue(i);
+                        else if (message.data.id === "indices") {
+                            vertexData.indices = message.data.value;
                         }
-                        vertexData.set(babylonData, kind);
-                    }
-                    finally {
-                        module.destroy(dracoData);
-                    }
-                }
-            }
-            finally {
-                if (geometry) {
-                    module.destroy(geometry);
-                }
+                        else {
+                            vertexData.set(message.data.value, message.data.id);
+                        }
+                    };
 
-                module.destroy(decoder);
-                module.destroy(buffer);
-            }
+                    worker.addEventListener("error", onError);
+                    worker.addEventListener("message", onMessage);
+
+                    const dataViewCopy = new Uint8Array(dataView.byteLength);
+                    dataViewCopy.set(new Uint8Array(dataView.buffer, dataView.byteOffset, dataView.byteLength));
 
-            return vertexData;
+                    worker.postMessage({ id: "decodeMesh", dataView: dataViewCopy, attributes: attributes }, [dataViewCopy.buffer]);
+                });
+            });
         });
     }
 
-    private static _GetDecoderModule(): Promise<any> {
-        if (!DracoCompression._DecoderModulePromise) {
-            let promise: Nullable<Promise<any>> = null;
-            let config: any = {};
+    /**
+     * The worker function that gets converted to a blob url to pass into a worker.
+     */
+    private static _Worker(): void {
+        // self is actually a DedicatedWorkerGlobalScope
+        const _self = self as any as {
+            onmessage: (event: MessageEvent) => void;
+            postMessage: (message: any, transfer?: any[]) => void;
+            close: () => void;
+        };
+
+        let decoderModulePromise: Promise<any>;
 
-            if (typeof DracoDecoderModule !== "undefined") {
-                promise = Promise.resolve();
+        function initDecoder(decoderWasmUrl: string | undefined, decoderWasmBinary: ArrayBuffer | undefined, fallbackUrl: string | undefined): void {
+            if (decoderWasmUrl && decoderWasmBinary && typeof WebAssembly === "object") {
+                importScripts(decoderWasmUrl);
+                decoderModulePromise = DracoDecoderModule({
+                    wasmBinary: decoderWasmBinary
+                });
+            }
+            else if (fallbackUrl) {
+                importScripts(fallbackUrl);
+                decoderModulePromise = DracoDecoderModule();
             }
             else {
-                const decoder = DracoCompression.Configuration.decoder;
-                if (decoder) {
-                    if (decoder.wasmUrl && decoder.wasmBinaryUrl && typeof WebAssembly === "object") {
-                        promise = Promise.all([
-                            DracoCompression._LoadScriptAsync(decoder.wasmUrl),
-                            DracoCompression._LoadFileAsync(decoder.wasmBinaryUrl).then((data) => {
-                                config.wasmBinary = data;
-                            })
-                        ]);
+                throw Error("Failed to initialize Draco decoder");
+            }
+
+            _self.postMessage("done");
+        }
+
+        function decodeMesh(dataView: ArrayBufferView, attributes: { [kind: string]: number }): void {
+            decoderModulePromise.then((decoderModule) => {
+                const buffer = new decoderModule.DecoderBuffer();
+                buffer.Init(dataView, dataView.byteLength);
+
+                const decoder = new decoderModule.Decoder();
+                let geometry: any;
+                let status: any;
+
+                try {
+                    const type = decoder.GetEncodedGeometryType(buffer);
+                    switch (type) {
+                        case decoderModule.TRIANGULAR_MESH:
+                            geometry = new decoderModule.Mesh();
+                            status = decoder.DecodeBufferToMesh(buffer, geometry);
+                            break;
+                        case decoderModule.POINT_CLOUD:
+                            geometry = new decoderModule.PointCloud();
+                            status = decoder.DecodeBufferToPointCloud(buffer, geometry);
+                            break;
+                        default:
+                            throw new Error(`Invalid geometry type ${type}`);
                     }
-                    else if (decoder.fallbackUrl) {
-                        promise = DracoCompression._LoadScriptAsync(decoder.fallbackUrl);
+
+                    if (!status.ok() || !geometry.ptr) {
+                        throw new Error(status.error_msg());
                     }
-                }
-            }
 
-            if (!promise) {
-                throw new Error("Draco decoder module is not available");
-            }
+                    const numPoints = geometry.num_points();
 
-            DracoCompression._DecoderModulePromise = promise.then(() => {
-                return new Promise((resolve) => {
-                    config.onModuleLoaded = (decoderModule: any) => {
-                        // decoderModule is Promise-like. Wrap before resolving to avoid loop.
-                        resolve({ module: decoderModule });
-                    };
+                    if (type === decoderModule.TRIANGULAR_MESH) {
+                        const numFaces = geometry.num_faces();
+                        const faceIndices = new decoderModule.DracoInt32Array();
+                        try {
+                            const indices = new Uint32Array(numFaces * 3);
+                            for (let i = 0; i < numFaces; i++) {
+                                decoder.GetFaceFromMesh(geometry, i, faceIndices);
+                                const 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]);
+                        }
+                        finally {
+                            decoderModule.destroy(faceIndices);
+                        }
+                    }
 
-                    DracoDecoderModule(config);
-                });
-            });
-        }
+                    for (const kind in attributes) {
+                        const uniqueId = attributes[kind];
+                        const attribute = decoder.GetAttributeByUniqueId(geometry, uniqueId);
+                        const dracoData = new decoderModule.DracoFloat32Array();
+                        try {
+                            decoder.GetAttributeFloatForAllPoints(geometry, attribute, dracoData);
+                            const babylonData = new Float32Array(numPoints * attribute.num_components());
+                            for (let i = 0; i < babylonData.length; i++) {
+                                babylonData[i] = dracoData.GetValue(i);
+                            }
+                            _self.postMessage({ id: kind, value: babylonData }, [babylonData.buffer]);
+                        }
+                        finally {
+                            decoderModule.destroy(dracoData);
+                        }
+                    }
+                }
+                finally {
+                    if (geometry) {
+                        decoderModule.destroy(geometry);
+                    }
 
-        return DracoCompression._DecoderModulePromise;
-    }
+                    decoderModule.destroy(decoder);
+                    decoderModule.destroy(buffer);
+                }
 
-    private static _LoadScriptAsync(url: string): Promise<void> {
-        return new Promise((resolve, reject) => {
-            Tools.LoadScript(url, () => {
-                resolve();
-            }, (message) => {
-                reject(new Error(message));
+                _self.postMessage("done");
             });
-        });
+        }
+
+        _self.onmessage = (event) => {
+            const data = event.data;
+            switch (data.id) {
+                case "initDecoder": {
+                    initDecoder(data.decoderWasmUrl, data.decoderWasmBinary, data.fallbackUrl);
+                    break;
+                }
+                case "decodeMesh": {
+                    decodeMesh(data.dataView, data.attributes);
+                    break;
+                }
+            }
+        };
     }
 
-    private static _LoadFileAsync(url: string): Promise<ArrayBuffer> {
-        return new Promise((resolve, reject) => {
-            Tools.LoadFile(url, (data) => {
-                resolve(data as ArrayBuffer);
-            }, undefined, undefined, true, (request, exception) => {
-                reject(exception);
+    private _loadDecoderWasmBinaryAsync(): Promise<Nullable<ArrayBuffer>> {
+        const decoder = DracoCompression.Configuration.decoder;
+        if (decoder && decoder.wasmUrl && decoder.wasmBinaryUrl && typeof WebAssembly === "object") {
+            const wasmBinaryUrl = Tools.GetAbsoluteUrl(decoder.wasmBinaryUrl);
+            return new Promise((resolve, reject) => {
+                Tools.LoadFile(wasmBinaryUrl, (data) => {
+                    resolve(data as ArrayBuffer);
+                }, undefined, undefined, true, (request, exception) => {
+                    reject(exception);
+                });
             });
-        });
+        }
+        else {
+            return Promise.resolve(null);
+        }
     }
 }

+ 8 - 0
src/Meshes/abstractMesh.ts

@@ -487,6 +487,11 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
     public alwaysSelectAsActiveMesh = false;
 
     /**
+     * Gets or sets a boolean indicating that the bounding info does not need to be kept in sync (for performance reason)
+     */
+    public doNotSyncBoundingInfo = false;
+
+    /**
      * Gets or sets the current action manager
      * @see http://doc.babylonjs.com/how_to/how_to_use_actions
      */
@@ -1284,6 +1289,9 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
 
     /** @hidden */
     protected _afterComputeWorldMatrix(): void {
+        if (this.doNotSyncBoundingInfo) {
+            return;
+        }
         // Bounding info
         this._updateBoundingInfo();
     }

+ 16 - 15
src/Meshes/transformNode.ts

@@ -186,6 +186,7 @@ export class TransformNode extends Node {
         if (quaternion) {
             this.rotation.setAll(0.0);
         }
+        this._isDirty = true;
     }
 
     /**
@@ -879,8 +880,8 @@ export class TransformNode extends Node {
         }
 
         this._updateCache();
-        this._cache.position.copyFrom(this.position);
-        this._cache.scaling.copyFrom(this.scaling);
+        this._cache.position.copyFrom(this._position);
+        this._cache.scaling.copyFrom(this._scaling);
         this._cache.pivotMatrixUpdated = false;
         this._cache.billboardMode = this.billboardMode;
         this._cache.infiniteDistance = this.infiniteDistance;
@@ -890,25 +891,25 @@ export class TransformNode extends Node {
         let parent = this._getEffectiveParent();
 
         // Scaling
-        Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
+        Matrix.ScalingToRef(this._scaling.x * this.scalingDeterminant, this._scaling.y * this.scalingDeterminant, this._scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
 
         // Rotation
 
         //rotate, if quaternion is set and rotation was used
-        if (this.rotationQuaternion) {
+        if (this._rotationQuaternion) {
             var len = this.rotation.length();
             if (len) {
-                this.rotationQuaternion.multiplyInPlace(Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z));
-                this.rotation.copyFromFloats(0, 0, 0);
+                this._rotationQuaternion.multiplyInPlace(Quaternion.RotationYawPitchRoll(this._rotation.y, this._rotation.x, this._rotation.z));
+                this._rotation.copyFromFloats(0, 0, 0);
             }
         }
 
-        if (this.rotationQuaternion) {
-            this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
-            this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
+        if (this._rotationQuaternion) {
+            this._rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
+            this._cache.rotationQuaternion.copyFrom(this._rotationQuaternion);
         } else {
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
-            this._cache.rotation.copyFrom(this.rotation);
+            Matrix.RotationYawPitchRollToRef(this._rotation.y, this._rotation.x, this._rotation.z, Tmp.Matrix[0]);
+            this._cache.rotation.copyFrom(this._rotation);
         }
 
         // Translation
@@ -920,10 +921,10 @@ export class TransformNode extends Node {
 
             var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
 
-            Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
-                this.position.z + cameraGlobalPosition.z, this._tempMatrix2);
+            Matrix.TranslationToRef(this._position.x + cameraGlobalPosition.x, this._position.y + cameraGlobalPosition.y,
+                this._position.z + cameraGlobalPosition.z, this._tempMatrix2);
         } else {
-            Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._tempMatrix2);
+            Matrix.TranslationToRef(this._position.x, this._position.y, this._position.z, this._tempMatrix2);
         }
 
         // Composing transformations
@@ -1008,7 +1009,7 @@ export class TransformNode extends Node {
 
         // Normal matrix
         if (!this.ignoreNonUniformScaling) {
-            if (this.scaling.isNonUniform) {
+            if (this._scaling.isNonUniform) {
                 this._updateNonUniformScalingState(true);
             } else if (parent && (<TransformNode>parent)._nonUniformScaling) {
                 this._updateNonUniformScalingState((<TransformNode>parent)._nonUniformScaling);

+ 2 - 1
src/Misc/dds.ts

@@ -533,7 +533,8 @@ export class DDSTools {
             mipmapCount = Math.max(1, header[off_mipmapCount]);
         }
 
-        for (var face = 0; face < faces; face++) {
+        const startFace = currentFace || 0;
+        for (var face = startFace; face < faces; face++) {
             width = header[off_width];
             height = header[off_height];
 

+ 11 - 0
src/Misc/tools.ts

@@ -1462,6 +1462,17 @@ export class Tools {
         return bufferView.buffer;
     }
 
+    /**
+     * Gets the absolute url.
+     * @param url the input url
+     * @return the absolute url
+     */
+    public static GetAbsoluteUrl(url: string): string {
+        const a = document.createElement("a");
+        a.href = url;
+        return a.href;
+    }
+
     // Logs
     /**
      * No log

+ 3 - 0
src/Physics/Plugins/ammoJSPlugin.ts

@@ -856,6 +856,9 @@ export class AmmoJSPlugin implements IPhysicsEnginePlugin {
             meshChildren.forEach((childMesh) => {
                 var childImpostor = childMesh.getPhysicsImpostor();
                 if (childImpostor) {
+                    if (childImpostor.type == PhysicsImpostor.MeshImpostor) {
+                        throw "A child MeshImpostor is not supported. Only primitive impostors are supported as children (eg. box or sphere)";
+                    }
                     var shape = this._createShape(childImpostor);
 
                     // Position needs to be scaled based on parent's scaling