소스 검색

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into ktx2-light

Popov72 5 년 전
부모
커밋
853405042d
100개의 변경된 파일5758개의 추가작업 그리고 1776개의 파일을 삭제
  1. 1 1
      Playground/src/components/commandBarComponent.tsx
  2. 1 1
      Playground/src/components/hamburgerMenu.tsx
  3. 6 5
      Playground/src/components/rendererComponent.tsx
  4. 2 1
      Playground/src/globalState.ts
  5. 412 99
      dist/preview release/babylon.d.ts
  6. 2 2
      dist/preview release/babylon.js
  7. 1445 432
      dist/preview release/babylon.max.js
  8. 1 1
      dist/preview release/babylon.max.js.map
  9. 868 208
      dist/preview release/babylon.module.d.ts
  10. 435 106
      dist/preview release/documentation.d.ts
  11. 1 1
      dist/preview release/glTF2Interface/package.json
  12. 20 4
      dist/preview release/gui/babylon.gui.d.ts
  13. 100 59
      dist/preview release/gui/babylon.gui.js
  14. 1 1
      dist/preview release/gui/babylon.gui.js.map
  15. 2 2
      dist/preview release/gui/babylon.gui.min.js
  16. 40 8
      dist/preview release/gui/babylon.gui.module.d.ts
  17. 2 2
      dist/preview release/gui/package.json
  18. 5 5
      dist/preview release/inspector/babylon.inspector.bundle.js
  19. 181 32
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  20. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  21. 6 0
      dist/preview release/inspector/babylon.inspector.d.ts
  22. 15 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  23. 7 7
      dist/preview release/inspector/package.json
  24. 10 25
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  25. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  26. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  27. 10 25
      dist/preview release/loaders/babylon.glTFFileLoader.js
  28. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  29. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  30. 3 3
      dist/preview release/loaders/babylonjs.loaders.d.ts
  31. 10 25
      dist/preview release/loaders/babylonjs.loaders.js
  32. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  33. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  34. 6 6
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  35. 3 3
      dist/preview release/loaders/package.json
  36. 2 2
      dist/preview release/materialsLibrary/package.json
  37. 2 2
      dist/preview release/nodeEditor/package.json
  38. 1 1
      dist/preview release/package.json
  39. 1 1
      dist/preview release/packagesSizeBaseLine.json
  40. 2 2
      dist/preview release/postProcessesLibrary/package.json
  41. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  42. 3 3
      dist/preview release/serializers/package.json
  43. 868 208
      dist/preview release/viewer/babylon.module.d.ts
  44. 122 110
      dist/preview release/viewer/babylon.viewer.js
  45. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  46. 6 6
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  47. 7 1
      dist/preview release/what's new.md
  48. 1 0
      dist/what's new.md
  49. 14 0
      gui/src/2D/advancedDynamicTexture.ts
  50. 5 0
      gui/src/2D/controls/colorpicker.ts
  51. 9 1
      gui/src/2D/controls/control.ts
  52. 6 0
      gui/src/2D/controls/sliders/baseSlider.ts
  53. 2 2
      gui/src/2D/controls/textBlock.ts
  54. 22 5
      gui/src/2D/measure.ts
  55. 193 145
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/skeletonPropertyGridComponent.tsx
  56. 21 0
      inspector/src/components/globalState.ts
  57. 24 5
      inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx
  58. 82 23
      inspector/src/components/sceneExplorer/entities/sceneTreeItemComponent.tsx
  59. 6 2
      inspector/src/components/sceneExplorer/sceneExplorer.scss
  60. 3 3
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  61. 1 1
      inspector/src/components/sceneExplorer/treeItemSpecializedComponent.tsx
  62. 5 0
      inspector/src/inspector.ts
  63. 1 1
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  64. 12 33
      loaders/src/glTF/2.0/glTFLoader.ts
  65. 1 1
      loaders/src/glTF/2.0/glTFLoaderExtension.ts
  66. 1 1
      package.json
  67. 3 0
      src/Animations/animationGroup.ts
  68. 2 1
      src/Cameras/Inputs/freeCameraTouchInput.ts
  69. 18 12
      src/Debug/rayHelper.ts
  70. 18 0
      src/Debug/skeletonViewer.ts
  71. 11 5
      src/DeviceInput/deviceInputSystem.ts
  72. 73 0
      src/Engines/Extensions/engine.dynamicBuffer.ts
  73. 1 0
      src/Engines/Extensions/index.ts
  74. 2 63
      src/Engines/engine.ts
  75. 6 3
      src/Engines/thinEngine.ts
  76. 193 0
      src/Gizmos/cameraGizmo.ts
  77. 72 10
      src/Gizmos/gizmoManager.ts
  78. 1 0
      src/Gizmos/index.ts
  79. 2 1
      src/LibDeclarations/webxr.d.ts
  80. 14 0
      src/Loading/Plugins/babylonFileLoader.ts
  81. 2 1
      src/Materials/Textures/rawTexture.ts
  82. 1 0
      src/Materials/index.ts
  83. 3 26
      src/Materials/materialHelper.ts
  84. 43 0
      src/Materials/thinMaterialHelper.ts
  85. 2 2
      src/Meshes/buffer.ts
  86. 14 0
      src/Meshes/instancedMesh.ts
  87. 37 0
      src/Misc/interfaces/iClipPlanesHolder.ts
  88. 6 2
      src/Misc/sceneRecorder.ts
  89. 6 0
      src/Misc/sceneSerializer.ts
  90. 6 4
      src/Particles/baseParticleSystem.ts
  91. 2 2
      src/Particles/gpuParticleSystem.ts
  92. 10 7
      src/Particles/particleSystem.ts
  93. 11 0
      src/PostProcesses/anaglyphPostProcess.ts
  94. 26 0
      src/PostProcesses/blackAndWhitePostProcess.ts
  95. 18 1
      src/PostProcesses/bloomMergePostProcess.ts
  96. 33 2
      src/PostProcesses/blurPostProcess.ts
  97. 43 0
      src/PostProcesses/chromaticAberrationPostProcess.ts
  98. 16 0
      src/PostProcesses/circleOfConfusionPostProcess.ts
  99. 34 0
      src/PostProcesses/colorCorrectionPostProcess.ts
  100. 0 0
      src/PostProcesses/convolutionPostProcess.ts

+ 1 - 1
Playground/src/components/commandBarComponent.tsx

@@ -39,7 +39,7 @@ export class CommandBarComponent extends React.Component<ICommandBarComponentPro
     }
 
     onInspector() {
-        this.props.globalState.onInspectorRequiredObservable.notifyObservers();
+        this.props.globalState.onInspectorRequiredObservable.notifyObservers(!this.props.globalState.inspectorIsOpened);
     }
 
     onExamples() {

+ 1 - 1
Playground/src/components/hamburgerMenu.tsx

@@ -43,7 +43,7 @@ export class HamburgerMenuComponent extends React.Component<IHamburgerMenuCompon
     }
 
     onInspector() {
-        this.props.globalState.onInspectorRequiredObservable.notifyObservers();
+        this.props.globalState.onInspectorRequiredObservable.notifyObservers(!this.props.globalState.inspectorIsOpened);
         this.setState({isExpanded: false});
     }
 

+ 6 - 5
Playground/src/components/rendererComponent.tsx

@@ -41,18 +41,19 @@ export class RenderingComponent extends React.Component<IRenderingComponentProps
             this._downloadManager.download(this._engine);
         });
 
-        this.props.globalState.onInspectorRequiredObservable.add(() => {
+        this.props.globalState.onInspectorRequiredObservable.add((state) => {
             if (!this._scene) {
                 return;
             }
 
-            if (this._scene.debugLayer.isVisible()) {
-                this._scene.debugLayer.hide();
-            } else {
+            if (state) {
                 this._scene.debugLayer.show({
                     embedMode: true,
                 });
+            } else {
+                this._scene.debugLayer.hide();
             }
+            this.props.globalState.inspectorIsOpened = state;
         });
 
         this.props.globalState.onFullcreenRequiredObservable.add(() => {
@@ -240,7 +241,7 @@ export class RenderingComponent extends React.Component<IRenderingComponentProps
             }
 
             if (this._engine.scenes[0] && displayInspector) {
-                this.props.globalState.onInspectorRequiredObservable.notifyObservers();
+                this.props.globalState.onInspectorRequiredObservable.notifyObservers(true);
             }
 
             if (checkCamera && this._engine.scenes[0].activeCamera == null) {

+ 2 - 1
Playground/src/globalState.ts

@@ -28,6 +28,7 @@ export class GlobalState {
     public mobileDefaultMode = EditionMode.RenderingOnly;
 
     public runtimeMode = RuntimeMode.Editor;
+    public inspectorIsOpened = false;
 
     public currentSnippetTitle = "";
     public currentSnippetDescription = "";
@@ -49,7 +50,7 @@ export class GlobalState {
     public onMetadataUpdatedObservable = new Observable<void>();
     public onMetadataWindowHiddenObservable = new Observable<boolean>();
     public onDownloadRequiredObservable = new Observable<void>();
-    public onInspectorRequiredObservable = new Observable<void>();
+    public onInspectorRequiredObservable = new Observable<boolean>();
     public onFormatCodeRequiredObservable = new Observable<void>();
     public onFullcreenRequiredObservable = new Observable<void>();
     public onEditorFullcreenRequiredObservable = new Observable<void>();

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 412 - 99
dist/preview release/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 2
dist/preview release/babylon.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1445 - 432
dist/preview release/babylon.max.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.max.js.map


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 868 - 208
dist/preview release/babylon.module.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 435 - 106
dist/preview release/documentation.d.ts


+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 20 - 4
dist/preview release/gui/babylon.gui.d.ts

@@ -281,14 +281,24 @@ declare module BABYLON.GUI {
         /**
          * Computes the axis aligned bounding box of the measure after it is modified by a given transform
          * @param transform the matrix to transform the measure before computing the AABB
+         * @param addX number to add to left
+         * @param addY number to add to top
+         * @param addWidth number to add to width
+         * @param addHeight number to add to height
          * @param result the resulting AABB
          */
-        transformToRef(transform: Matrix2D, result: Measure): void;
+        addAndTransformToRef(transform: Matrix2D, addX: number, addY: number, addWidth: number, addHeight: number, result: Measure): void;
         /**
-         * Check equality between this measure and another one
-         * @param other defines the other measures
-         * @returns true if both measures are equals
+         * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+         * @param transform the matrix to transform the measure before computing the AABB
+         * @param result the resulting AABB
          */
+        transformToRef(transform: Matrix2D, result: Measure): void;
+        /**
+     * Check equality between this measure and another one
+     * @param other defines the other measures
+     * @returns true if both measures are equals
+     */
         isEqualsTo(other: Measure): boolean;
         /**
          * Creates an empty measure
@@ -333,6 +343,7 @@ declare module BABYLON.GUI {
         private _pointerMoveObserver;
         private _pointerObserver;
         private _canvasPointerOutObserver;
+        private _canvasBlurObserver;
         private _background;
         /** @hidden */
         _rootContainer: Container;
@@ -600,6 +611,7 @@ declare module BABYLON.GUI {
         moveFocusToControl(control: IFocusableControl): void;
         private _manageFocus;
         private _attachToOnPointerOut;
+        private _attachToOnBlur;
         /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
@@ -1209,6 +1221,8 @@ declare module BABYLON.GUI {
         /** @hidden */
         _onWheelScroll(deltaX?: number, deltaY?: number): void;
         /** @hidden */
+        _onCanvasBlur(): void;
+        /** @hidden */
         _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
         /** Releases associated resources */
@@ -2324,6 +2338,7 @@ declare module BABYLON.GUI {
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
         /**
          * This function expands the color picker by creating a color picker dialog with manual
          * color value input and the ability to save colors into an array to be used later in
@@ -2670,6 +2685,7 @@ declare module BABYLON.GUI {
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
     }
 }
 declare module BABYLON.GUI {

+ 100 - 59
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_perfCounter__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -400,7 +400,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_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -543,7 +543,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -1061,6 +1061,9 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
         if (this._canvasPointerOutObserver) {
             scene.getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
         }
+        if (this._canvasBlurObserver) {
+            scene.getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+        }
         if (this._layerToDispose) {
             this._layerToDispose.texture = null;
             this._layerToDispose.dispose();
@@ -1315,6 +1318,7 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
             }
         });
         this._attachToOnPointerOut(scene);
+        this._attachToOnBlur(scene);
     };
     /**
     * Register the clipboard Events onto the canvas
@@ -1395,6 +1399,7 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
         });
         mesh.enablePointerMoveEvents = supportPointerMove;
         this._attachToOnPointerOut(scene);
+        this._attachToOnBlur(scene);
     };
     /**
     * Move the focus to a specific control
@@ -1434,6 +1439,16 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
             }
         });
     };
+    AdvancedDynamicTexture.prototype._attachToOnBlur = function (scene) {
+        var _this = this;
+        this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(function (pointerEvent) {
+            Object.entries(_this._lastControlDown).forEach(function (_a) {
+                var key = _a[0], value = _a[1];
+                value._onCanvasBlur();
+            });
+            _this._lastControlDown = {};
+        });
+    };
     // Statics
     /**
      * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
@@ -1515,7 +1530,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
@@ -1747,7 +1762,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__["_TypeStore"].RegisteredTy
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -1930,7 +1945,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -2293,6 +2308,10 @@ var ColorPicker = /** @class */ (function (_super) {
         delete this._host._capturingControl[pointerId];
         _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
     };
+    ColorPicker.prototype._onCanvasBlur = function () {
+        this._forcePointerUp();
+        _super.prototype._onCanvasBlur.call(this);
+    };
     /**
      * This function expands the color picker by creating a color picker dialog with manual
      * color value input and the ability to save colors into an array to be used later in
@@ -3319,7 +3338,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -3734,7 +3753,7 @@ babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredTypes
 "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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -5091,7 +5110,7 @@ var Control = /** @class */ (function () {
         }
         if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
             this.host._numLayoutCalls++;
-            this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
+            this._currentMeasure.addAndTransformToRef(this._transformMatrix, -this.paddingLeftInPixels | 0, -this.paddingTopInPixels | 0, this.paddingRightInPixels | 0, this.paddingBottomInPixels | 0, this._prevCurrentMeasureTransformedIntoGlobalSpace);
             context.save();
             this._applyStates(context);
             var rebuildCount = 0;
@@ -5467,6 +5486,8 @@ var Control = /** @class */ (function () {
         }
     };
     /** @hidden */
+    Control.prototype._onCanvasBlur = function () { };
+    /** @hidden */
     Control.prototype._processObservables = function (type, x, y, pointerId, buttonIndex, deltaX, deltaY) {
         if (!this._isEnabled) {
             return false;
@@ -5680,7 +5701,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -5913,7 +5934,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -6010,7 +6031,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* 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");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
@@ -6468,7 +6489,7 @@ babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__["_TypeStore"].RegisteredTypes[
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -7403,7 +7424,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -7442,7 +7463,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -8455,7 +8476,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __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_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__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");
@@ -8726,7 +8747,7 @@ babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registere
 __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/perfCounter");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -8996,7 +9017,7 @@ babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registe
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -9203,7 +9224,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -9353,7 +9374,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
@@ -10976,7 +10997,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -11286,6 +11307,10 @@ var BaseSlider = /** @class */ (function (_super) {
         delete this._host._capturingControl[pointerId];
         _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
     };
+    BaseSlider.prototype._onCanvasBlur = function () {
+        this._forcePointerUp();
+        _super.prototype._onCanvasBlur.call(this);
+    };
     return BaseSlider;
 }(_control__WEBPACK_IMPORTED_MODULE_2__["Control"]));
 
@@ -11306,7 +11331,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -11899,7 +11924,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -12154,7 +12179,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -12422,7 +12447,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -12679,13 +12704,13 @@ var TextBlock = /** @class */ (function (_super) {
         }
         if (this._resizeToFit) {
             if (this._textWrapping === TextWrapping.Clip) {
-                var newWidth = this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth;
+                var newWidth = (this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth) | 0;
                 if (newWidth !== this._width.internalValue) {
                     this._width.updateInPlace(newWidth, _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__["ValueAndUnit"].UNITMODE_PIXEL);
                     this._rebuildLayout = true;
                 }
             }
-            var newHeight = this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length;
+            var newHeight = (this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length) | 0;
             if (this._lines.length > 0 && this._lineSpacing.internalValue !== 0) {
                 var lineSpacing = 0;
                 if (this._lineSpacing.isPixel) {
@@ -12885,7 +12910,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -13274,7 +13299,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_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -13499,7 +13524,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_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 var tmpRect = [
@@ -13583,13 +13608,21 @@ var Measure = /** @class */ (function () {
     /**
      * Computes the axis aligned bounding box of the measure after it is modified by a given transform
      * @param transform the matrix to transform the measure before computing the AABB
+     * @param addX number to add to left
+     * @param addY number to add to top
+     * @param addWidth number to add to width
+     * @param addHeight number to add to height
      * @param result the resulting AABB
      */
-    Measure.prototype.transformToRef = function (transform, result) {
-        tmpRect[0].copyFromFloats(this.left, this.top);
-        tmpRect[1].copyFromFloats(this.left + this.width, this.top);
-        tmpRect[2].copyFromFloats(this.left + this.width, this.top + this.height);
-        tmpRect[3].copyFromFloats(this.left, this.top + this.height);
+    Measure.prototype.addAndTransformToRef = function (transform, addX, addY, addWidth, addHeight, result) {
+        var left = this.left + addX;
+        var top = this.top + addY;
+        var width = this.width + addWidth;
+        var height = this.height + addHeight;
+        tmpRect[0].copyFromFloats(left, top);
+        tmpRect[1].copyFromFloats(left + width, top);
+        tmpRect[2].copyFromFloats(left + width, top + height);
+        tmpRect[3].copyFromFloats(left, top + height);
         tmpV1.copyFromFloats(Number.MAX_VALUE, Number.MAX_VALUE);
         tmpV2.copyFromFloats(0, 0);
         for (var i = 0; i < 4; i++) {
@@ -13605,10 +13638,18 @@ var Measure = /** @class */ (function () {
         result.height = tmpV2.y - tmpV1.y;
     };
     /**
-     * Check equality between this measure and another one
-     * @param other defines the other measures
-     * @returns true if both measures are equals
+     * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+     * @param transform the matrix to transform the measure before computing the AABB
+     * @param result the resulting AABB
      */
+    Measure.prototype.transformToRef = function (transform, result) {
+        this.addAndTransformToRef(transform, 0, 0, 0, 0, result);
+    };
+    /**
+ * Check equality between this measure and another one
+ * @param other defines the other measures
+ * @returns true if both measures are equals
+ */
     Measure.prototype.isEqualsTo = function (other) {
         if (this.left !== other.left) {
             return false;
@@ -13648,7 +13689,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_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -13791,7 +13832,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -14097,7 +14138,7 @@ var ValueAndUnit = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -14416,7 +14457,7 @@ var XmlLoader = /** @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/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -14459,7 +14500,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_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__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");
@@ -14640,7 +14681,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/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -14797,7 +14838,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -15203,7 +15244,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -15289,7 +15330,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_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__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");
@@ -15783,7 +15824,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_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__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");
@@ -15838,7 +15879,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -15965,7 +16006,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -16051,7 +16092,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -16176,7 +16217,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -16367,7 +16408,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* 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");
 
@@ -16634,7 +16675,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/perfCounter");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Maths/math.vector");
 /* 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");
@@ -16957,7 +16998,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/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* 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';
@@ -16979,7 +17020,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/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* 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';
@@ -17002,7 +17043,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_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -17304,14 +17345,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/perfCounter":
+/***/ "babylonjs/Maths/math.vector":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
 
 /***/ })
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 40 - 8
dist/preview release/gui/babylon.gui.module.d.ts

@@ -289,14 +289,24 @@ declare module "babylonjs-gui/2D/measure" {
         /**
          * Computes the axis aligned bounding box of the measure after it is modified by a given transform
          * @param transform the matrix to transform the measure before computing the AABB
+         * @param addX number to add to left
+         * @param addY number to add to top
+         * @param addWidth number to add to width
+         * @param addHeight number to add to height
          * @param result the resulting AABB
          */
-        transformToRef(transform: Matrix2D, result: Measure): void;
+        addAndTransformToRef(transform: Matrix2D, addX: number, addY: number, addWidth: number, addHeight: number, result: Measure): void;
         /**
-         * Check equality between this measure and another one
-         * @param other defines the other measures
-         * @returns true if both measures are equals
+         * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+         * @param transform the matrix to transform the measure before computing the AABB
+         * @param result the resulting AABB
          */
+        transformToRef(transform: Matrix2D, result: Measure): void;
+        /**
+     * Check equality between this measure and another one
+     * @param other defines the other measures
+     * @returns true if both measures are equals
+     */
         isEqualsTo(other: Measure): boolean;
         /**
          * Creates an empty measure
@@ -353,6 +363,7 @@ declare module "babylonjs-gui/2D/advancedDynamicTexture" {
         private _pointerMoveObserver;
         private _pointerObserver;
         private _canvasPointerOutObserver;
+        private _canvasBlurObserver;
         private _background;
         /** @hidden */
         _rootContainer: Container;
@@ -620,6 +631,7 @@ declare module "babylonjs-gui/2D/advancedDynamicTexture" {
         moveFocusToControl(control: IFocusableControl): void;
         private _manageFocus;
         private _attachToOnPointerOut;
+        private _attachToOnBlur;
         /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
@@ -1240,6 +1252,8 @@ declare module "babylonjs-gui/2D/controls/control" {
         /** @hidden */
         _onWheelScroll(deltaX?: number, deltaY?: number): void;
         /** @hidden */
+        _onCanvasBlur(): void;
+        /** @hidden */
         _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
         /** Releases associated resources */
@@ -2405,6 +2419,7 @@ declare module "babylonjs-gui/2D/controls/colorpicker" {
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
         /**
          * This function expands the color picker by creating a color picker dialog with manual
          * color value input and the ability to save colors into an array to be used later in
@@ -2776,6 +2791,7 @@ declare module "babylonjs-gui/2D/controls/sliders/baseSlider" {
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
     }
 }
 declare module "babylonjs-gui/2D/controls/sliders/slider" {
@@ -4669,14 +4685,24 @@ declare module BABYLON.GUI {
         /**
          * Computes the axis aligned bounding box of the measure after it is modified by a given transform
          * @param transform the matrix to transform the measure before computing the AABB
+         * @param addX number to add to left
+         * @param addY number to add to top
+         * @param addWidth number to add to width
+         * @param addHeight number to add to height
          * @param result the resulting AABB
          */
-        transformToRef(transform: Matrix2D, result: Measure): void;
+        addAndTransformToRef(transform: Matrix2D, addX: number, addY: number, addWidth: number, addHeight: number, result: Measure): void;
         /**
-         * Check equality between this measure and another one
-         * @param other defines the other measures
-         * @returns true if both measures are equals
+         * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+         * @param transform the matrix to transform the measure before computing the AABB
+         * @param result the resulting AABB
          */
+        transformToRef(transform: Matrix2D, result: Measure): void;
+        /**
+     * Check equality between this measure and another one
+     * @param other defines the other measures
+     * @returns true if both measures are equals
+     */
         isEqualsTo(other: Measure): boolean;
         /**
          * Creates an empty measure
@@ -4721,6 +4747,7 @@ declare module BABYLON.GUI {
         private _pointerMoveObserver;
         private _pointerObserver;
         private _canvasPointerOutObserver;
+        private _canvasBlurObserver;
         private _background;
         /** @hidden */
         _rootContainer: Container;
@@ -4988,6 +5015,7 @@ declare module BABYLON.GUI {
         moveFocusToControl(control: IFocusableControl): void;
         private _manageFocus;
         private _attachToOnPointerOut;
+        private _attachToOnBlur;
         /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
@@ -5597,6 +5625,8 @@ declare module BABYLON.GUI {
         /** @hidden */
         _onWheelScroll(deltaX?: number, deltaY?: number): void;
         /** @hidden */
+        _onCanvasBlur(): void;
+        /** @hidden */
         _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
         /** Releases associated resources */
@@ -6712,6 +6742,7 @@ declare module BABYLON.GUI {
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
         /**
          * This function expands the color picker by creating a color picker dialog with manual
          * color value input and the ability to save colors into an array to be used later in
@@ -7058,6 +7089,7 @@ declare module BABYLON.GUI {
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        _onCanvasBlur(): void;
     }
 }
 declare module BABYLON.GUI {

+ 2 - 2
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 5 - 5
dist/preview release/inspector/babylon.inspector.bundle.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 181 - 32
dist/preview release/inspector/babylon.inspector.bundle.max.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 6 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -59,6 +59,8 @@ declare module INSPECTOR {
         prepareGLTFPlugin(loader: BABYLON.GLTFFileLoader): void;
         lightGizmos: Array<BABYLON.LightGizmo>;
         enableLightGizmo(light: BABYLON.Light, enable?: boolean): void;
+        cameraGizmos: Array<BABYLON.CameraGizmo>;
+        enableCameraGizmo(camera: BABYLON.Camera, enable?: boolean): void;
     }
 }
 declare module INSPECTOR {
@@ -2289,6 +2291,7 @@ declare module INSPECTOR {
         switchSkeletonViewers(): void;
         checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps): void;
         changeDisplayMode(): void;
+        changeDisplayOptions(option: string, value: number): void;
         shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps): boolean;
         onOverrideMeshLink(): void;
         render(): JSX.Element;
@@ -2914,15 +2917,18 @@ declare module INSPECTOR {
         camera: BABYLON.Camera;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
+        isGizmoEnabled: boolean;
     }> {
         private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
         componentWillUnmount(): void;
+        toggleGizmo(): void;
         render(): JSX.Element;
     }
 }

+ 15 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -28,7 +28,9 @@ declare module "babylonjs-inspector/components/globalState" {
     import { ISceneLoaderPlugin, ISceneLoaderPluginAsync } from "babylonjs/Loading/sceneLoader";
     import { Scene } from "babylonjs/scene";
     import { Light } from "babylonjs/Lights/light";
+    import { Camera } from "babylonjs/Cameras/camera";
     import { LightGizmo } from "babylonjs/Gizmos/lightGizmo";
+    import { CameraGizmo } from "babylonjs/Gizmos/cameraGizmo";
     import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
     import { ReplayRecorder } from "babylonjs-inspector/components/replayRecorder";
     export class GlobalState {
@@ -70,6 +72,8 @@ declare module "babylonjs-inspector/components/globalState" {
         prepareGLTFPlugin(loader: GLTFFileLoader): void;
         lightGizmos: Array<LightGizmo>;
         enableLightGizmo(light: Light, enable?: boolean): void;
+        cameraGizmos: Array<CameraGizmo>;
+        enableCameraGizmo(camera: Camera, enable?: boolean): void;
     }
 }
 declare module "babylonjs-inspector/components/actionTabs/paneComponent" {
@@ -2766,6 +2770,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mes
         switchSkeletonViewers(): void;
         checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps): void;
         changeDisplayMode(): void;
+        changeDisplayOptions(option: string, value: number): void;
         shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps): boolean;
         onOverrideMeshLink(): void;
         render(): JSX.Element;
@@ -3546,19 +3551,23 @@ declare module "babylonjs-inspector/components/sceneExplorer/entities/cameraTree
     import { IExplorerExtensibilityGroup } from "babylonjs/Debug/debugLayer";
     import { Camera } from "babylonjs/Cameras/camera";
     import * as React from "react";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
     interface ICameraTreeItemComponentProps {
         camera: Camera;
         extensibilityGroups?: IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
+        isGizmoEnabled: boolean;
     }> {
         private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
         componentWillUnmount(): void;
+        toggleGizmo(): void;
         render(): JSX.Element;
     }
 }
@@ -4135,6 +4144,8 @@ declare module INSPECTOR {
         prepareGLTFPlugin(loader: BABYLON.GLTFFileLoader): void;
         lightGizmos: Array<BABYLON.LightGizmo>;
         enableLightGizmo(light: BABYLON.Light, enable?: boolean): void;
+        cameraGizmos: Array<BABYLON.CameraGizmo>;
+        enableCameraGizmo(camera: BABYLON.Camera, enable?: boolean): void;
     }
 }
 declare module INSPECTOR {
@@ -6365,6 +6376,7 @@ declare module INSPECTOR {
         switchSkeletonViewers(): void;
         checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps): void;
         changeDisplayMode(): void;
+        changeDisplayOptions(option: string, value: number): void;
         shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps): boolean;
         onOverrideMeshLink(): void;
         render(): JSX.Element;
@@ -6990,15 +7002,18 @@ declare module INSPECTOR {
         camera: BABYLON.Camera;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
+        isGizmoEnabled: boolean;
     }> {
         private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
         componentWillUnmount(): void;
+        toggleGizmo(): void;
         render(): JSX.Element;
     }
 }

+ 7 - 7
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,12 +29,12 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30",
-        "babylonjs-gui": "4.2.0-alpha.30",
-        "babylonjs-loaders": "4.2.0-alpha.30",
-        "babylonjs-materials": "4.2.0-alpha.30",
-        "babylonjs-serializers": "4.2.0-alpha.30",
-        "babylonjs-gltf2interface": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32",
+        "babylonjs-gui": "4.2.0-alpha.32",
+        "babylonjs-loaders": "4.2.0-alpha.32",
+        "babylonjs-materials": "4.2.0-alpha.32",
+        "babylonjs-serializers": "4.2.0-alpha.32",
+        "babylonjs-gltf2interface": "4.2.0-alpha.32"
     },
     "peerDependencies": {
         "@types/react": ">=16.7.3",

+ 10 - 25
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2688,7 +2688,6 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
         var _this = this;
         return Promise.resolve().then(function () {
-            var _a;
             _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
             _this._loadExtensions();
             _this._checkExtensions();
@@ -2714,23 +2713,7 @@ var GLTFLoader = /** @class */ (function () {
                     var material = _this._gltf.materials[m];
                     var context_1 = "/materials/" + m;
                     var babylonDrawMode = babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["Material"].TriangleFillMode;
-                    var babylonData = material._data ? material._data[babylonDrawMode] : null;
-                    if (babylonData) {
-                        continue;
-                    }
-                    _this.logOpen(context_1 + " " + (material.name || ""));
-                    var babylonMaterial = _this.createMaterial(context_1, material, babylonDrawMode);
-                    babylonData = {
-                        babylonMaterial: babylonMaterial,
-                        babylonMeshes: [],
-                        promise: _this.loadMaterialPropertiesAsync(context_1, material, babylonMaterial)
-                    };
-                    promises.push(babylonData.promise);
-                    material._data = (_a = material._data) !== null && _a !== void 0 ? _a : {};
-                    material._data[babylonDrawMode] = babylonData;
-                    GLTFLoader.AddPointerMetadata(babylonMaterial, context_1);
-                    _this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                    _this.logClose();
+                    promises.push(_this._loadMaterialAsync(context_1, material, null, babylonDrawMode, function (material) { }));
                 }
             }
             // Restore the blocking of material dirty.
@@ -3964,13 +3947,15 @@ var GLTFLoader = /** @class */ (function () {
             this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
             this.logClose();
         }
-        babylonData.babylonMeshes.push(babylonMesh);
-        babylonMesh.onDisposeObservable.addOnce(function () {
-            var index = babylonData.babylonMeshes.indexOf(babylonMesh);
-            if (index !== -1) {
-                babylonData.babylonMeshes.splice(index, 1);
-            }
-        });
+        if (babylonMesh) {
+            babylonData.babylonMeshes.push(babylonMesh);
+            babylonMesh.onDisposeObservable.addOnce(function () {
+                var index = babylonData.babylonMeshes.indexOf(babylonMesh);
+                if (index !== -1) {
+                    babylonData.babylonMeshes.splice(index, 1);
+                }
+            });
+        }
         assign(babylonData.babylonMaterial);
         return babylonData.promise.then(function () {
             return babylonData.babylonMaterial;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 10 - 25
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -5302,7 +5302,6 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
         var _this = this;
         return Promise.resolve().then(function () {
-            var _a;
             _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
             _this._loadExtensions();
             _this._checkExtensions();
@@ -5328,23 +5327,7 @@ var GLTFLoader = /** @class */ (function () {
                     var material = _this._gltf.materials[m];
                     var context_1 = "/materials/" + m;
                     var babylonDrawMode = babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["Material"].TriangleFillMode;
-                    var babylonData = material._data ? material._data[babylonDrawMode] : null;
-                    if (babylonData) {
-                        continue;
-                    }
-                    _this.logOpen(context_1 + " " + (material.name || ""));
-                    var babylonMaterial = _this.createMaterial(context_1, material, babylonDrawMode);
-                    babylonData = {
-                        babylonMaterial: babylonMaterial,
-                        babylonMeshes: [],
-                        promise: _this.loadMaterialPropertiesAsync(context_1, material, babylonMaterial)
-                    };
-                    promises.push(babylonData.promise);
-                    material._data = (_a = material._data) !== null && _a !== void 0 ? _a : {};
-                    material._data[babylonDrawMode] = babylonData;
-                    GLTFLoader.AddPointerMetadata(babylonMaterial, context_1);
-                    _this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                    _this.logClose();
+                    promises.push(_this._loadMaterialAsync(context_1, material, null, babylonDrawMode, function (material) { }));
                 }
             }
             // Restore the blocking of material dirty.
@@ -6578,13 +6561,15 @@ var GLTFLoader = /** @class */ (function () {
             this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
             this.logClose();
         }
-        babylonData.babylonMeshes.push(babylonMesh);
-        babylonMesh.onDisposeObservable.addOnce(function () {
-            var index = babylonData.babylonMeshes.indexOf(babylonMesh);
-            if (index !== -1) {
-                babylonData.babylonMeshes.splice(index, 1);
-            }
-        });
+        if (babylonMesh) {
+            babylonData.babylonMeshes.push(babylonMesh);
+            babylonMesh.onDisposeObservable.addOnce(function () {
+                var index = babylonData.babylonMeshes.indexOf(babylonMesh);
+                if (index !== -1) {
+                    babylonData.babylonMeshes.splice(index, 1);
+                }
+            });
+        }
         assign(babylonData.babylonMaterial);
         return babylonData.promise.then(function () {
             return babylonData.babylonMaterial;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -1236,7 +1236,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
          */
-        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /**
          * Define this method to modify the default behavior when creating materials.
          * @param context The context when loading the asset
@@ -1500,7 +1500,7 @@ declare module BABYLON.GLTF2 {
         private _loadVertexAccessorAsync;
         private _loadMaterialMetallicRoughnessPropertiesAsync;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
         private _createDefaultMaterial;
         /**
          * Creates a Babylon material from a glTF material.
@@ -2220,7 +2220,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
         _loadUriAsync(context: string, property: IProperty, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** @hidden */

+ 10 - 25
dist/preview release/loaders/babylonjs.loaders.js

@@ -6682,7 +6682,6 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._loadAsync = function (nodes, resultFunc) {
         var _this = this;
         return Promise.resolve().then(function () {
-            var _a;
             _this._uniqueRootUrl = (_this._rootUrl.indexOf("file:") === -1 && _this._fileName) ? _this._rootUrl : "" + _this._rootUrl + Date.now() + "/";
             _this._loadExtensions();
             _this._checkExtensions();
@@ -6708,23 +6707,7 @@ var GLTFLoader = /** @class */ (function () {
                     var material = _this._gltf.materials[m];
                     var context_1 = "/materials/" + m;
                     var babylonDrawMode = babylonjs_Misc_deferred__WEBPACK_IMPORTED_MODULE_0__["Material"].TriangleFillMode;
-                    var babylonData = material._data ? material._data[babylonDrawMode] : null;
-                    if (babylonData) {
-                        continue;
-                    }
-                    _this.logOpen(context_1 + " " + (material.name || ""));
-                    var babylonMaterial = _this.createMaterial(context_1, material, babylonDrawMode);
-                    babylonData = {
-                        babylonMaterial: babylonMaterial,
-                        babylonMeshes: [],
-                        promise: _this.loadMaterialPropertiesAsync(context_1, material, babylonMaterial)
-                    };
-                    promises.push(babylonData.promise);
-                    material._data = (_a = material._data) !== null && _a !== void 0 ? _a : {};
-                    material._data[babylonDrawMode] = babylonData;
-                    GLTFLoader.AddPointerMetadata(babylonMaterial, context_1);
-                    _this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-                    _this.logClose();
+                    promises.push(_this._loadMaterialAsync(context_1, material, null, babylonDrawMode, function (material) { }));
                 }
             }
             // Restore the blocking of material dirty.
@@ -7958,13 +7941,15 @@ var GLTFLoader = /** @class */ (function () {
             this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
             this.logClose();
         }
-        babylonData.babylonMeshes.push(babylonMesh);
-        babylonMesh.onDisposeObservable.addOnce(function () {
-            var index = babylonData.babylonMeshes.indexOf(babylonMesh);
-            if (index !== -1) {
-                babylonData.babylonMeshes.splice(index, 1);
-            }
-        });
+        if (babylonMesh) {
+            babylonData.babylonMeshes.push(babylonMesh);
+            babylonMesh.onDisposeObservable.addOnce(function () {
+                var index = babylonData.babylonMeshes.indexOf(babylonMesh);
+                if (index !== -1) {
+                    babylonData.babylonMeshes.splice(index, 1);
+                }
+            });
+        }
         assign(babylonData.babylonMaterial);
         return babylonData.promise.then(function () {
             return babylonData.babylonMaterial;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -1309,7 +1309,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
          */
-        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /**
          * Define this method to modify the default behavior when creating materials.
          * @param context The context when loading the asset
@@ -1590,7 +1590,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
         private _loadVertexAccessorAsync;
         private _loadMaterialMetallicRoughnessPropertiesAsync;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
         private _createDefaultMaterial;
         /**
          * Creates a Babylon material from a glTF material.
@@ -2409,7 +2409,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_lod" {
         /** @hidden */
         loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
         _loadUriAsync(context: string, property: IProperty, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** @hidden */
@@ -4129,7 +4129,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
          */
-        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /**
          * Define this method to modify the default behavior when creating materials.
          * @param context The context when loading the asset
@@ -4393,7 +4393,7 @@ declare module BABYLON.GLTF2 {
         private _loadVertexAccessorAsync;
         private _loadMaterialMetallicRoughnessPropertiesAsync;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
         private _createDefaultMaterial;
         /**
          * Creates a Babylon material from a glTF material.
@@ -5113,7 +5113,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
         _loadUriAsync(context: string, property: IProperty, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** @hidden */

+ 3 - 3
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.2.0-alpha.30",
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs-gltf2interface": "4.2.0-alpha.32",
+        "babylonjs": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/nodeEditor/package.json

@@ -4,14 +4,14 @@
     },
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32"
     },
     "files": [
         "babylon.nodeEditor.max.js.map",

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

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1 +1 @@
-{"thinEngineOnly":117102,"engineOnly":153538,"sceneOnly":517643,"minGridMaterial":655833,"minStandardMaterial":805280}
+{"thinEngineOnly":117135,"engineOnly":153575,"sceneOnly":517842,"minGridMaterial":656175,"minStandardMaterial":805600}

+ 2 - 2
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

+ 3 - 3
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.30",
-        "babylonjs-gltf2interface": "4.2.0-alpha.30"
+        "babylonjs": "4.2.0-alpha.32",
+        "babylonjs-gltf2interface": "4.2.0-alpha.32"
     },
     "engines": {
         "node": "*"

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 868 - 208
dist/preview release/viewer/babylon.module.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 122 - 110
dist/preview release/viewer/babylon.viewer.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -1309,7 +1309,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
          */
-        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /**
          * Define this method to modify the default behavior when creating materials.
          * @param context The context when loading the asset
@@ -1590,7 +1590,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
         private _loadVertexAccessorAsync;
         private _loadMaterialMetallicRoughnessPropertiesAsync;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
         private _createDefaultMaterial;
         /**
          * Creates a Babylon material from a glTF material.
@@ -2409,7 +2409,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_lod" {
         /** @hidden */
         loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
         _loadUriAsync(context: string, property: IProperty, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** @hidden */
@@ -4129,7 +4129,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
          */
-        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /**
          * Define this method to modify the default behavior when creating materials.
          * @param context The context when loading the asset
@@ -4393,7 +4393,7 @@ declare module BABYLON.GLTF2 {
         private _loadVertexAccessorAsync;
         private _loadMaterialMetallicRoughnessPropertiesAsync;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
         private _createDefaultMaterial;
         /**
          * Creates a Babylon material from a glTF material.
@@ -5113,7 +5113,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>>;
         /** @hidden */
-        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+        _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
         /** @hidden */
         _loadUriAsync(context: string, property: IProperty, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** @hidden */

+ 7 - 1
dist/preview release/what's new.md

@@ -17,9 +17,11 @@
 
 ### General
 
-- Added support for querystrings on KTX file URLs ([abogartz](https://github.com/abogartz/Babylon.js)
+- Added support for postproces serialization ([Deltakosh](https://github.com/deltakosh))
+- Added support for querystrings on KTX file URLs ([abogartz](https://github.com/abogartz)
 - Refactored React refs from old string API to React.createRef() API ([belfortk](https://github.com/belfortk))
 - Scale on one axis for `BoundingBoxGizmo` ([cedricguillemet](https://github.com/cedricguillemet))
+- Camera gizmo ([cedricguillemet](https://github.com/cedricguillemet))
 - Node support (Transform, Bone) for gizmos ([cedricguillemet](https://github.com/cedricguillemet))
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
@@ -39,6 +41,7 @@
 - Force compute world matrix of the newly-attached mesh of a ray helper ([RaananW](https://github.com/RaananW))
 - Allow 180 monoscopic videos on top of the video dome ([#8575](https://github.com/BabylonJS/Babylon.js/issues/8575)) ([RaananW](https://github.com/RaananW))
 - Added `AssetContainerTask` support to `AssetsManager` class ([MackeyK24](https://github.com/MackeyK24))
+- Changed DeviceSourceManager getInput contract to no longer return nullable values ([Drigax](https://github.com/drigax))
 
 ### Engine
 
@@ -93,6 +96,7 @@
 ### Sprites
 
 - Added support for 'sprite.useAlphaForPicking` to enable precise picking using sprite alpha ([Deltakosh](https://github.com/deltakosh))
+- Improved rendering engine by using instancing when available ([Deltakosh](https://github.com/deltakosh))
 
 ### Physics
 
@@ -165,6 +169,7 @@
 - All camera view matrices are now calculated by Babylon to support left and right handed systems ([RaananW](https://github.com/RaananW))
 - WebXR Features Manager now has the ability to check if a feature can be enabled, and set native features optional or required ([RaananW](https://github.com/RaananW))
 - Optional camera gaze mode added to the pointer selection feature ([RaananW](https://github.com/RaananW))
+- WebXR hit test can now define different entity type for the results ([#8687](https://github.com/BabylonJS/Babylon.js/issues/8687)) ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 
@@ -276,6 +281,7 @@
 - Fix an issue causing views to render blank when scene rendering is skipped for a given iteration of the render loop ([elInfidel](https://github.com/elInfidel))
 - Fix docs Matrix.RotationYawPitchRoll and Matrix.RotationYawPitchRollToRef ([VSerain](https://github.com/VSerain))
 - Fix issue in `GLTFLoader._updateBoneMatrices()` where bone rest position was not set. ([drigax](https://github.com/drigax))
+- Fix the bounding box of instances that does not match the instance position / rotation / scaling ([Popov72](https://github.com/Popov72))
 
 ## Breaking changes
 - `FollowCamera.target` was renamed to `FollowCamera.meshTarget` to not be in conflict with `TargetCamera.target` ([Deltakosh](https://github.com/deltakosh))

+ 1 - 0
dist/what's new.md

@@ -236,6 +236,7 @@
 - Added `ScrollViewer.freezeControls` property to speed up rendering ([Popov72](https://github.com/Popov72))
 - Added `ImageScrollBar.num90RotationInVerticalMode` property to let the user rotate the pictures when in vertical mode ([Popov72](https://github.com/Popov72))
 - Modified isPointerBlocker to block mouse wheel scroll events. ScrollViewer mouse scroll no longer dependent on scene. ([lockphase](https://github.com/lockphase/))
+- Added `_onCanvasBlur` event for controls to detect when the canvas loses focus. Fixes bug where sliders and color pickers would become stuck when canvas lost focus. ([DarraghBurkeMS](https://github.com/DarraghBurkeMS))
 
 ### Particles
 

+ 14 - 0
gui/src/2D/advancedDynamicTexture.ts

@@ -56,6 +56,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
     private _pointerMoveObserver: Nullable<Observer<PointerInfoPre>>;
     private _pointerObserver: Nullable<Observer<PointerInfo>>;
     private _canvasPointerOutObserver: Nullable<Observer<PointerEvent>>;
+    private _canvasBlurObserver: Nullable<Observer<Engine>>;
     private _background: string;
     /** @hidden */
     public _rootContainer = new Container("root");
@@ -480,6 +481,9 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         if (this._canvasPointerOutObserver) {
             scene.getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
         }
+        if (this._canvasBlurObserver) {
+            scene.getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+        }
         if (this._layerToDispose) {
             this._layerToDispose.texture = null;
             this._layerToDispose.dispose();
@@ -741,6 +745,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             }
         });
         this._attachToOnPointerOut(scene);
+        this._attachToOnBlur(scene);
     }
     /** @hidden */
     private onClipboardCopy = (rawEvt: Event) => {
@@ -838,6 +843,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         });
         mesh.enablePointerMoveEvents = supportPointerMove;
         this._attachToOnPointerOut(scene);
+        this._attachToOnBlur(scene);
     }
     /**
     * Move the focus to a specific control
@@ -876,6 +882,14 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             }
         });
     }
+    private _attachToOnBlur(scene: Scene): void {
+        this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add((pointerEvent) => {
+            Object.entries(this._lastControlDown).forEach(([key, value]) => {
+                value._onCanvasBlur();
+            });
+            this._lastControlDown = {};
+        });
+    }
     // Statics
     /**
      * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)

+ 5 - 0
gui/src/2D/controls/colorpicker.ts

@@ -434,6 +434,11 @@ export class ColorPicker extends Control {
         super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
     }
 
+    public _onCanvasBlur() {
+        this._forcePointerUp();
+        super._onCanvasBlur();
+    }
+
     /**
      * This function expands the color picker by creating a color picker dialog with manual
      * color value input and the ability to save colors into an array to be used later in

+ 9 - 1
gui/src/2D/controls/control.ts

@@ -1400,7 +1400,12 @@ export class Control {
         if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
             this.host._numLayoutCalls++;
 
-            this._currentMeasure.transformToRef(this._transformMatrix, this._prevCurrentMeasureTransformedIntoGlobalSpace);
+            this._currentMeasure.addAndTransformToRef(this._transformMatrix,
+                -this.paddingLeftInPixels | 0,
+                -this.paddingTopInPixels | 0,
+                this.paddingRightInPixels | 0,
+                this.paddingBottomInPixels | 0,
+                this._prevCurrentMeasureTransformedIntoGlobalSpace);
 
             context.save();
 
@@ -1854,6 +1859,9 @@ export class Control {
     }
 
     /** @hidden */
+    public _onCanvasBlur(): void {}
+
+    /** @hidden */
     public _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean {
         if (!this._isEnabled) {
             return false;

+ 6 - 0
gui/src/2D/controls/sliders/baseSlider.ts

@@ -326,4 +326,10 @@ export class BaseSlider extends Control {
         delete this._host._capturingControl[pointerId];
         super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
     }
+
+    public _onCanvasBlur(): void {
+        this._forcePointerUp();
+        super._onCanvasBlur();
+    }
+
 }

+ 2 - 2
gui/src/2D/controls/textBlock.ts

@@ -256,13 +256,13 @@ export class TextBlock extends Control {
 
         if (this._resizeToFit) {
             if (this._textWrapping === TextWrapping.Clip) {
-                let newWidth = this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth;
+                let newWidth = (this.paddingLeftInPixels + this.paddingRightInPixels + maxLineWidth) | 0;
                 if (newWidth !== this._width.internalValue) {
                     this._width.updateInPlace(newWidth, ValueAndUnit.UNITMODE_PIXEL);
                     this._rebuildLayout = true;
                 }
             }
-            let newHeight = this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length;
+            let newHeight = (this.paddingTopInPixels + this.paddingBottomInPixels + this._fontOffset.height * this._lines.length) | 0;
 
             if (this._lines.length > 0 && this._lineSpacing.internalValue !== 0) {
                 let lineSpacing = 0;

+ 22 - 5
gui/src/2D/measure.ts

@@ -86,13 +86,22 @@ export class Measure {
     /**
      * Computes the axis aligned bounding box of the measure after it is modified by a given transform
      * @param transform the matrix to transform the measure before computing the AABB
+     * @param addX number to add to left
+     * @param addY number to add to top
+     * @param addWidth number to add to width
+     * @param addHeight number to add to height
      * @param result the resulting AABB
      */
-    public transformToRef(transform: Matrix2D, result: Measure) {
-        tmpRect[0].copyFromFloats(this.left, this.top);
-        tmpRect[1].copyFromFloats(this.left + this.width, this.top);
-        tmpRect[2].copyFromFloats(this.left + this.width, this.top + this.height);
-        tmpRect[3].copyFromFloats(this.left, this.top + this.height);
+    public addAndTransformToRef(transform: Matrix2D, addX: number, addY: number, addWidth: number, addHeight: number, result: Measure) {
+        const left = this.left + addX;
+        const top = this.top + addY;
+        const width = this.width + addWidth;
+        const height = this.height + addHeight;
+
+        tmpRect[0].copyFromFloats(left, top);
+        tmpRect[1].copyFromFloats(left + width, top);
+        tmpRect[2].copyFromFloats(left + width, top + height);
+        tmpRect[3].copyFromFloats(left, top + height);
 
         tmpV1.copyFromFloats(Number.MAX_VALUE, Number.MAX_VALUE);
         tmpV2.copyFromFloats(0, 0);
@@ -110,6 +119,14 @@ export class Measure {
     }
 
     /**
+     * Computes the axis aligned bounding box of the measure after it is modified by a given transform
+     * @param transform the matrix to transform the measure before computing the AABB
+     * @param result the resulting AABB
+     */
+    public transformToRef(transform: Matrix2D, result: Measure) {
+        this.addAndTransformToRef(transform, 0, 0, 0, 0, result);
+    }
+        /**
      * Check equality between this measure and another one
      * @param other defines the other measures
      * @returns true if both measures are equals

+ 193 - 145
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/skeletonPropertyGridComponent.tsx

@@ -1,146 +1,194 @@
-import * as React from "react";
-
-import { Observable } from "babylonjs/Misc/observable";
-
-import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
-import { LineContainerComponent } from "../../../lineContainerComponent";
-import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
-import { TextLineComponent } from "../../../lines/textLineComponent";
-import { LockObject } from "../lockObject";
-import { GlobalState } from '../../../../globalState';
-import { Skeleton } from 'babylonjs/Bones/skeleton';
-import { AnimationGridComponent } from '../animations/animationPropertyGridComponent';
-import { SkeletonViewer } from 'babylonjs/Debug/skeletonViewer';
-import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
-import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
-
-interface ISkeletonPropertyGridComponentProps {
-    globalState: GlobalState;
-    skeleton: Skeleton,
-    lockObject: LockObject,
-    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
-}
-
-export class SkeletonPropertyGridComponent extends React.Component<ISkeletonPropertyGridComponentProps> {
-    private _skeletonViewersEnabled = false;
-    private _skeletonViewerDisplayOptions = { displayMode : SkeletonViewer.DISPLAY_LINES }
-    private _skeletonViewers = new Array<SkeletonViewer>();
-
-    constructor(props: ISkeletonPropertyGridComponentProps) {
-        super(props);
-        
-        this.checkSkeletonViewerState(this.props);
-    }
-
-    switchSkeletonViewers() {
-        this._skeletonViewersEnabled = !this._skeletonViewersEnabled;
-        const scene = this.props.skeleton.getScene();
-
-        if (this._skeletonViewersEnabled) {
-            for (var mesh of scene.meshes) {
-                if (mesh.skeleton === this.props.skeleton) {
-                    var found = false;
-                    for (var sIndex = 0; sIndex < this._skeletonViewers.length; sIndex++) {
-                        if (this._skeletonViewers[sIndex].skeleton === mesh.skeleton) {
-                            found = true;
-                            break;
-                        }
-                    }
-                    if (found) {
-                        continue;
-                    }
-                    var viewer = new SkeletonViewer(mesh.skeleton, mesh, scene, false, 3, { displayMode: this._skeletonViewerDisplayOptions.displayMode });
-                    viewer.isEnabled = true;
-                    this._skeletonViewers.push(viewer);
-                    if (!mesh.reservedDataStore) {
-                        mesh.reservedDataStore = {};
-                    }
-                    mesh.reservedDataStore.skeletonViewer = viewer;                   
-                }
-            }
-        } else {
-            for (var index = 0; index < this._skeletonViewers.length; index++) {
-                this._skeletonViewers[index].mesh.reservedDataStore.skeletonViewer = null;
-                this._skeletonViewers[index].dispose();
-            }
-            this._skeletonViewers = [];
-
-        }
-    }
-
-    checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps) {
-        const scene = props.skeleton.getScene();
-        this._skeletonViewers = [];
-
-        if (!scene) {
-            return;
-        }
-
-        for (var mesh of scene.meshes) {
-            if (mesh.skeleton === props.skeleton && mesh.reservedDataStore && mesh.reservedDataStore.skeletonViewer) {
-                this._skeletonViewers.push(mesh.reservedDataStore.skeletonViewer);
-            }
-        }
-
-        this._skeletonViewersEnabled = (this._skeletonViewers.length > 0);
-    }
-
-    changeDisplayMode(){
-        if (this._skeletonViewersEnabled){              
-            for (var index = 0; index < this._skeletonViewers.length; index++) {
-                this._skeletonViewers[index].changeDisplayMode( this._skeletonViewerDisplayOptions.displayMode || 0 );
-            }                   
-        }
-    }
-
-    shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps) {
-        if (nextProps.skeleton !== this.props.skeleton) {
-            this.checkSkeletonViewerState(nextProps);
-        }
-
-        return true;
-    }
-
-    onOverrideMeshLink() {
-        if (!this.props.globalState.onSelectionChangedObservable) {
-            return;
-        }
-
-        const skeleton = this.props.skeleton;
-        this.props.globalState.onSelectionChangedObservable.notifyObservers(skeleton.overrideMesh);
-    }        
-
-    render() {
-        const skeleton = this.props.skeleton;
-
-        const debugModeOptions = [
-            { label: "Lines", value: SkeletonViewer.DISPLAY_LINES },
-            { label: "Spheres", value: SkeletonViewer.DISPLAY_SPHERES },
-            { label: "Sphere and Spurs", value: SkeletonViewer.DISPLAY_SPHERE_AND_SPURS }
-        ];
-
-
-        return (
-            <div className="pane">
-                <CustomPropertyGridComponent globalState={this.props.globalState} target={skeleton}
-                    lockObject={this.props.lockObject}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                    
-                <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
-                    <TextLineComponent label="ID" value={skeleton.id} />
-                    <TextLineComponent label="Bone count" value={skeleton.bones.length.toString()} />
-                    {
-                        skeleton.overrideMesh &&
-                        <TextLineComponent label="Override mesh" value={skeleton.overrideMesh.name} onLink={() => this.onOverrideMeshLink()}/>
-                    }                        
-                    <CheckBoxLineComponent label="Use texture to store matrices" target={skeleton} propertyName="useTextureToStoreBoneMatrices" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    
-                    <LineContainerComponent globalState={this.props.globalState} title="DEBUG">                        
-                        <CheckBoxLineComponent label="Enabled" isSelected={() => this._skeletonViewersEnabled} onSelect={() => this.switchSkeletonViewers()} />
-                        <OptionsLineComponent label="displayMode" options={debugModeOptions} target={this._skeletonViewerDisplayOptions} propertyName="displayMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={() => this.changeDisplayMode()} />
-                    </LineContainerComponent>                    
-                </LineContainerComponent>
-                <AnimationGridComponent globalState={this.props.globalState} animatable={skeleton} scene={skeleton.getScene()} lockObject={this.props.lockObject} />
-            </div>
-        );
-    }
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
+import { TextLineComponent } from "../../../lines/textLineComponent";
+import { LockObject } from "../lockObject";
+import { GlobalState } from '../../../../globalState';
+import { Skeleton } from 'babylonjs/Bones/skeleton';
+import { AnimationGridComponent } from '../animations/animationPropertyGridComponent';
+import { SkeletonViewer } from 'babylonjs/Debug/skeletonViewer';
+import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
+import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
+import { FloatLineComponent } from "../../../lines/floatLineComponent";
+
+
+interface ISkeletonPropertyGridComponentProps {
+    globalState: GlobalState;
+    skeleton: Skeleton,
+    lockObject: LockObject,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class SkeletonPropertyGridComponent extends React.Component<ISkeletonPropertyGridComponentProps> {
+    private _skeletonViewersEnabled = false;
+
+    private _skeletonViewerDisplayOptions = { 
+        displayMode : SkeletonViewer.DISPLAY_LINES,
+        sphereBaseSize : 0.15,
+        sphereScaleUnit : 2,
+        sphereFactor : 0.865,
+        midStep : 0.235,
+        midStepFactor : 0.155
+
+    }
+
+    private _skeletonViewers = new Array<SkeletonViewer>();
+
+    constructor(props: ISkeletonPropertyGridComponentProps) {
+        super(props);
+        
+        this.checkSkeletonViewerState(this.props);
+    }
+
+    switchSkeletonViewers() {
+        this._skeletonViewersEnabled = !this._skeletonViewersEnabled;
+        const scene = this.props.skeleton.getScene();
+
+        if (this._skeletonViewersEnabled) {
+            for (var mesh of scene.meshes) {
+                if (mesh.skeleton === this.props.skeleton) {
+                    var found = false;
+                    for (var sIndex = 0; sIndex < this._skeletonViewers.length; sIndex++) {
+                        if (this._skeletonViewers[sIndex].skeleton === mesh.skeleton) {
+                            found = true;
+                            break;
+                        }
+                    }
+                    if (found) {
+                        continue;
+                    }
+
+                    var viewer = new SkeletonViewer(mesh.skeleton, mesh, scene, false, 3, { 
+                        displayMode: this._skeletonViewerDisplayOptions.displayMode,
+                        displayOptions : {
+                            sphereBaseSize : this._skeletonViewerDisplayOptions.sphereBaseSize,
+                            sphereScaleUnit : this._skeletonViewerDisplayOptions.sphereScaleUnit,
+                            sphereFactor : this._skeletonViewerDisplayOptions.sphereFactor,
+                            midStep : this._skeletonViewerDisplayOptions.midStep,
+                            midStepFactor : this._skeletonViewerDisplayOptions.midStepFactor
+                        }
+                    });
+
+                    viewer.isEnabled = true;
+                    this._skeletonViewers.push(viewer);
+                    if (!mesh.reservedDataStore) {
+                        mesh.reservedDataStore = {};
+                    }
+                    mesh.reservedDataStore.skeletonViewer = viewer;                   
+                }
+            }
+        } else {
+            for (var index = 0; index < this._skeletonViewers.length; index++) {
+                this._skeletonViewers[index].mesh.reservedDataStore.skeletonViewer = null;
+                this._skeletonViewers[index].dispose();
+            }
+            this._skeletonViewers = [];
+
+        }
+    }
+
+    checkSkeletonViewerState(props: ISkeletonPropertyGridComponentProps) {
+        const scene = props.skeleton.getScene();
+        this._skeletonViewers = [];
+
+        if (!scene) {
+            return;
+        }
+
+        for (var mesh of scene.meshes) {
+            if (mesh.skeleton === props.skeleton && mesh.reservedDataStore && mesh.reservedDataStore.skeletonViewer) {
+                this._skeletonViewers.push(mesh.reservedDataStore.skeletonViewer);
+            }
+        }
+
+        this._skeletonViewersEnabled = (this._skeletonViewers.length > 0);
+    }
+
+    changeDisplayMode(){
+        if (this._skeletonViewersEnabled){              
+            for (var index = 0; index < this._skeletonViewers.length; index++) {
+                this._skeletonViewers[index].changeDisplayMode( this._skeletonViewerDisplayOptions.displayMode || 0 );
+            }                   
+        }
+    }
+
+    changeDisplayOptions(option: string, value: number){
+        if (this._skeletonViewersEnabled){              
+            for (var index = 0; index < this._skeletonViewers.length; index++) {
+                this._skeletonViewers[index].changeDisplayOptions( option, value );
+            } 
+            if((this._skeletonViewerDisplayOptions as any)[option] !== undefined ){
+                (this._skeletonViewerDisplayOptions as any)[option] = value;
+            }            
+        }
+    }
+
+    shouldComponentUpdate(nextProps: ISkeletonPropertyGridComponentProps) {
+        if (nextProps.skeleton !== this.props.skeleton) {
+            this.checkSkeletonViewerState(nextProps);
+        }
+
+        return true;
+    }
+
+    onOverrideMeshLink() {
+        if (!this.props.globalState.onSelectionChangedObservable) {
+            return;
+        }
+
+        const skeleton = this.props.skeleton;
+        this.props.globalState.onSelectionChangedObservable.notifyObservers(skeleton.overrideMesh);
+    }        
+
+    render() {
+        const skeleton = this.props.skeleton;
+
+        const debugModeOptions = [
+            { label: "Lines", value: SkeletonViewer.DISPLAY_LINES },
+            { label: "Spheres", value: SkeletonViewer.DISPLAY_SPHERES },
+            { label: "Sphere and Spurs", value: SkeletonViewer.DISPLAY_SPHERE_AND_SPURS }
+        ];
+
+        let displayOptions;
+        if(this._skeletonViewerDisplayOptions.displayMode > SkeletonViewer.DISPLAY_LINES){
+            displayOptions = 
+            (<LineContainerComponent globalState={this.props.globalState} title="DISPLAY OPTIONS">
+                <FloatLineComponent label="sphereBaseSize" target={this._skeletonViewerDisplayOptions} propertyName='sphereBaseSize' onPropertyChangedObservable={this.props.onPropertyChangedObservable} onChange={(value)=>{this.changeDisplayOptions('sphereBaseSize', value)}}/>
+                <FloatLineComponent label="sphereScaleUnit" target={this._skeletonViewerDisplayOptions} propertyName='sphereScaleUnit' onPropertyChangedObservable={this.props.onPropertyChangedObservable} onChange={(value)=>{this.changeDisplayOptions('sphereScaleUnit', value)}}/>
+                <FloatLineComponent label="sphereFactor" target={this._skeletonViewerDisplayOptions} propertyName='sphereFactor' onPropertyChangedObservable={this.props.onPropertyChangedObservable} onChange={(value)=>{this.changeDisplayOptions('sphereFactor', value)}}/>
+                <FloatLineComponent label="midStep" target={this._skeletonViewerDisplayOptions} propertyName='midStep' onPropertyChangedObservable={this.props.onPropertyChangedObservable} onChange={(value)=>{this.changeDisplayOptions('midStep', value)}}/>
+                <FloatLineComponent label="midStepFactor" target={this._skeletonViewerDisplayOptions} propertyName='midStepFactor' onPropertyChangedObservable={this.props.onPropertyChangedObservable} onChange={(value)=>{this.changeDisplayOptions('midStepFactor', value)}}/>
+            </LineContainerComponent>)
+        }else{
+             displayOptions = (null)
+        }
+
+        return (
+            <div className="pane">
+                <CustomPropertyGridComponent globalState={this.props.globalState} target={skeleton}
+                    lockObject={this.props.lockObject}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                    
+                <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
+                    <TextLineComponent label="ID" value={skeleton.id} />
+                    <TextLineComponent label="Bone count" value={skeleton.bones.length.toString()} />
+                    {
+                        skeleton.overrideMesh &&
+                        <TextLineComponent label="Override mesh" value={skeleton.overrideMesh.name} onLink={() => this.onOverrideMeshLink()}/>
+                    }                        
+                    <CheckBoxLineComponent label="Use texture to store matrices" target={skeleton} propertyName="useTextureToStoreBoneMatrices" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    
+                    <LineContainerComponent globalState={this.props.globalState} title="DEBUG">                        
+                        <CheckBoxLineComponent label="Enabled" isSelected={() => this._skeletonViewersEnabled} onSelect={() => this.switchSkeletonViewers()} />
+                        <OptionsLineComponent label="displayMode" options={debugModeOptions} target={this._skeletonViewerDisplayOptions} propertyName="displayMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={() => this.changeDisplayMode()} />
+                        {displayOptions}                   
+                    </LineContainerComponent>                    
+                </LineContainerComponent>
+                <AnimationGridComponent globalState={this.props.globalState} animatable={skeleton} scene={skeleton.getScene()} lockObject={this.props.lockObject} />
+            </div>
+        );
+    }
 }

+ 21 - 0
inspector/src/components/globalState.ts

@@ -6,7 +6,9 @@ import { Observable, Observer } from "babylonjs/Misc/observable";
 import { ISceneLoaderPlugin, ISceneLoaderPluginAsync } from "babylonjs/Loading/sceneLoader";
 import { Scene } from "babylonjs/scene";
 import { Light } from "babylonjs/Lights/light";
+import { Camera } from "babylonjs/Cameras/camera";
 import { LightGizmo } from "babylonjs/Gizmos/lightGizmo";
+import { CameraGizmo } from "babylonjs/Gizmos/cameraGizmo";
 import { PropertyChangedEvent } from "./propertyChangedEvent";
 import { ReplayRecorder } from './replayRecorder';
 import { DataStorage } from 'babylonjs/Misc/dataStorage';
@@ -130,4 +132,23 @@ export class GlobalState {
             light.reservedDataStore.lightGizmo = null;
         }
     }
+    // Camera gizmos
+    public cameraGizmos: Array<CameraGizmo> = [];
+    public enableCameraGizmo(camera: Camera, enable = true) {
+        if (enable) {
+            if (!camera.reservedDataStore) {
+                camera.reservedDataStore = {}
+            }
+            if (!camera.reservedDataStore.cameraGizmo) {
+                camera.reservedDataStore.cameraGizmo = new CameraGizmo();
+                this.cameraGizmos.push(camera.reservedDataStore.cameraGizmo)
+                camera.reservedDataStore.cameraGizmo.camera = camera;
+                camera.reservedDataStore.cameraGizmo.material.reservedDataStore = {hidden: true};
+            }
+        } else if (camera.reservedDataStore && camera.reservedDataStore.cameraGizmo) {
+            this.cameraGizmos.splice(this.cameraGizmos.indexOf(camera.reservedDataStore.cameraGizmo), 1);
+            camera.reservedDataStore.cameraGizmo.dispose();
+            camera.reservedDataStore.cameraGizmo = null;
+        }
+    }
 }

+ 24 - 5
inspector/src/components/sceneExplorer/entities/cameraTreeItemComponent.tsx

@@ -5,18 +5,20 @@ import { Camera } from "babylonjs/Cameras/camera";
 import { Scene } from "babylonjs/scene";
 
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faVideo, faCamera } from '@fortawesome/free-solid-svg-icons';
+import { faVideo, faCamera, faEye } from '@fortawesome/free-solid-svg-icons';
 import { TreeItemLabelComponent } from "../treeItemLabelComponent";
 import { ExtensionsComponent } from "../extensionsComponent";
 import * as React from "react";
+import { GlobalState } from "../../globalState";
 
 interface ICameraTreeItemComponentProps {
     camera: Camera,
     extensibilityGroups?: IExplorerExtensibilityGroup[],
-    onClick: () => void
+    onClick: () => void,
+    globalState: GlobalState
 }
 
-export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, { isActive: boolean }> {
+export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, { isActive: boolean, isGizmoEnabled:boolean }> {
     private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
 
     constructor(props: ICameraTreeItemComponentProps) {
@@ -25,7 +27,7 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
         const camera = this.props.camera;
         const scene = camera.getScene();
 
-        this.state = { isActive: scene.activeCamera === camera };
+        this.state = { isActive: scene.activeCamera === camera, isGizmoEnabled: (camera.reservedDataStore && camera.reservedDataStore.cameraGizmo) };
     }
 
     setActive(): void {
@@ -65,10 +67,24 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
         }
     }
 
+    toggleGizmo(): void {
+        const camera = this.props.camera;
+        if(camera.reservedDataStore && camera.reservedDataStore.cameraGizmo){
+            if (camera.getScene().reservedDataStore && camera.getScene().reservedDataStore.gizmoManager) {
+                camera.getScene().reservedDataStore.gizmoManager.attachToMesh(null);
+            }
+            this.props.globalState.enableCameraGizmo(camera, false);
+            this.setState({ isGizmoEnabled: false });
+        }else{
+            this.props.globalState.enableCameraGizmo(camera, true);
+            this.setState({ isGizmoEnabled: true });
+        }
+    }
+
     render() {
         const isActiveElement = this.state.isActive ? <FontAwesomeIcon icon={faVideo} /> : <FontAwesomeIcon icon={faVideo} className="isNotActive" />;
         const scene = this.props.camera.getScene()!;
-
+        const isGizmoEnabled = (this.state.isGizmoEnabled || (this.props.camera && this.props.camera.reservedDataStore && this.props.camera.reservedDataStore.cameraGizmo)) ? <FontAwesomeIcon icon={faEye} /> : <FontAwesomeIcon icon={faEye} className="isNotActive" />;
         return (
             <div className="cameraTools">
                 <TreeItemLabelComponent label={this.props.camera.name} onClick={() => this.props.onClick()} icon={faCamera} color="green" />
@@ -78,6 +94,9 @@ export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComp
                         {isActiveElement}
                     </div>
                 }
+                <div className="enableGizmo icon" onClick={() => this.toggleGizmo()} title="Turn on/off the camera's gizmo">
+                    {isGizmoEnabled}
+                </div>
                 <ExtensionsComponent target={this.props.camera} extensibilityGroups={this.props.extensibilityGroups} />
             </div>
         )

+ 82 - 23
inspector/src/components/sceneExplorer/entities/sceneTreeItemComponent.tsx

@@ -14,6 +14,7 @@ import { GlobalState } from "../../globalState";
 import { UtilityLayerRenderer } from "babylonjs/Rendering/utilityLayerRenderer";
 import { PropertyChangedEvent } from '../../../components/propertyChangedEvent';
 import { LightGizmo } from 'babylonjs/Gizmos/lightGizmo';
+import { CameraGizmo } from 'babylonjs/Gizmos/cameraGizmo';
 import { TmpVectors, Vector3 } from 'babylonjs/Maths/math';
 
 interface ISceneTreeItemComponentProps {
@@ -89,9 +90,17 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                         this.props.globalState.enableLightGizmo(this._selectedEntity, true);
                         this.forceUpdate();
                     }
-                    manager.attachToMesh(this._selectedEntity.reservedDataStore.lightGizmo.attachedMesh);
+                    manager.attachToNode(this._selectedEntity.reservedDataStore.lightGizmo.attachedNode);
+                } else if (className.indexOf("Camera") !== -1) {
+                    if (!this._selectedEntity.reservedDataStore || !this._selectedEntity.reservedDataStore.cameraGizmo) {
+                        this.props.globalState.enableCameraGizmo(this._selectedEntity, true);
+                        this.forceUpdate();
+                    }
+                    manager.attachToNode(this._selectedEntity.reservedDataStore.cameraGizmo.attachedNode);
+                }else if(className.indexOf("Bone") !== -1){
+                    manager.attachToMesh((this._selectedEntity._linkedTransformNode)?this._selectedEntity._linkedTransformNode:this._selectedEntity);
                 } else {
-                    manager.attachToMesh(null);
+                    manager.attachToNode(null);
                 }
             }
         });
@@ -158,7 +167,23 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                     var gizmoScene = this.props.globalState.lightGizmos[0].gizmoLayer.utilityLayerScene;
                     let pickInfo = gizmoScene.pick(pickPosition.x, pickPosition.y, (m: any) => {
                         for (var g of (this.props.globalState.lightGizmos as any)) {
-                            if (g.attachedMesh == m) {
+                            if (g.attachedNode == m) {
+                                return true;
+                            }
+                        }
+                        return false;
+                    });
+                    if (pickInfo && pickInfo.hit && this.props.onSelectionChangedObservable) {
+                        this.props.onSelectionChangedObservable.notifyObservers(pickInfo.pickedMesh);
+                        return;
+                    }
+                }
+                // Pick camera gizmos
+                if (this.props.globalState.cameraGizmos.length > 0) {
+                    var gizmoScene = this.props.globalState.cameraGizmos[0].gizmoLayer.utilityLayerScene;
+                    let pickInfo = gizmoScene.pick(pickPosition.x, pickPosition.y, (m: any) => {
+                        for (var g of (this.props.globalState.cameraGizmos as any)) {
+                            if (g.attachedNode == m) {
                                 return true;
                             }
                         }
@@ -207,7 +232,7 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                     }
                     for (var gizmo of this.props.globalState.lightGizmos) {
                         if (gizmo._rootMesh == node) {
-                            manager.attachToMesh(gizmo.attachedMesh);
+                            manager.attachToNode(gizmo.attachedNode);
                         }
                     }
                 }
@@ -230,16 +255,28 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                     if (!this._posDragEnd) {
                         // Record movement for generating replay code
                         this._posDragEnd = manager.gizmos.positionGizmo!.onDragEndObservable.add(() => {
-                            if (manager.gizmos.positionGizmo && manager.gizmos.positionGizmo.attachedMesh) {
-                                var lightGizmo: Nullable<LightGizmo> = manager.gizmos.positionGizmo.attachedMesh.reservedDataStore ? manager.gizmos.positionGizmo.attachedMesh.reservedDataStore.lightGizmo : null;
-                                var obj: any = (lightGizmo && lightGizmo.light) ? lightGizmo.light : manager.gizmos.positionGizmo.attachedMesh;
+                            if (manager.gizmos.positionGizmo && manager.gizmos.positionGizmo.attachedNode) {
+                                var lightGizmo: Nullable<LightGizmo> = manager.gizmos.positionGizmo.attachedNode.reservedDataStore ? manager.gizmos.positionGizmo.attachedNode.reservedDataStore.lightGizmo : null;
+                                var objLight: any = (lightGizmo && lightGizmo.light) ? lightGizmo.light : manager.gizmos.positionGizmo.attachedNode;
 
-                                if (obj.position) {
+                                if (objLight.position) {
                                     var e = new PropertyChangedEvent();
-                                    e.object = obj
+                                    e.object = objLight
                                     e.property = "position"
-                                    e.value = obj.position;
+                                    e.value = objLight.position;
                                     this.props.globalState.onPropertyChangedObservable.notifyObservers(e)
+                                } else {
+                                    var cameraGizmo: Nullable<CameraGizmo> = manager.gizmos.positionGizmo.attachedNode.reservedDataStore ? manager.gizmos.positionGizmo.attachedNode.reservedDataStore.cameraGizmo : null;
+                                    var objCamera: any = (cameraGizmo && cameraGizmo.camera) ? cameraGizmo.camera : manager.gizmos.positionGizmo.attachedNode;
+    
+                                    if (objCamera.position) {
+                                        var e = new PropertyChangedEvent();
+                                        e.object = objCamera
+                                        e.property = "position"
+                                        e.value = objCamera.position;
+                                        this.props.globalState.onPropertyChangedObservable.notifyObservers(e)
+                                    }
+
                                 }
                             }
                         })
@@ -251,27 +288,41 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                     if (!this._rotateDragEnd) {
                         // Record movement for generating replay code
                         this._rotateDragEnd = manager.gizmos.rotationGizmo!.onDragEndObservable.add(() => {
-                            if (manager.gizmos.rotationGizmo && manager.gizmos.rotationGizmo.attachedMesh) {
-                                var lightGizmo: Nullable<LightGizmo> = manager.gizmos.rotationGizmo.attachedMesh.reservedDataStore ? manager.gizmos.rotationGizmo.attachedMesh.reservedDataStore.lightGizmo : null;
-                                var obj: any = (lightGizmo && lightGizmo.light) ? lightGizmo.light : manager.gizmos.rotationGizmo.attachedMesh;
+                            if (manager.gizmos.rotationGizmo && manager.gizmos.rotationGizmo.attachedNode) {
+                                var lightGizmo: Nullable<LightGizmo> = manager.gizmos.rotationGizmo.attachedNode.reservedDataStore ? manager.gizmos.rotationGizmo.attachedNode.reservedDataStore.lightGizmo : null;
+                                var objLight: any = (lightGizmo && lightGizmo.light) ? lightGizmo.light : manager.gizmos.rotationGizmo.attachedNode;
+                                var cameraGizmo: Nullable<CameraGizmo> = manager.gizmos.rotationGizmo.attachedNode.reservedDataStore ? manager.gizmos.rotationGizmo.attachedNode.reservedDataStore.cameraGizmo : null;
+                                var objCamera: any = (cameraGizmo && cameraGizmo.camera) ? cameraGizmo.camera : manager.gizmos.rotationGizmo.attachedNode;
 
-                                if (obj.rotationQuaternion) {
+                                if (objLight.rotationQuaternion) {
                                     var e = new PropertyChangedEvent();
-                                    e.object = obj;
+                                    e.object = objLight;
                                     e.property = "rotationQuaternion";
-                                    e.value = obj.rotationQuaternion;
+                                    e.value = objLight.rotationQuaternion;
                                     this.props.globalState.onPropertyChangedObservable.notifyObservers(e);
-                                } else if (obj.rotation) {
+                                } else if (objLight.rotation) {
                                     var e = new PropertyChangedEvent();
-                                    e.object = obj;
+                                    e.object = objLight;
                                     e.property = "rotation";
-                                    e.value = obj.rotation;
+                                    e.value = objLight.rotation;
                                     this.props.globalState.onPropertyChangedObservable.notifyObservers(e);
-                                } else if (obj.direction) {
+                                } else if (objLight.direction) {
                                     var e = new PropertyChangedEvent();
-                                    e.object = obj;
+                                    e.object = objLight;
                                     e.property = "direction";
-                                    e.value = obj.direction;
+                                    e.value = objLight.direction;
+                                    this.props.globalState.onPropertyChangedObservable.notifyObservers(e);
+                                } else if (objCamera.rotationQuaternion) {
+                                    var e = new PropertyChangedEvent();
+                                    e.object = objCamera;
+                                    e.property = "rotationQuaternion";
+                                    e.value = objCamera.rotationQuaternion;
+                                    this.props.globalState.onPropertyChangedObservable.notifyObservers(e);
+                                } else if (objCamera.rotation) {
+                                    var e = new PropertyChangedEvent();
+                                    e.object = objCamera;
+                                    e.property = "rotation";
+                                    e.value = objCamera.rotation;
                                     this.props.globalState.onPropertyChangedObservable.notifyObservers(e);
                                 }
                             }
@@ -318,7 +369,15 @@ export class SceneTreeItemComponent extends React.Component<ISceneTreeItemCompon
                         this.props.globalState.enableLightGizmo(this._selectedEntity, true);
                         this.forceUpdate();
                     }
-                    manager.attachToMesh(this._selectedEntity.reservedDataStore.lightGizmo.attachedMesh);
+                    manager.attachToNode(this._selectedEntity.reservedDataStore.lightGizmo.attachedNode);
+                } else if (className.indexOf("Camera") !== -1) {
+                    if (!this._selectedEntity.reservedDataStore || !this._selectedEntity.reservedDataStore.cameraGizmo) {
+                        this.props.globalState.enableCameraGizmo(this._selectedEntity, true);
+                        this.forceUpdate();
+                    }
+                    manager.attachToNode(this._selectedEntity.reservedDataStore.cameraGizmo.attachedNode);
+                } else if(className.indexOf("Bone") !== -1){
+                    manager.attachToMesh((this._selectedEntity._linkedTransformNode)?this._selectedEntity._linkedTransformNode:this._selectedEntity);
                 }
             }
         }

+ 6 - 2
inspector/src/components/sceneExplorer/sceneExplorer.scss

@@ -402,16 +402,20 @@
         .cameraTools {
             grid-column: 2;
             display: grid;
-            grid-template-columns: 1fr 20px auto 5px;
+            grid-template-columns: 1fr 20px 20px auto 5px;
             align-items: center;
 
             .activeCamera {
                 grid-column: 2;
             }
 
+            .enableGizmo {
+                grid-column: 3;          
+            } 
+
             .extensions {
                 width: 20px;
-                grid-column: 3;
+                grid-column: 4;
             }
         }
 

+ 3 - 3
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -274,7 +274,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                 pipelineContextMenus.push({
                     label: "Add new Default Rendering Pipeline",
                     action: () => {
-                        let newPipeline = new DefaultRenderingPipeline("Default rendering pipeline", true, scene, [scene.activeCamera!]);
+                        let newPipeline = new DefaultRenderingPipeline("Default rendering pipeline", true, scene, scene.cameras);
                         this.props.globalState.onSelectionChangedObservable.notifyObservers(newPipeline);
                     }
                 });
@@ -284,7 +284,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                 pipelineContextMenus.push({
                     label: "Add new SSAO Rendering Pipeline",
                     action: () => {
-                        let newPipeline = new SSAORenderingPipeline("SSAO rendering pipeline", scene, 1, [scene.activeCamera!]);
+                        let newPipeline = new SSAORenderingPipeline("SSAO rendering pipeline", scene, 1, scene.cameras);
                         this.props.globalState.onSelectionChangedObservable.notifyObservers(newPipeline);
                     }
                 });
@@ -294,7 +294,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
                 pipelineContextMenus.push({
                     label: "Add new SSAO2 Rendering Pipeline",
                     action: () => {
-                        let newPipeline = new SSAO2RenderingPipeline("SSAO2 rendering pipeline", scene, 1, [scene.activeCamera!]);
+                        let newPipeline = new SSAO2RenderingPipeline("SSAO2 rendering pipeline", scene, 1, scene.cameras);
                         this.props.globalState.onSelectionChangedObservable.notifyObservers(newPipeline);
                     }
                 });

+ 1 - 1
inspector/src/components/sceneExplorer/treeItemSpecializedComponent.tsx

@@ -96,7 +96,7 @@ export class TreeItemSpecializedComponent extends React.Component<ITreeItemSpeci
             }
 
             if (className.indexOf("Camera") !== -1) {
-                return (<CameraTreeItemComponent extensibilityGroups={this.props.extensibilityGroups} camera={entity as Camera} onClick={() => this.onClick()} />);
+                return (<CameraTreeItemComponent globalState={this.props.globalState} extensibilityGroups={this.props.extensibilityGroups} camera={entity as Camera} onClick={() => this.onClick()} />);
             }
 
             if (className.indexOf("Light", className.length - 5) !== -1) {

+ 5 - 0
inspector/src/inspector.ts

@@ -492,6 +492,11 @@ export class Inspector {
                 this._GlobalState.enableLightGizmo(g.light, false);
             }
         });
+        this._GlobalState.cameraGizmos.forEach((g) => {
+            if (g.camera) {
+                this._GlobalState.enableCameraGizmo(g.camera, false);
+            }
+        });
         if (this._Scene && this._Scene.reservedDataStore && this._Scene.reservedDataStore.gizmoManager) {
             this._Scene.reservedDataStore.gizmoManager.dispose();
             this._Scene.reservedDataStore.gizmoManager = null;

+ 1 - 1
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -194,7 +194,7 @@ export class MSFT_lod implements IGLTFLoaderExtension {
     }
 
     /** @hidden */
-    public _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>> {
+    public _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>> {
         // Don't load material LODs if already loading a node LOD.
         if (this._nodeIndexLOD) {
             return null;

+ 12 - 33
loaders/src/glTF/2.0/glTFLoader.ts

@@ -314,31 +314,8 @@ export class GLTFLoader implements IGLTFLoader {
                     const material = this._gltf.materials[m];
                     const context = "/materials/" + m;
                     const babylonDrawMode = Material.TriangleFillMode;
-                    let babylonData = material._data ? material._data[babylonDrawMode] : null;
 
-                    if (babylonData) {
-                        continue;
-                    }
-
-                    this.logOpen(`${context} ${material.name || ""}`);
-
-                    const babylonMaterial = this.createMaterial(context, material, babylonDrawMode);
-
-                    babylonData = {
-                        babylonMaterial: babylonMaterial,
-                        babylonMeshes: [],
-                        promise: this.loadMaterialPropertiesAsync(context, material, babylonMaterial)
-                    };
-
-                    promises.push(babylonData.promise);
-
-                    material._data = material._data ?? {};
-                    material._data[babylonDrawMode] = babylonData;
-
-                    GLTFLoader.AddPointerMetadata(babylonMaterial, context);
-                    this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
-
-                    this.logClose();
+                    promises.push(this._loadMaterialAsync(context, material, null, babylonDrawMode, (material) => { }));
                 }
             }
 
@@ -1727,7 +1704,7 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     /** @hidden */
-    public _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void = () => { }): Promise<Material> {
+    public _loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void = () => { }): Promise<Material> {
         const extensionPromise = this._extensionsLoadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign);
         if (extensionPromise) {
             return extensionPromise;
@@ -1754,14 +1731,16 @@ export class GLTFLoader implements IGLTFLoader {
             this.logClose();
         }
 
-        babylonData.babylonMeshes.push(babylonMesh);
+        if (babylonMesh) {
+            babylonData.babylonMeshes.push(babylonMesh);
 
-        babylonMesh.onDisposeObservable.addOnce(() => {
-            const index = babylonData.babylonMeshes.indexOf(babylonMesh);
-            if (index !== -1) {
-                babylonData.babylonMeshes.splice(index, 1);
-            }
-        });
+            babylonMesh.onDisposeObservable.addOnce(() => {
+                const index = babylonData.babylonMeshes.indexOf(babylonMesh);
+                if (index !== -1) {
+                    babylonData.babylonMeshes.splice(index, 1);
+                }
+            });
+        }
 
         assign(babylonData.babylonMaterial);
 
@@ -2326,7 +2305,7 @@ export class GLTFLoader implements IGLTFLoader {
         return this._applyExtensions(primitive, "loadMeshPrimitive", (extension) => extension._loadMeshPrimitiveAsync && extension._loadMeshPrimitiveAsync(context, name, node, mesh, primitive, assign));
     }
 
-    private _extensionsLoadMaterialAsync(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>> {
+    private _extensionsLoadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>> {
         return this._applyExtensions(material, "loadMaterial", (extension) => extension._loadMaterialAsync && extension._loadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign));
     }
 

+ 1 - 1
loaders/src/glTF/2.0/glTFLoaderExtension.ts

@@ -82,7 +82,7 @@ export interface IGLTFLoaderExtension extends IGLTFBaseLoaderExtension, IDisposa
      * @param assign A function called synchronously after parsing the glTF properties
      * @returns A promise that resolves with the loaded Babylon material when the load is complete or null if not handled
      */
-    _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
+    _loadMaterialAsync?(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<Material>>;
 
     /**
      * Define this method to modify the default behavior when creating materials.

+ 1 - 1
package.json

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.30",
+    "version": "4.2.0-alpha.32",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 3 - 0
src/Animations/animationGroup.ts

@@ -427,6 +427,9 @@ export class AnimationGroup implements IDisposable {
      */
     public reset(): AnimationGroup {
         if (!this._isStarted) {
+            this.play();
+            this.goToFrame(0);
+            this.stop();
             return this;
         }
 

+ 2 - 1
src/Cameras/Inputs/freeCameraTouchInput.ts

@@ -54,7 +54,8 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
             this._pointerInput = (p) => {
                 var evt = <PointerEvent>p.event;
 
-                if (evt.pointerType === "mouse") {
+                let isMouseEvent = evt instanceof MouseEvent;
+                if (evt.pointerType === "mouse" || isMouseEvent) {
                     return;
                 }
 

+ 18 - 12
src/Debug/rayHelper.ts

@@ -8,6 +8,7 @@ import { Mesh } from "../Meshes/mesh";
 import { LinesMesh } from "../Meshes/linesMesh";
 
 import "../Meshes/Builders/linesBuilder";
+import { Observer } from '../Misc/observable';
 
 /**
  * As raycast might be hard to debug, the RayHelper can help rendering the different rays
@@ -26,7 +27,8 @@ export class RayHelper {
     private _renderFunction: Nullable<() => void>;
     private _scene: Nullable<Scene>;
 
-    private _updateToMeshFunction: Nullable<() => void>;
+    private _onAfterRenderObserver: Nullable<Observer<Scene>>;
+    private _onAfterStepObserver: Nullable<Observer<Scene>>;
     private _attachedToMesh: Nullable<AbstractMesh>;
     private _meshSpaceDirection: Vector3;
     private _meshSpaceOrigin: Vector3;
@@ -72,6 +74,7 @@ export class RayHelper {
             this._scene = scene;
             this._renderPoints = [ray.origin, ray.origin.add(ray.direction.scale(ray.length))];
             this._renderLine = Mesh.CreateLines("ray", this._renderPoints, scene, true);
+            this._renderLine.isPickable = false;
 
             if (this._renderFunction) {
                 this._scene.registerBeforeRender(this._renderFunction);
@@ -160,6 +163,10 @@ export class RayHelper {
             meshSpaceDirection = new Vector3(0, 0, -1);
         }
 
+        if (!this._scene) {
+            this._scene = mesh.getScene();
+        }
+
         if (!this._meshSpaceDirection) {
             this._meshSpaceDirection = meshSpaceDirection.clone();
             this._meshSpaceOrigin = meshSpaceOrigin.clone();
@@ -168,9 +175,9 @@ export class RayHelper {
             this._meshSpaceOrigin.copyFrom(meshSpaceOrigin);
         }
 
-        if (!this._updateToMeshFunction) {
-            this._updateToMeshFunction = (<() => void>this._updateToMesh.bind(this));
-            this._attachedToMesh.getScene().registerBeforeRender(this._updateToMeshFunction);
+        if (!this._onAfterRenderObserver) {
+            this._onAfterRenderObserver = this._scene.onBeforeRenderObservable.add(() => this._updateToMesh());
+            this._onAfterStepObserver = this._scene.onAfterStepObservable.add(() => this._updateToMesh());
         }
 
         // force world matrix computation before the first ray helper computation
@@ -183,19 +190,19 @@ export class RayHelper {
      * Detach the ray helper from the mesh it has previously been attached to.
      */
     public detachFromMesh(): void {
-
-        if (this._attachedToMesh) {
-            if (this._updateToMeshFunction) {
-                this._attachedToMesh.getScene().unregisterBeforeRender(this._updateToMeshFunction);
+        if (this._attachedToMesh && this._scene) {
+            if (this._onAfterRenderObserver) {
+                this._scene.onBeforeRenderObservable.remove(this._onAfterRenderObserver);
+                this._scene.onAfterStepObservable.remove(this._onAfterStepObserver);
             }
             this._attachedToMesh = null;
-            this._updateToMeshFunction = null;
+            this._onAfterRenderObserver = null;
+            this._onAfterStepObserver = null;
+            this._scene = null;
         }
-
     }
 
     private _updateToMesh(): void {
-
         var ray = this.ray;
 
         if (!this._attachedToMesh || !ray) {
@@ -215,7 +222,6 @@ export class RayHelper {
      * Dispose the helper and release its associated resources.
      */
     public dispose(): void {
-
         this.hide();
         this.detachFromMesh();
         this.ray = null;

+ 18 - 0
src/Debug/skeletonViewer.ts

@@ -536,6 +536,24 @@ export class SkeletonViewer {
         }
     }
 
+    /** Changes the displayMode of the skeleton viewer
+     * @param option String of the option name
+     * @param value The numerical option value
+     */
+    public changeDisplayOptions(option: string, value: number): void {
+        let wasEnabled = (this.isEnabled) ? true : false;
+        (this.options.displayOptions as any)[option] = value;
+        this.isEnabled = false;
+        if (this._debugMesh) {
+            this._debugMesh.dispose();
+            this._debugMesh = null;
+            this.ready = false;
+        }
+        this.update();
+        this._bindObs();
+        this.isEnabled = wasEnabled;
+    }
+
     /** Release associated resources */
     public dispose(): void {
         this.isEnabled = false;

+ 11 - 5
src/DeviceInput/deviceInputSystem.ts

@@ -29,7 +29,7 @@ export class DeviceInputSystem implements IDisposable {
     public onInputChanged: (deviceType: DeviceType, deviceSlot: number, inputIndex: number, previousState: Nullable<number>, currentState: Nullable<number>) => void;
 
     // Private Members
-    private _inputs: Array<Array<Array<Nullable<number>>>> = [];
+    private _inputs: Array<Array<Array<number>>> = [];
     private _gamepads: Array<DeviceType>;
     private _keyboardActive: boolean = false;
     private _pointerActive: boolean = false;
@@ -81,13 +81,13 @@ export class DeviceInputSystem implements IDisposable {
      */
 
     /**
-     * Checks for current device input value, given an id and input index
+     * Checks for current device input value, given an id and input index. Throws exception if requested device not initialized.
      * @param deviceType Enum specifiying device type
      * @param deviceSlot "Slot" or index that device is referenced in
      * @param inputIndex Id of input to be checked
      * @returns Current value of input
      */
-    public pollInput(deviceType: DeviceType, deviceSlot: number, inputIndex: number): Nullable<number> {
+    public pollInput(deviceType: DeviceType, deviceSlot: number, inputIndex: number): number {
         const device = this._inputs[deviceType][deviceSlot];
 
         if (!device) {
@@ -138,10 +138,10 @@ export class DeviceInputSystem implements IDisposable {
         }
 
         if (!this._inputs[deviceType][deviceSlot]) {
-            const device = new Array<Nullable<number>>(numberOfInputs);
+            const device = new Array<number>(numberOfInputs);
 
             for (let i = 0; i < numberOfInputs; i++) {
-                device[i] = null;
+                device[i] = 0; /* set device input as unpressed */
             }
 
             this._inputs[deviceType][deviceSlot] = device;
@@ -209,6 +209,9 @@ export class DeviceInputSystem implements IDisposable {
             if (!this._inputs[deviceType][deviceSlot]) {
                 this._pointerActive = true;
                 this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
+                const pointer = this._inputs[deviceType][deviceSlot]; /* initalize our pointer position immediately after registration */
+                pointer[0] = evt.clientX;
+                pointer[1] = evt.clientY;
             }
 
             const pointer = this._inputs[deviceType][deviceSlot];
@@ -233,6 +236,9 @@ export class DeviceInputSystem implements IDisposable {
             if (!this._inputs[deviceType][deviceSlot]) {
                 this._pointerActive = true;
                 this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
+                const pointer = this._inputs[deviceType][deviceSlot]; /* initalize our pointer position immediately after registration */
+                pointer[0] = evt.clientX;
+                pointer[1] = evt.clientY;
             }
 
             const pointer = this._inputs[deviceType][deviceSlot];

+ 73 - 0
src/Engines/Extensions/engine.dynamicBuffer.ts

@@ -0,0 +1,73 @@
+import { ThinEngine } from "../../Engines/thinEngine";
+import { DataBuffer } from '../../Meshes/dataBuffer';
+import { IndicesArray, DataArray } from "../../types";
+
+declare module "../../Engines/thinEngine" {
+    export interface ThinEngine {
+        /**
+         * Update a dynamic index buffer
+         * @param indexBuffer defines the target index buffer
+         * @param indices defines the data to update
+         * @param offset defines the offset in the target index buffer where update should start
+         */
+        updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset?: number): void;
+
+        /**
+         * Updates a dynamic vertex buffer.
+         * @param vertexBuffer the vertex buffer to update
+         * @param data the data used to update the vertex buffer
+         * @param byteOffset the byte offset of the data
+         * @param byteLength the byte length of the data
+         */
+        updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void;
+    }
+}
+
+ThinEngine.prototype.updateDynamicIndexBuffer = function(this: ThinEngine, indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
+    // Force cache update
+    this._currentBoundBuffer[this._gl.ELEMENT_ARRAY_BUFFER] = null;
+    this.bindIndexBuffer(indexBuffer);
+    var arrayBuffer;
+
+    if (indices instanceof Uint16Array || indices instanceof Uint32Array) {
+        arrayBuffer = indices;
+    } else {
+        arrayBuffer = indexBuffer.is32Bits ? new Uint32Array(indices) : new Uint16Array(indices);
+    }
+
+    this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, arrayBuffer, this._gl.DYNAMIC_DRAW);
+
+    this._resetIndexBufferBinding();
+};
+
+ThinEngine.prototype.updateDynamicVertexBuffer = function(this: ThinEngine, vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
+    this.bindArrayBuffer(vertexBuffer);
+
+    if (byteOffset === undefined) {
+        byteOffset = 0;
+    }
+
+    const dataLength = (data as number[]).length || (data as ArrayBuffer).byteLength;
+
+    if (byteLength === undefined || byteLength >= dataLength && byteOffset === 0) {
+        if (data instanceof Array) {
+            this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, new Float32Array(data));
+        } else {
+            this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, <ArrayBuffer>data);
+        }
+    } else {
+        if (data instanceof Array) {
+            this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(data).subarray(byteOffset, byteOffset + byteLength));
+        } else {
+            if (data instanceof ArrayBuffer) {
+                data = new Uint8Array(data, byteOffset, byteLength);
+            } else {
+                data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
+            }
+
+            this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
+        }
+    }
+
+    this._resetVertexBufferBinding();
+};

+ 1 - 0
src/Engines/Extensions/index.ts

@@ -11,6 +11,7 @@ export * from "./engine.renderTarget";
 export * from "./engine.renderTargetCube";
 export * from "./engine.webVR";
 export * from "./engine.uniformBuffer";
+export * from "./engine.dynamicBuffer";
 export * from "./engine.views";
 export * from "./engine.readTexture";
 

+ 2 - 63
src/Engines/engine.ts

@@ -1,5 +1,5 @@
 import { Observable } from "../Misc/observable";
-import { Nullable, IndicesArray, DataArray } from "../types";
+import { Nullable } from "../types";
 import { Scene } from "../scene";
 import { InternalTexture } from "../Materials/Textures/internalTexture";
 import { IAudioEngine } from "../Audio/audioEngine";
@@ -23,6 +23,7 @@ import { Logger } from '../Misc/logger';
 
 import "./Extensions/engine.alpha";
 import "./Extensions/engine.readTexture";
+import "./Extensions/engine.dynamicBuffer";
 
 declare type Material = import("../Materials/material").Material;
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
@@ -1342,45 +1343,6 @@ export class Engine extends ThinEngine {
         return true;
     }
 
-    /**
-     * Updates a dynamic vertex buffer.
-     * @param vertexBuffer the vertex buffer to update
-     * @param data the data used to update the vertex buffer
-     * @param byteOffset the byte offset of the data
-     * @param byteLength the byte length of the data
-     */
-    public updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
-        this.bindArrayBuffer(vertexBuffer);
-
-        if (byteOffset === undefined) {
-            byteOffset = 0;
-        }
-
-        const dataLength = (data as number[]).length || (data as ArrayBuffer).byteLength;
-
-        if (byteLength === undefined || byteLength >= dataLength && byteOffset === 0) {
-            if (data instanceof Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, new Float32Array(data));
-            } else {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, byteOffset, <ArrayBuffer>data);
-            }
-        } else {
-            if (data instanceof Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(data).subarray(byteOffset, byteOffset + byteLength));
-            } else {
-                if (data instanceof ArrayBuffer) {
-                    data = new Uint8Array(data, byteOffset, byteLength);
-                } else {
-                    data = new Uint8Array(data.buffer, data.byteOffset + byteOffset, byteLength);
-                }
-
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, <ArrayBuffer>data);
-            }
-        }
-
-        this._resetVertexBufferBinding();
-    }
-
     public _deletePipelineContext(pipelineContext: IPipelineContext): void {
         let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
         if (webGLPipelineContext && webGLPipelineContext.program) {
@@ -1563,29 +1525,6 @@ export class Engine extends ThinEngine {
     }
 
     /**
-     * Update a dynamic index buffer
-     * @param indexBuffer defines the target index buffer
-     * @param indices defines the data to update
-     * @param offset defines the offset in the target index buffer where update should start
-     */
-    public updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
-        // Force cache update
-        this._currentBoundBuffer[this._gl.ELEMENT_ARRAY_BUFFER] = null;
-        this.bindIndexBuffer(indexBuffer);
-        var arrayBuffer;
-
-        if (indices instanceof Uint16Array || indices instanceof Uint32Array) {
-            arrayBuffer = indices;
-        } else {
-            arrayBuffer = indexBuffer.is32Bits ? new Uint32Array(indices) : new Uint16Array(indices);
-        }
-
-        this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, arrayBuffer, this._gl.DYNAMIC_DRAW);
-
-        this._resetIndexBufferBinding();
-    }
-
-    /**
      * Updates the sample count of a render target texture
      * @see https://doc.babylonjs.com/features/webgl2#multisample-render-targets
      * @param texture defines the texture to update

+ 6 - 3
src/Engines/thinEngine.ts

@@ -142,14 +142,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.2.0-alpha.30";
+        return "babylonjs@4.2.0-alpha.32";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.2.0-alpha.30";
+        return "4.2.0-alpha.32";
     }
 
     /**
@@ -941,7 +941,7 @@ export class ThinEngine {
     }
 
     /**
-     * Gets a string idenfifying the name of the class
+     * Gets a string identifying the name of the class
      * @returns "Engine" string
      */
     public getClassName(): string {
@@ -1563,6 +1563,9 @@ export class ThinEngine {
 
     private _vertexAttribPointer(buffer: DataBuffer, indx: number, size: number, type: number, normalized: boolean, stride: number, offset: number): void {
         var pointer = this._currentBufferPointers[indx];
+        if (!pointer) {
+            return;
+        }
 
         var changed = false;
         if (!pointer.active) {

+ 193 - 0
src/Gizmos/cameraGizmo.ts

@@ -0,0 +1,193 @@
+import { Nullable } from "../types";
+import { Vector3 } from "../Maths/math.vector";
+import { Color3 } from '../Maths/math.color';
+import { Mesh } from "../Meshes/mesh";
+import { Gizmo } from "./gizmo";
+import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
+import { StandardMaterial } from '../Materials/standardMaterial';
+import { Scene } from '../scene';
+import { Camera } from '../Cameras/camera';
+import { BoxBuilder } from "../Meshes/Builders/boxBuilder";
+import { CylinderBuilder } from '../Meshes/Builders/cylinderBuilder';
+import { Matrix } from '../Maths/math';
+import { LinesBuilder } from "../Meshes/Builders/linesBuilder";
+
+/**
+ * Gizmo that enables viewing a camera
+ */
+export class CameraGizmo extends Gizmo {
+    private _cameraMesh: Mesh;
+    private _cameraLinesMesh: Mesh;
+    private _material: StandardMaterial;
+
+    /**
+     * Creates a CameraGizmo
+     * @param gizmoLayer The utility layer the gizmo will be added to
+     */
+    constructor(gizmoLayer?: UtilityLayerRenderer) {
+        super(gizmoLayer);
+
+        this._material = new StandardMaterial("cameraGizmoMaterial", this.gizmoLayer.utilityLayerScene);
+        this._material.diffuseColor = new Color3(0.5, 0.5, 0.5);
+        this._material.specularColor = new Color3(0.1, 0.1, 0.1);
+    }
+    private _camera: Nullable<Camera> = null;
+
+    /** Gets or sets a boolean indicating if frustum lines must be rendered (true by default)) */
+    public get displayFrustum() {
+        return this._cameraLinesMesh.isEnabled();
+    }
+    public set displayFrustum(value) {
+        this._cameraLinesMesh.setEnabled(value);
+    }
+
+    /**
+     * The camera that the gizmo is attached to
+     */
+    public set camera(camera: Nullable<Camera>) {
+        this._camera = camera;
+        this.attachedNode = camera;
+        if (camera) {
+            // Create the mesh for the given camera
+            if (this._cameraMesh) {
+                this._cameraMesh.dispose();
+            }
+            if (this._cameraLinesMesh) {
+                this._cameraLinesMesh.dispose();
+            }
+            this._cameraMesh = CameraGizmo._CreateCameraMesh(this.gizmoLayer.utilityLayerScene);
+            this._cameraLinesMesh = CameraGizmo._CreateCameraFrustum(this.gizmoLayer.utilityLayerScene);
+
+            this._cameraMesh.getChildMeshes(false).forEach((m) => {
+                m.material = this._material;
+            });
+            this._cameraMesh.parent = this._rootMesh;
+
+            this._cameraLinesMesh.parent = this._rootMesh;
+
+            if (this.gizmoLayer.utilityLayerScene.activeCamera && this.gizmoLayer.utilityLayerScene.activeCamera.maxZ < camera.maxZ * 1.5) {
+                this.gizmoLayer.utilityLayerScene.activeCamera.maxZ = camera.maxZ * 1.5;
+            }
+
+            if (!this.attachedNode!.reservedDataStore) {
+                this.attachedNode!.reservedDataStore = {};
+            }
+            this.attachedNode!.reservedDataStore.cameraGizmo = this;
+
+            // Add lighting to the camera gizmo
+            var gizmoLight = this.gizmoLayer._getSharedGizmoLight();
+            gizmoLight.includedOnlyMeshes = gizmoLight.includedOnlyMeshes.concat(this._cameraMesh.getChildMeshes(false));
+
+            this._update();
+        }
+    }
+
+    public get camera() {
+        return this._camera;
+    }
+
+    /**
+     * Gets the material used to render the camera gizmo
+     */
+    public get material() {
+        return this._material;
+    }
+    /**
+     * @hidden
+     * Updates the gizmo to match the attached mesh's position/rotation
+     */
+
+    protected _update() {
+        super._update();
+        if (!this._camera) {
+            return;
+        }
+
+        // frustum matrix
+        this._camera.getProjectionMatrix().invertToRef(this._invProjection);
+        this._cameraLinesMesh.setPivotMatrix(this._invProjection, false);
+
+        this._cameraLinesMesh.scaling.x = 1 / this._rootMesh.scaling.x;
+        this._cameraLinesMesh.scaling.y = 1 / this._rootMesh.scaling.y;
+        this._cameraLinesMesh.scaling.z = 1 / this._rootMesh.scaling.z;
+    }
+
+    // Static helper methods
+    private static _Scale = 0.05;
+    private _invProjection = new Matrix();
+
+    /**
+     * Disposes of the camera gizmo
+     */
+    public dispose() {
+        if (this._cameraMesh) {
+            this._cameraMesh.dispose();
+        }
+        if (this._cameraLinesMesh) {
+            this._cameraLinesMesh.dispose();
+        }
+        this._material.dispose();
+        super.dispose();
+    }
+
+    private static _CreateCameraMesh(scene: Scene) {
+        var root = new Mesh("rootCameraGizmo", scene);
+
+        var mesh = new Mesh(root.name, scene);
+        mesh.parent = root;
+
+        var box = BoxBuilder.CreateBox(root.name, {width: 1.0, height: 0.8, depth: 0.5 }, scene);
+        box.parent = mesh;
+
+        var cyl1 = CylinderBuilder.CreateCylinder(root.name, {height: 0.5, diameterTop: 0.8, diameterBottom: 0.8}, scene);
+        cyl1.parent = mesh;
+        cyl1.position.y = 0.3;
+        cyl1.position.x = -0.6;
+        cyl1.rotation.x = Math.PI * 0.5;
+
+        var cyl2 = CylinderBuilder.CreateCylinder(root.name, {height: 0.5, diameterTop: 0.6, diameterBottom: 0.6}, scene);
+        cyl2.parent = mesh;
+        cyl2.position.y = 0.5;
+        cyl2.position.x = 0.4;
+        cyl2.rotation.x = Math.PI * 0.5;
+
+        var cyl3 = CylinderBuilder.CreateCylinder(root.name, {height: 0.5, diameterTop: 0.5, diameterBottom: 0.5}, scene);
+        cyl3.parent = mesh;
+        cyl3.position.y = 0.0;
+        cyl3.position.x = 0.6;
+        cyl3.rotation.z = Math.PI * 0.5;
+
+        root.scaling.scaleInPlace(CameraGizmo._Scale);
+        root.rotation.y = -Math.PI * 0.5;
+        mesh.position.x = -0.9;
+
+        return root;
+    }
+
+    private static _CreateCameraFrustum(scene: Scene) {
+        var root = new Mesh("rootCameraGizmo", scene);
+        var mesh = new Mesh(root.name, scene);
+        mesh.parent = root;
+
+        for (var y = 0; y < 4; y += 2)
+        {
+            for (var x = 0; x < 4; x += 2)
+            {
+                var line = LinesBuilder.CreateLines("lines", { points: [new Vector3(-1 + x, -1 + y, -1), new Vector3(-1 + x, -1 + y, 1)] }, scene);
+                line.parent = mesh;
+                line.alwaysSelectAsActiveMesh = true;
+                line.isPickable = false;
+                var line = LinesBuilder.CreateLines("lines", { points: [new Vector3(-1, -1 + x, -1 + y), new Vector3(1, -1 + x, -1 + y)] }, scene);
+                line.parent = mesh;
+                line.alwaysSelectAsActiveMesh = true;
+                line.isPickable = false;
+                var line = LinesBuilder.CreateLines("lines", { points: [new Vector3(-1 + x, -1, -1 + y), new Vector3(-1 + x,  1, -1 + y)] }, scene);
+                line.parent = mesh;
+                line.alwaysSelectAsActiveMesh = true;
+                line.isPickable = false;
+            }
+        }
+
+        return root;
+    }
+}

+ 72 - 10
src/Gizmos/gizmoManager.ts

@@ -15,20 +15,27 @@ import { ScaleGizmo } from "./scaleGizmo";
 import { BoundingBoxGizmo } from "./boundingBoxGizmo";
 
 /**
- * Helps setup gizmo's in the scene to rotate/scale/position meshes
+ * Helps setup gizmo's in the scene to rotate/scale/position nodes
  */
 export class GizmoManager implements IDisposable {
     /**
      * Gizmo's created by the gizmo manager, gizmo will be null until gizmo has been enabled for the first time
      */
     public gizmos: { positionGizmo: Nullable<PositionGizmo>, rotationGizmo: Nullable<RotationGizmo>, scaleGizmo: Nullable<ScaleGizmo>, boundingBoxGizmo: Nullable<BoundingBoxGizmo> };
+
     /** When true, the gizmo will be detached from the current object when a pointer down occurs with an empty picked mesh */
     public clearGizmoOnEmptyPointerEvent = false;
+
     /** Fires an event when the manager is attached to a mesh */
     public onAttachedToMeshObservable = new Observable<Nullable<AbstractMesh>>();
+
+    /** Fires an event when the manager is attached to a node */
+    public onAttachedToNodeObservable = new Observable<Nullable<Node>>();
+
     private _gizmosEnabled = { positionGizmo: false, rotationGizmo: false, scaleGizmo: false, boundingBoxGizmo: false };
     private _pointerObserver: Nullable<Observer<PointerInfo>> = null;
     private _attachedMesh: Nullable<AbstractMesh> = null;
+    private _attachedNode: Nullable<Node> = null;
     private _boundingBoxColor = Color3.FromHexString("#0984e3");
     private _defaultUtilityLayer: UtilityLayerRenderer;
     private _defaultKeepDepthUtilityLayer: UtilityLayerRenderer;
@@ -42,7 +49,11 @@ export class GizmoManager implements IDisposable {
      */
     public attachableMeshes: Nullable<Array<AbstractMesh>> = null;
     /**
-     * If pointer events should perform attaching/detaching a gizmo, if false this can be done manually via attachToMesh. (Default: true)
+     * Array of nodes which will have the gizmo attached when a pointer selected them. If null, all nodes are attachable. (Default: null)
+     */
+    public attachableNodes: Nullable<Array<Node>> = null;
+    /**
+     * If pointer events should perform attaching/detaching a gizmo, if false this can be done manually via attachToMesh/attachToNode. (Default: true)
      */
     public usePointerToAttachGizmos = true;
 
@@ -124,7 +135,11 @@ export class GizmoManager implements IDisposable {
         if (this._attachedMesh) {
             this._attachedMesh.removeBehavior(this.boundingBoxDragBehavior);
         }
+        if (this._attachedNode) {
+            this._attachedNode.removeBehavior(this.boundingBoxDragBehavior);
+        }
         this._attachedMesh = mesh;
+        this._attachedNode = null;
         for (var key in this.gizmos) {
             var gizmo = <Nullable<Gizmo>>((<any>this.gizmos)[key]);
             if (gizmo && (<any>this._gizmosEnabled)[key]) {
@@ -138,6 +153,31 @@ export class GizmoManager implements IDisposable {
     }
 
     /**
+     * Attaches a set of gizmos to the specified node
+     * @param node The node the gizmo's should be attached to
+     */
+    public attachToNode(node: Nullable<Node>) {
+        if (this._attachedMesh) {
+            this._attachedMesh.removeBehavior(this.boundingBoxDragBehavior);
+        }
+        if (this._attachedNode) {
+            this._attachedNode.removeBehavior(this.boundingBoxDragBehavior);
+        }
+        this._attachedMesh = null;
+        this._attachedNode = node;
+        for (var key in this.gizmos) {
+            var gizmo = <Nullable<Gizmo>>((<any>this.gizmos)[key]);
+            if (gizmo && (<any>this._gizmosEnabled)[key]) {
+                gizmo.attachedNode = node;
+            }
+        }
+        if (this.boundingBoxGizmoEnabled && this._attachedNode) {
+            this._attachedNode.addBehavior(this.boundingBoxDragBehavior);
+        }
+        this.onAttachedToNodeObservable.notifyObservers(node);
+    }
+
+    /**
      * If the position gizmo is enabled
      */
     public set positionGizmoEnabled(value: boolean) {
@@ -145,9 +185,13 @@ export class GizmoManager implements IDisposable {
             if (!this.gizmos.positionGizmo) {
                 this.gizmos.positionGizmo = new PositionGizmo(this._defaultUtilityLayer, this._thickness);
             }
-            this.gizmos.positionGizmo.attachedMesh = this._attachedMesh;
+            if (this._attachedNode) {
+                this.gizmos.positionGizmo.attachedNode = this._attachedNode;
+            } else {
+                this.gizmos.positionGizmo.attachedMesh = this._attachedMesh;
+            }
         } else if (this.gizmos.positionGizmo) {
-            this.gizmos.positionGizmo.attachedMesh = null;
+            this.gizmos.positionGizmo.attachedNode = null;
         }
         this._gizmosEnabled.positionGizmo = value;
     }
@@ -162,9 +206,13 @@ export class GizmoManager implements IDisposable {
             if (!this.gizmos.rotationGizmo) {
                 this.gizmos.rotationGizmo = new RotationGizmo(this._defaultUtilityLayer, 32, false, this._thickness);
             }
-            this.gizmos.rotationGizmo.attachedMesh = this._attachedMesh;
+            if (this._attachedNode) {
+                this.gizmos.rotationGizmo.attachedNode = this._attachedNode;
+            } else {
+                this.gizmos.rotationGizmo.attachedMesh = this._attachedMesh;
+            }
         } else if (this.gizmos.rotationGizmo) {
-            this.gizmos.rotationGizmo.attachedMesh = null;
+            this.gizmos.rotationGizmo.attachedNode = null;
         }
         this._gizmosEnabled.rotationGizmo = value;
     }
@@ -177,9 +225,13 @@ export class GizmoManager implements IDisposable {
     public set scaleGizmoEnabled(value: boolean) {
         if (value) {
             this.gizmos.scaleGizmo = this.gizmos.scaleGizmo || new ScaleGizmo(this._defaultUtilityLayer, this._thickness);
-            this.gizmos.scaleGizmo.attachedMesh = this._attachedMesh;
+            if (this._attachedNode) {
+                this.gizmos.scaleGizmo.attachedNode = this._attachedNode;
+            } else {
+                this.gizmos.scaleGizmo.attachedMesh = this._attachedMesh;
+            }
         } else if (this.gizmos.scaleGizmo) {
-            this.gizmos.scaleGizmo.attachedMesh = null;
+            this.gizmos.scaleGizmo.attachedNode = null;
         }
         this._gizmosEnabled.scaleGizmo = value;
     }
@@ -192,16 +244,26 @@ export class GizmoManager implements IDisposable {
     public set boundingBoxGizmoEnabled(value: boolean) {
         if (value) {
             this.gizmos.boundingBoxGizmo = this.gizmos.boundingBoxGizmo || new BoundingBoxGizmo(this._boundingBoxColor, this._defaultKeepDepthUtilityLayer);
-            this.gizmos.boundingBoxGizmo.attachedMesh = this._attachedMesh;
+            if (this._attachedMesh) {
+                this.gizmos.boundingBoxGizmo.attachedMesh = this._attachedMesh;
+            } else {
+                this.gizmos.boundingBoxGizmo.attachedNode = this._attachedNode;
+            }
+
             if (this._attachedMesh) {
                 this._attachedMesh.removeBehavior(this.boundingBoxDragBehavior);
                 this._attachedMesh.addBehavior(this.boundingBoxDragBehavior);
+            } else if (this._attachedNode) {
+                this._attachedNode.removeBehavior(this.boundingBoxDragBehavior);
+                this._attachedNode.addBehavior(this.boundingBoxDragBehavior);
             }
         } else if (this.gizmos.boundingBoxGizmo) {
             if (this._attachedMesh) {
                 this._attachedMesh.removeBehavior(this.boundingBoxDragBehavior);
+            } else if (this._attachedNode) {
+                this._attachedNode.removeBehavior(this.boundingBoxDragBehavior);
             }
-            this.gizmos.boundingBoxGizmo.attachedMesh = null;
+            this.gizmos.boundingBoxGizmo.attachedNode = null;
         }
         this._gizmosEnabled.boundingBoxGizmo = value;
     }

+ 1 - 0
src/Gizmos/index.ts

@@ -8,4 +8,5 @@ export * from "./positionGizmo";
 export * from "./rotationGizmo";
 export * from "./scaleGizmo";
 export * from "./lightGizmo";
+export * from "./cameraGizmo";
 export * from "./planeDragGizmo";

+ 2 - 1
src/LibDeclarations/webxr.d.ts

@@ -185,7 +185,8 @@ declare class XRRay {
 
 declare enum XRHitTestTrackableType {
     "point",
-    "plane"
+    "plane",
+    "mesh"
 }
 
 interface XRHitResult {

+ 14 - 0
src/Loading/Plugins/babylonFileLoader.ts

@@ -29,6 +29,7 @@ import { ReflectionProbe } from "../../Probes/reflectionProbe";
 import { _TypeStore } from '../../Misc/typeStore';
 import { Tools } from '../../Misc/tools';
 import { StringTools } from '../../Misc/stringTools';
+import { PostProcess } from '../../PostProcesses/postProcess';
 
 /** @hidden */
 export var _BabylonLoaderRegistered = true;
@@ -315,6 +316,19 @@ var loadAssetContainer = (scene: Scene, data: string, rootUrl: string, onError?:
             }
         }
 
+        // Postprocesses
+        if (parsedData.postProcesses !== undefined && parsedData.postProcesses !== null) {
+            for (index = 0, cache = parsedData.postProcesses.length; index < cache; index++) {
+                var parsedPostProcess = parsedData.postProcesses[index];
+                var postProcess = PostProcess.Parse(parsedPostProcess, scene, rootUrl);
+                if (postProcess) {
+                    container.postProcesses.push(postProcess);
+                    log += (index === 0 ? "\n\Postprocesses:" : "");
+                    log += "\n\t\t" + postProcess.toString();
+                }
+            }
+        }
+
         // Animation Groups
         if (parsedData.animationGroups !== undefined && parsedData.animationGroups !== null) {
             for (index = 0, cache = parsedData.animationGroups.length; index < cache; index++) {

+ 2 - 1
src/Materials/Textures/rawTexture.ts

@@ -1,10 +1,11 @@
-import { Scene } from "../../scene";
 import { Texture } from "./texture";
 import { Constants } from "../../Engines/constants";
 import "../../Engines/Extensions/engine.rawTexture";
 import { Nullable } from '../../types';
 import { ThinEngine } from '../../Engines/thinEngine';
 
+declare type Scene = import("../../scene").Scene;
+
 /**
  * Raw texture can help creating a texture directly from an array of data.
  * This can be super useful if you either get the data from an uncompressed source or

+ 1 - 0
src/Materials/index.ts

@@ -7,6 +7,7 @@ export * from "./fresnelParameters";
 export * from "./imageProcessingConfiguration";
 export * from "./material";
 export * from "./materialDefines";
+export * from "./thinMaterialHelper";
 export * from "./materialHelper";
 export * from "./multiMaterial";
 export * from "./PBR/index";

+ 3 - 26
src/Materials/materialHelper.ts

@@ -16,10 +16,10 @@ import { WebVRFreeCamera } from '../Cameras/VR/webVRCamera';
 import { MaterialDefines } from "./materialDefines";
 import { Color3 } from '../Maths/math.color';
 import { EffectFallbacks } from './effectFallbacks';
+import { ThinMaterialHelper } from './thinMaterialHelper';
 
 /**
- * "Static Class" containing the most commonly used helper while dealing with material for
- * rendering purpose.
+ * "Static Class" containing the most commonly used helper while dealing with material for rendering purpose.
  *
  * It contains the basic tools to help defining defines, binding uniform for the common part of the materials.
  *
@@ -835,29 +835,6 @@ export class MaterialHelper {
      * @param effect The effect we are binding the data to
      */
     public static BindClipPlane(effect: Effect, scene: Scene): void {
-        if (scene.clipPlane) {
-            let clipPlane = scene.clipPlane;
-            effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
-        if (scene.clipPlane2) {
-            let clipPlane = scene.clipPlane2;
-            effect.setFloat4("vClipPlane2", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
-        if (scene.clipPlane3) {
-            let clipPlane = scene.clipPlane3;
-            effect.setFloat4("vClipPlane3", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
-        if (scene.clipPlane4) {
-            let clipPlane = scene.clipPlane4;
-            effect.setFloat4("vClipPlane4", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
-        if (scene.clipPlane5) {
-            let clipPlane = scene.clipPlane5;
-            effect.setFloat4("vClipPlane5", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
-        if (scene.clipPlane6) {
-            let clipPlane = scene.clipPlane6;
-            effect.setFloat4("vClipPlane6", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-        }
+        ThinMaterialHelper.BindClipPlane(effect, scene);
     }
 }

+ 43 - 0
src/Materials/thinMaterialHelper.ts

@@ -0,0 +1,43 @@
+import { Effect } from './effect';
+import { IClipPlanesHolder } from '../Misc/interfaces/iClipPlanesHolder';
+
+/**
+ * "Static Class" containing a few commonly used helper while dealing with material for rendering purpose.
+ *
+ * It is complementary with MaterialHelper but provides completely independent functions (for tree shaking sake)
+ *
+ * This works by convention in BabylonJS but is meant to be use only with shader following the in place naming rules and conventions.
+ */
+export class ThinMaterialHelper {
+    /**
+     * Binds the clip plane information from the holder to the effect.
+     * @param effect The effect we are binding the data to
+     * @param holder The entity containing the clip plane information
+     */
+    public static BindClipPlane(effect: Effect, holder: IClipPlanesHolder): void {
+        if (holder.clipPlane) {
+            let clipPlane = holder.clipPlane;
+            effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+        if (holder.clipPlane2) {
+            let clipPlane = holder.clipPlane2;
+            effect.setFloat4("vClipPlane2", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+        if (holder.clipPlane3) {
+            let clipPlane = holder.clipPlane3;
+            effect.setFloat4("vClipPlane3", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+        if (holder.clipPlane4) {
+            let clipPlane = holder.clipPlane4;
+            effect.setFloat4("vClipPlane4", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+        if (holder.clipPlane5) {
+            let clipPlane = holder.clipPlane5;
+            effect.setFloat4("vClipPlane5", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+        if (holder.clipPlane6) {
+            let clipPlane = holder.clipPlane6;
+            effect.setFloat4("vClipPlane6", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+        }
+    }
+}

+ 2 - 2
src/Meshes/buffer.ts

@@ -1,12 +1,12 @@
 import { Nullable, DataArray } from "../types";
-import { Engine } from "../Engines/engine";
+import { ThinEngine } from "../Engines/thinEngine";
 import { DataBuffer } from './dataBuffer';
 
 /**
  * Class used to store data that will be store in GPU memory
  */
 export class Buffer {
-    private _engine: Engine;
+    private _engine: ThinEngine;
     private _buffer: Nullable<DataBuffer>;
     /** @hidden */
     public _data: Nullable<DataArray>;

+ 14 - 0
src/Meshes/instancedMesh.ts

@@ -11,6 +11,7 @@ import { DeepCopier } from "../Misc/deepCopier";
 import { TransformNode } from './transformNode';
 import { Light } from '../Lights/light';
 import { VertexBuffer } from './buffer';
+import { BoundingInfo } from '../Culling/boundingInfo';
 
 Mesh._instancedMeshFactory = (name: string, mesh: Mesh): InstancedMesh => {
     let instance = new InstancedMesh(name, mesh);
@@ -409,6 +410,19 @@ export class InstancedMesh extends AbstractMesh {
         return this._sourceMesh._generatePointsArray();
     }
 
+    /** @hidden */
+    public _updateBoundingInfo(): AbstractMesh {
+        const effectiveMesh = this as AbstractMesh;
+        if (this._boundingInfo) {
+            this._boundingInfo.update(effectiveMesh.worldMatrixFromCache);
+        }
+        else {
+            this._boundingInfo = new BoundingInfo(this.absolutePosition, this.absolutePosition, effectiveMesh.worldMatrixFromCache);
+        }
+        this._updateSubMeshesBoundingInfo(effectiveMesh.worldMatrixFromCache);
+        return this;
+    }
+
     /**
      * Creates a new InstancedMesh from the current mesh.
      * - name (string) : the cloned mesh name

+ 37 - 0
src/Misc/interfaces/iClipPlanesHolder.ts

@@ -0,0 +1,37 @@
+import { Nullable } from '../../types';
+import { Plane } from '../../Maths/math';
+
+/**
+ * Interface used to define entities containing multiple clip planes
+ */
+export interface IClipPlanesHolder {
+    /**
+     * Gets or sets the active clipplane 1
+     */
+    clipPlane: Nullable<Plane>;
+
+    /**
+     * Gets or sets the active clipplane 2
+     */
+    clipPlane2: Nullable<Plane>;
+
+    /**
+     * Gets or sets the active clipplane 3
+     */
+    clipPlane3: Nullable<Plane>;
+
+    /**
+     * Gets or sets the active clipplane 4
+     */
+    clipPlane4: Nullable<Plane>;
+
+    /**
+     * Gets or sets the active clipplane 5
+     */
+    clipPlane5: Nullable<Plane>;
+
+    /**
+     * Gets or sets the active clipplane 6
+     */
+    clipPlane6: Nullable<Plane>;
+}

+ 6 - 2
src/Misc/sceneRecorder.ts

@@ -11,6 +11,7 @@ import { TransformNode } from '../Meshes/transformNode';
 import { ParticleSystem } from '../Particles/particleSystem';
 import { MorphTargetManager } from '../Morph/morphTargetManager';
 import { ShadowGenerator } from '../Lights/Shadows/shadowGenerator';
+import { PostProcess } from '../PostProcesses/postProcess';
 
 /**
  * Class used to record delta files between 2 scene states
@@ -89,7 +90,7 @@ export class SceneRecorder {
                         deltaJSON[key] = [];
                     }
                     newObject.__state = {
-                        id: currentObject.id
+                        id: currentObject.id || currentObject.name
                     };
                     deltaJSON[key].push(newObject);
                 }
@@ -97,7 +98,7 @@ export class SceneRecorder {
                 // We need to delete
                 let newObject: any = {
                     __state: {
-                        deleteId: originalObject.id
+                        deleteId: originalObject.id || originalObject.name
                     }
                 };
                 deltaJSON[key].push(newObject);
@@ -231,6 +232,9 @@ export class SceneRecorder {
                     case "morphTargetManagers":
                         this._ApplyDeltaForEntity(source, scene, scene.getMorphTargetById.bind(scene), (data) => MorphTargetManager.Parse(data, scene));
                         break;
+                    case "postProcesses":
+                        this._ApplyDeltaForEntity(source, scene, scene.getPostProcessByName.bind(scene), (data) => PostProcess.Parse(data, scene, ""));
+                        break;
                 }
             } else if (!isNaN(property)) {
                 anyScene[prop] = source;

+ 6 - 0
src/Misc/sceneSerializer.ts

@@ -296,6 +296,12 @@ export class SceneSerializer {
             serializationObject.particleSystems.push(scene.particleSystems[index].serialize(false));
         }
 
+        // Post processes
+        serializationObject.postProcesses = [];
+        for (index = 0; index < scene.postProcesses.length; index++) {
+            serializationObject.postProcesses.push(scene.postProcesses[index].serialize());
+        }
+
         // Action Manager
         if (scene.actionManager) {
             serializationObject.actions = scene.actionManager.serialize("scene");

+ 6 - 4
src/Particles/baseParticleSystem.ts

@@ -2,17 +2,19 @@ import { Nullable } from "../types";
 import { Vector2, Vector3 } from "../Maths/math.vector";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { ImageProcessingConfiguration, ImageProcessingConfigurationDefines } from "../Materials/imageProcessingConfiguration";
-import { ProceduralTexture } from "../Materials/Textures/Procedurals/proceduralTexture";
-import { RawTexture } from "../Materials/Textures/rawTexture";
 import { ColorGradient, FactorGradient, Color3Gradient, IValueGradient } from "../Misc/gradients";
 import { BoxParticleEmitter, IParticleEmitterType, PointParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, CylinderDirectedParticleEmitter, ConeParticleEmitter } from "../Particles/EmitterTypes/index";
 import { Constants } from "../Engines/constants";
-import { Texture } from '../Materials/Textures/texture';
+import { BaseTexture } from '../Materials/Textures/baseTexture';
 import { Color4 } from '../Maths/math.color';
 import { ThinEngine } from '../Engines/thinEngine';
 
+import "../Engines/Extensions/engine.dynamicBuffer";
+
 declare type Animation = import("../Animations/animation").Animation;
 declare type Scene = import("../scene").Scene;
+declare type ProceduralTexture = import("../Materials/Textures/Procedurals/proceduralTexture").ProceduralTexture;
+declare type RawTexture = import("../Materials/Textures/rawTexture").RawTexture;
 
 /**
  * This represents the base class for particle system in Babylon.
@@ -169,7 +171,7 @@ export class BaseParticleSystem {
     /**
      * The texture used to render each particle. (this can be a spritesheet)
      */
-    public particleTexture: Nullable<Texture>;
+    public particleTexture: Nullable<BaseTexture>;
 
     /**
      * The layer mask we are rendering the particles through.

+ 2 - 2
src/Particles/gpuParticleSystem.ts

@@ -709,9 +709,9 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
     }>, sceneOrEngine: Scene | ThinEngine, isAnimationSheetEnabled: boolean = false, customEffect: Nullable<Effect> = null) {
         super(name);
 
-        if (sceneOrEngine.getClassName() === "Scene") {
+        if (!sceneOrEngine || sceneOrEngine.getClassName() === "Scene") {
             this._scene = (sceneOrEngine as Scene) || EngineStore.LastCreatedScene;
-            this._engine = this._engine;
+            this._engine = this._scene.getEngine();
             this.uniqueId = this._scene.getUniqueId();
             this._scene.particleSystems.push(this);
         } else {

+ 10 - 7
src/Particles/particleSystem.ts

@@ -5,7 +5,6 @@ import { Vector3, Matrix, TmpVectors, Vector4 } from "../Maths/math.vector";
 import { Scalar } from "../Maths/math.scalar";
 import { VertexBuffer } from "../Meshes/buffer";
 import { Buffer } from "../Meshes/buffer";
-import { MaterialHelper } from "../Materials/materialHelper";
 import { Effect } from "../Materials/effect";
 import { ImageProcessingConfiguration } from "../Materials/imageProcessingConfiguration";
 import { RawTexture } from "../Materials/Textures/rawTexture";
@@ -28,10 +27,12 @@ import { Color4, Color3, TmpColors } from '../Maths/math.color';
 import { ISize } from '../Maths/math.size';
 import { BaseTexture } from '../Materials/Textures/baseTexture';
 import { ThinEngine } from '../Engines/thinEngine';
+import { ThinMaterialHelper } from '../Materials/thinMaterialHelper';
+
+import "../Engines/Extensions/engine.alpha";
 
 declare type AbstractMesh = import("../Meshes/abstractMesh").AbstractMesh;
 declare type ProceduralTexture = import("../Materials/Textures/Procedurals/proceduralTexture").ProceduralTexture;
-
 declare type Scene = import("../scene").Scene;
 
 /**
@@ -143,6 +144,9 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
     /** Gets or sets a matrix to use to compute projection */
     public defaultProjectionMatrix: Matrix;
 
+    /** Gets or sets a matrix to use to compute view */
+    public defaultViewMatrix: Matrix;
+
     /** Gets or sets a boolean indicating that ramp gradients must be used
      * @see https://doc.babylonjs.com/babylon101/particles#ramp-gradients
      */
@@ -1888,7 +1892,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
         // Render
         engine.enableEffect(effect);
 
-        var viewMatrix = this._scene?.getViewMatrix() || Matrix.IdentityReadOnly;
+        var viewMatrix = this.defaultViewMatrix ?? this._scene!.getViewMatrix();
         effect.setTexture("diffuseSampler", this.particleTexture);
         effect.setMatrix("view", viewMatrix);
         effect.setMatrix("projection", this.defaultProjectionMatrix ?? this._scene!.getProjectionMatrix());
@@ -1918,14 +1922,13 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
         if (this._scene) {
             if (this._scene.clipPlane || this._scene.clipPlane2 || this._scene.clipPlane3 || this._scene.clipPlane4 || this._scene.clipPlane5 || this._scene.clipPlane6) {
-                MaterialHelper.BindClipPlane(effect, this._scene);
+                ThinMaterialHelper.BindClipPlane(effect, this._scene);
             }
         }
 
         if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
-            var invView = viewMatrix.clone();
-            invView.invert();
-            effect.setMatrix("invView", invView);
+            viewMatrix.invertToRef(TmpVectors.Matrix[0]);
+            effect.setMatrix("invView", TmpVectors.Matrix[0]);
         }
 
         engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);

+ 11 - 0
src/PostProcesses/anaglyphPostProcess.ts

@@ -5,6 +5,7 @@ import { Camera } from "../Cameras/camera";
 import { Effect } from "../Materials/effect";
 
 import "../Shaders/anaglyph.fragment";
+import { _TypeStore } from '../Misc/typeStore';
 
 /**
  * Postprocess used to generate anaglyphic rendering
@@ -13,6 +14,14 @@ export class AnaglyphPostProcess extends PostProcess {
     private _passedProcess: Nullable<PostProcess>;
 
     /**
+     * Gets a string identifying the name of the class
+     * @returns "AnaglyphPostProcess" string
+     */
+    public getClassName(): string {
+        return "AnaglyphPostProcess";
+    }
+
+    /**
      * Creates a new AnaglyphPostProcess
      * @param name defines postprocess name
      * @param options defines creation options or target ratio scale
@@ -30,3 +39,5 @@ export class AnaglyphPostProcess extends PostProcess {
         });
     }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.AnaglyphPostProcess"] = AnaglyphPostProcess;

+ 26 - 0
src/PostProcesses/blackAndWhitePostProcess.ts

@@ -4,6 +4,11 @@ import { Effect } from "../Materials/effect";
 import { Engine } from "../Engines/engine";
 
 import "../Shaders/blackAndWhite.fragment";
+import { _TypeStore } from '../Misc/typeStore';
+import { serialize, SerializationHelper } from '../Misc/decorators';
+import { Nullable } from '../types';
+
+declare type Scene = import("../scene").Scene;
 
 /**
  * Post process used to render in black and white
@@ -12,9 +17,18 @@ export class BlackAndWhitePostProcess extends PostProcess {
     /**
      * Linear about to convert he result to black and white (default: 1)
      */
+    @serialize()
     public degree = 1;
 
     /**
+     * Gets a string identifying the name of the class
+     * @returns "BlackAndWhitePostProcess" string
+     */
+    public getClassName(): string {
+        return "BlackAndWhitePostProcess";
+    }
+
+    /**
      * Creates a black and white post process
      * @see https://doc.babylonjs.com/how_to/how_to_use_postprocesses#black-and-white
      * @param name The name of the effect.
@@ -31,4 +45,16 @@ export class BlackAndWhitePostProcess extends PostProcess {
             effect.setFloat("degree", this.degree);
         });
     }
+
+    /** @hidden */
+    public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string): Nullable<BlackAndWhitePostProcess> {
+        return SerializationHelper.Parse(() => {
+            return new BlackAndWhitePostProcess(
+                parsedPostProcess.name, parsedPostProcess.options,
+                targetCamera, parsedPostProcess.renderTargetSamplingMode,
+                scene.getEngine(), parsedPostProcess.reusable);
+        }, parsedPostProcess, scene, rootUrl);
+    }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.BlackAndWhitePostProcess"] = BlackAndWhitePostProcess;

+ 18 - 1
src/PostProcesses/bloomMergePostProcess.ts

@@ -6,11 +6,25 @@ import { Camera } from "../Cameras/camera";
 import { Constants } from "../Engines/constants";
 
 import "../Shaders/bloomMerge.fragment";
+import { _TypeStore } from '../Misc/typeStore';
+import { serialize } from '../Misc/decorators';
 
 /**
  * The BloomMergePostProcess merges blurred images with the original based on the values of the circle of confusion.
  */
 export class BloomMergePostProcess extends PostProcess {
+    /** Weight of the bloom to be added to the original input. */
+    @serialize()
+    public weight = 1;
+
+    /**
+     * Gets a string identifying the name of the class
+     * @returns "BloomMergePostProcess" string
+     */
+    public getClassName(): string {
+        return "BloomMergePostProcess";
+    }
+
     /**
      * Creates a new instance of @see BloomMergePostProcess
      * @param name The name of the effect.
@@ -27,10 +41,11 @@ export class BloomMergePostProcess extends PostProcess {
      */
     constructor(name: string, originalFromInput: PostProcess, blurred: PostProcess,
         /** Weight of the bloom to be added to the original input. */
-        public weight: number,
+        weight: number,
         options: number | PostProcessOptions,
         camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
         super(name, "bloomMerge", ["bloomWeight"], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2", "bloomBlur"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
+        this.weight = weight;
         this.onApplyObservable.add((effect: Effect) => {
             effect.setTextureFromPostProcess("textureSampler", originalFromInput);
             effect.setTextureFromPostProcessOutput("bloomBlur", blurred);
@@ -42,3 +57,5 @@ export class BloomMergePostProcess extends PostProcess {
         }
     }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.BloomMergePostProcess"] = BloomMergePostProcess;

+ 33 - 2
src/PostProcesses/blurPostProcess.ts

@@ -9,16 +9,27 @@ import { Constants } from "../Engines/constants";
 
 import "../Shaders/kernelBlur.fragment";
 import "../Shaders/kernelBlur.vertex";
+import { _TypeStore } from '../Misc/typeStore';
+import { serialize, serializeAsVector2, SerializationHelper } from '../Misc/decorators';
+
+declare type Scene = import("../scene").Scene;
 
 /**
  * The Blur Post Process which blurs an image based on a kernel and direction.
  * Can be used twice in x and y directions to perform a guassian blur in two passes.
  */
 export class BlurPostProcess extends PostProcess {
+    @serialize("kernel")
     protected _kernel: number;
     protected _idealKernel: number;
+    @serialize("packedFloat")
     protected _packedFloat: boolean = false;
     private _staticDefines: string = "";
+
+    /** The direction in which to blur the image. */
+    @serializeAsVector2()
+    public direction: Vector2;
+
     /**
      * Sets the length in pixels of the blur sample region
      */
@@ -63,6 +74,14 @@ export class BlurPostProcess extends PostProcess {
     }
 
     /**
+     * Gets a string identifying the name of the class
+     * @returns "BlurPostProcess" string
+     */
+    public getClassName(): string {
+        return "BlurPostProcess";
+    }
+
+    /**
      * Creates a new instance BlurPostProcess
      * @param name The name of the effect.
      * @param direction The direction in which to blur the image.
@@ -76,11 +95,11 @@ export class BlurPostProcess extends PostProcess {
      * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
      */
     constructor(name: string,
-        /** The direction in which to blur the image. */
-        public direction: Vector2,
+        direction: Vector2,
         kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, defines = "", private blockCompilation = false) {
         super(name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["circleOfConfusionSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", { varyingCount: 0, depCount: 0 }, true);
         this._staticDefines = defines;
+        this.direction = direction;
         this.onApplyObservable.add((effect: Effect) => {
             if (this._outputTexture) {
                 effect.setFloat2('delta', (1 / this._outputTexture.width) * this.direction.x, (1 / this._outputTexture.height) * this.direction.y);
@@ -254,4 +273,16 @@ export class BlurPostProcess extends PostProcess {
     protected _glslFloat(x: number, decimalFigures = 8) {
         return x.toFixed(decimalFigures).replace(/0+$/, '');
     }
+
+    /** @hidden */
+    public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string): Nullable<BlurPostProcess> {
+        return SerializationHelper.Parse(() => {
+            return new BlurPostProcess(
+                parsedPostProcess.name, parsedPostProcess.direction, parsedPostProcess.kernel,
+                parsedPostProcess.options, targetCamera, parsedPostProcess.renderTargetSamplingMode,
+                scene.getEngine(), parsedPostProcess.reusable, parsedPostProcess.textureType, undefined, false);
+        }, parsedPostProcess, scene, rootUrl);
+    }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.BlurPostProcess"] = BlurPostProcess;

+ 43 - 0
src/PostProcesses/chromaticAberrationPostProcess.ts

@@ -7,6 +7,10 @@ import { Engine } from "../Engines/engine";
 import { Constants } from "../Engines/constants";
 
 import "../Shaders/chromaticAberration.fragment";
+import { _TypeStore } from '../Misc/typeStore';
+import { serialize, SerializationHelper } from '../Misc/decorators';
+
+declare type Scene = import("../scene").Scene;
 
 /**
  * The ChromaticAberrationPostProcess separates the rgb channels in an image to produce chromatic distortion around the edges of the screen
@@ -15,23 +19,43 @@ export class ChromaticAberrationPostProcess extends PostProcess {
     /**
      * The amount of seperation of rgb channels (default: 30)
      */
+    @serialize()
     aberrationAmount = 30;
 
     /**
      * The amount the effect will increase for pixels closer to the edge of the screen. (default: 0)
      */
+    @serialize()
     radialIntensity = 0;
 
     /**
      * The normilized direction in which the rgb channels should be seperated. If set to 0,0 radial direction will be used. (default: Vector2(0.707,0.707))
      */
+    @serialize()
     direction = new Vector2(0.707, 0.707);
 
     /**
      * The center position where the radialIntensity should be around. [0.5,0.5 is center of screen, 1,1 is top right corder] (default: Vector2(0.5 ,0.5))
      */
+    @serialize()
     centerPosition = new Vector2(0.5, 0.5);
 
+    /** The width of the screen to apply the effect on */
+    @serialize()
+    screenWidth: number;
+
+    /** The height of the screen to apply the effect on */
+    @serialize()
+    screenHeight: number;
+
+    /**
+     * Gets a string identifying the name of the class
+     * @returns "ChromaticAberrationPostProcess" string
+     */
+    public getClassName(): string {
+        return "ChromaticAberrationPostProcess";
+    }
+
     /**
      * Creates a new instance ChromaticAberrationPostProcess
      * @param name The name of the effect.
@@ -47,6 +71,10 @@ export class ChromaticAberrationPostProcess extends PostProcess {
      */
     constructor(name: string, screenWidth: number, screenHeight: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
         super(name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation);
+
+        this.screenWidth = screenWidth;
+        this.screenHeight = screenHeight;
+
         this.onApplyObservable.add((effect: Effect) => {
             effect.setFloat('chromatic_aberration', this.aberrationAmount);
             effect.setFloat('screen_width', screenWidth);
@@ -56,4 +84,19 @@ export class ChromaticAberrationPostProcess extends PostProcess {
             effect.setFloat2('centerPosition', this.centerPosition.x, this.centerPosition.y);
         });
     }
+
+    /** @hidden */
+    public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string): Nullable<ChromaticAberrationPostProcess> {
+        return SerializationHelper.Parse(() => {
+            return new ChromaticAberrationPostProcess(
+                parsedPostProcess.name,
+                parsedPostProcess.screenWidth, parsedPostProcess.screenHeight,
+                parsedPostProcess.options, targetCamera,
+                parsedPostProcess.renderTargetSamplingMode,
+                scene.getEngine(), parsedPostProcess.reusable,
+                parsedPostProcess.textureType, false);
+        }, parsedPostProcess, scene, rootUrl);
+    }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.ChromaticAberrationPostProcess"] = ChromaticAberrationPostProcess;

+ 16 - 0
src/PostProcesses/circleOfConfusionPostProcess.ts

@@ -8,6 +8,8 @@ import { Logger } from "../Misc/logger";
 import { Constants } from "../Engines/constants";
 
 import "../Shaders/circleOfConfusion.fragment";
+import { _TypeStore } from '../Misc/typeStore';
+import { serialize } from '../Misc/decorators';
 
 /**
  * The CircleOfConfusionPostProcess computes the circle of confusion value for each pixel given required lens parameters. See https://en.wikipedia.org/wiki/Circle_of_confusion
@@ -16,20 +18,32 @@ export class CircleOfConfusionPostProcess extends PostProcess {
     /**
      * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
      */
+    @serialize()
     public lensSize = 50;
     /**
      * F-Stop of the effect's camera. The diamater of the resulting aperture can be computed by lensSize/fStop. (default: 1.4)
      */
+    @serialize()
     public fStop = 1.4;
     /**
      * Distance away from the camera to focus on in scene units/1000 (eg. millimeter). (default: 2000)
      */
+    @serialize()
     public focusDistance = 2000;
     /**
      * Focal length of the effect's camera in scene units/1000 (eg. millimeter). (default: 50)
      */
+    @serialize()
     public focalLength = 50;
 
+    /**
+     * Gets a string identifying the name of the class
+     * @returns "CircleOfConfusionPostProcess" string
+     */
+    public getClassName(): string {
+        return "CircleOfConfusionPostProcess";
+    }
+
     private _depthTexture: Nullable<RenderTargetTexture> = null;
     /**
      * Creates a new instance CircleOfConfusionPostProcess
@@ -70,3 +84,5 @@ export class CircleOfConfusionPostProcess extends PostProcess {
         this._depthTexture = value;
     }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.CircleOfConfusionPostProcess"] = CircleOfConfusionPostProcess;

+ 34 - 0
src/PostProcesses/colorCorrectionPostProcess.ts

@@ -5,6 +5,11 @@ import { Engine } from "../Engines/engine";
 import { Camera } from "../Cameras/camera";
 
 import "../Shaders/colorCorrection.fragment";
+import { _TypeStore } from '../Misc/typeStore';
+import { SerializationHelper, serialize } from '../Misc/decorators';
+import { Nullable } from '../types';
+
+declare type Scene = import("../scene").Scene;
 
 /**
  *
@@ -25,6 +30,20 @@ export class ColorCorrectionPostProcess extends PostProcess {
 
     private _colorTableTexture: Texture;
 
+    /**
+     * Gets the color table url used to create the LUT texture
+     */
+    @serialize()
+    public colorTableUrl: string;
+
+    /**
+     * Gets a string identifying the name of the class
+     * @returns "ColorCorrectionPostProcess" string
+     */
+    public getClassName(): string {
+        return "ColorCorrectionPostProcess";
+    }
+
     constructor(name: string, colorTableUrl: string, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
         super(name, 'colorCorrection', null, ['colorTable'], options, camera, samplingMode, engine, reusable);
 
@@ -33,8 +52,23 @@ export class ColorCorrectionPostProcess extends PostProcess {
         this._colorTableTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
         this._colorTableTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
 
+        this.colorTableUrl = colorTableUrl;
+
         this.onApply = (effect: Effect) => {
             effect.setTexture("colorTable", this._colorTableTexture);
         };
     }
+
+    /** @hidden */
+    public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string): Nullable<ColorCorrectionPostProcess> {
+        return SerializationHelper.Parse(() => {
+            return new ColorCorrectionPostProcess(
+                parsedPostProcess.name, parsedPostProcess.colorTableUrl,
+                parsedPostProcess.options, targetCamera,
+                parsedPostProcess.renderTargetSamplingMode,
+                scene.getEngine(), parsedPostProcess.reusable);
+        }, parsedPostProcess, scene, rootUrl);
+    }
 }
+
+_TypeStore.RegisteredTypes["BABYLON.ColorCorrectionPostProcess"] = ColorCorrectionPostProcess;

+ 0 - 0
src/PostProcesses/convolutionPostProcess.ts


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.