Procházet zdrojové kódy

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into WebGPU

Popov72 před 4 roky
rodič
revize
f9c60a1369
88 změnil soubory, kde provedl 7504 přidání a 5223 odebrání
  1. 1236 1053
      dist/preview release/babylon.d.ts
  2. 2 2
      dist/preview release/babylon.js
  3. 917 449
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 1501 1120
      dist/preview release/babylon.module.d.ts
  6. 1242 1055
      dist/preview release/documentation.d.ts
  7. 6 2
      dist/preview release/gui/babylon.gui.d.ts
  8. 62 52
      dist/preview release/gui/babylon.gui.js
  9. 1 1
      dist/preview release/gui/babylon.gui.js.map
  10. 1 1
      dist/preview release/gui/babylon.gui.min.js
  11. 12 4
      dist/preview release/gui/babylon.gui.module.d.ts
  12. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  13. 2 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  15. 1 0
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  17. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  18. 1 0
      dist/preview release/loaders/babylon.glTFFileLoader.js
  19. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  20. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  21. 1 0
      dist/preview release/loaders/babylonjs.loaders.js
  22. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  23. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  24. 3 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  25. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  26. 52 6
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  27. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  28. 6 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  29. 1 1
      dist/preview release/packagesSizeBaseLine.json
  30. 1501 1120
      dist/preview release/viewer/babylon.module.d.ts
  31. 114 94
      dist/preview release/viewer/babylon.viewer.js
  32. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  33. 2 2
      dist/preview release/what's new.md
  34. 6 4
      gui/src/2D/advancedDynamicTexture.ts
  35. 5 0
      gui/src/2D/controls/selector.ts
  36. 1 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  37. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  38. 1 0
      loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts
  39. 39 2
      nodeEditor/src/diagram/graphFrame.ts
  40. 8 0
      nodeEditor/src/diagram/nodePort.ts
  41. 12 0
      src/Cameras/camera.ts
  42. 3 0
      src/Debug/ISkeletonViewer.ts
  43. 35 24
      src/Debug/skeletonViewer.ts
  44. 5 1
      src/Engines/constants.ts
  45. 14 0
      src/Engines/nativeEngine.ts
  46. 41 5
      src/Engines/thinEngine.ts
  47. 3 3
      src/Materials/Node/Blocks/PBR/ambientOcclusionBlock.ts
  48. 2 2
      src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts
  49. 2 0
      src/Materials/Node/nodeMaterialBlock.ts
  50. 7 0
      src/Materials/Node/nodeMaterialBlockConnectionPoint.ts
  51. 22 1
      src/Materials/PBR/pbrBaseMaterial.ts
  52. 10 0
      src/Materials/PBR/pbrClearCoatConfiguration.ts
  53. 1 0
      src/Materials/PBR/pbrSubSurfaceConfiguration.ts
  54. 3 2
      src/Materials/Textures/dynamicTexture.ts
  55. 17 0
      src/Materials/material.ts
  56. 11 0
      src/Materials/materialDefines.ts
  57. 71 23
      src/Materials/materialHelper.ts
  58. 70 0
      src/Materials/prePassConfiguration.ts
  59. 20 0
      src/Materials/standardMaterial.ts
  60. 35 6
      src/Misc/khronosTextureContainer2.ts
  61. 1 1
      src/Navigation/Plugins/recastJSPlugin.ts
  62. 4 21
      src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts
  63. 48 12
      src/PostProcesses/motionBlurPostProcess.ts
  64. 23 0
      src/PostProcesses/postProcess.ts
  65. 47 17
      src/PostProcesses/screenSpaceReflectionPostProcess.ts
  66. 26 0
      src/Rendering/motionBlurConfiguration.ts
  67. 1 1
      src/Rendering/prePassEffectConfiguration.ts
  68. 36 35
      src/Rendering/prePassRenderer.ts
  69. 28 0
      src/Rendering/screenSpaceReflectionsConfiguration.ts
  70. 0 15
      src/Rendering/ssao2Configuration.ts
  71. 4 1
      src/Shaders/ShadersInclude/bonesDeclaration.fx
  72. 5 1
      src/Shaders/ShadersInclude/pbrBlockClearcoat.fx
  73. 3 1
      src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx
  74. 0 16
      src/Shaders/ShadersInclude/pbrFragmentExtraDeclaration.fx
  75. 9 0
      src/Shaders/ShadersInclude/prePassDeclaration.fx
  76. 37 0
      src/Shaders/ShadersInclude/prePassVertex.fx
  77. 11 0
      src/Shaders/ShadersInclude/prePassVertexDeclaration.fx
  78. 6 0
      src/Shaders/ShadersInclude/subSurfaceScatteringFunctions.fx
  79. 21 4
      src/Shaders/default.fragment.fx
  80. 10 7
      src/Shaders/default.vertex.fx
  81. 23 0
      src/Shaders/pbr.fragment.fx
  82. 12 39
      src/Shaders/pbr.vertex.fx
  83. 4 0
      src/Shaders/screenSpaceReflection.fragment.fx
  84. 1 1
      src/XR/webXRFeaturesManager.ts
  85. binární
      tests/validation/ReferenceImages/geometrybufferrenderer.png
  86. binární
      tests/validation/ReferenceImages/motionBlur.png
  87. binární
      tests/validation/ReferenceImages/ssr.png
  88. 22 1
      tests/validation/config.json

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1236 - 1053
dist/preview release/babylon.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 2
dist/preview release/babylon.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 917 - 449
dist/preview release/babylon.max.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/babylon.max.js.map


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1501 - 1120
dist/preview release/babylon.module.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1242 - 1055
dist/preview release/documentation.d.ts


+ 6 - 2
dist/preview release/gui/babylon.gui.d.ts

@@ -504,8 +504,9 @@ declare module BABYLON.GUI {
        * @param scene defines the hosting scene
        * @param generateMipMaps defines a boolean indicating if mipmaps must be generated (false by default)
        * @param samplingMode defines the texture sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
+       * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
        */
-        constructor(name: string, width: number | undefined, height: number | undefined, scene: BABYLON.Nullable<BABYLON.Scene>, generateMipMaps?: boolean, samplingMode?: number);
+        constructor(name: string, width: number | undefined, height: number | undefined, scene: BABYLON.Nullable<BABYLON.Scene>, generateMipMaps?: boolean, samplingMode?: number, invertY?: boolean);
         /**
         * Get the current class name of the texture useful for serialization or dynamic coding.
         * @returns "AdvancedDynamicTexture"
@@ -619,9 +620,10 @@ declare module BABYLON.GUI {
          * @param height defines the texture height (1024 by default)
          * @param supportPointerMove defines a boolean indicating if the texture must capture move events (true by default)
          * @param onlyAlphaTesting defines a boolean indicating that alpha blending will not be used (only alpha testing) (false by default)
+         * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
          * @returns a new AdvancedDynamicTexture
          */
-        static CreateForMesh(mesh: BABYLON.AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean): AdvancedDynamicTexture;
+        static CreateForMesh(mesh: BABYLON.AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean, invertY?: boolean): AdvancedDynamicTexture;
         /**
         * Creates a new AdvancedDynamicTexture in fullscreen mode.
         * In this mode the texture will rely on a layer for its rendering.
@@ -2866,6 +2868,8 @@ declare module BABYLON.GUI {
         /** an array of SelectionGroups */
         groups?: SelectorGroup[]);
         protected _getTypeName(): string;
+        /** Gets the (stack) panel of the SelectionPanel  */
+        get panel(): StackPanel;
         /** Gets or sets the headerColor */
         get headerColor(): string;
         set headerColor(color: string);

+ 62 - 52
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_Maths_math_vector__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__) {
 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/Maths/math.vector");
+/* 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___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/Maths/math.vector");
+/* 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___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");
@@ -579,13 +579,14 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
    * @param scene defines the hosting scene
    * @param generateMipMaps defines a boolean indicating if mipmaps must be generated (false by default)
    * @param samplingMode defines the texture sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
+   * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
    */
-    function AdvancedDynamicTexture(name, width, height, scene, generateMipMaps, samplingMode) {
+    function AdvancedDynamicTexture(name, width, height, scene, generateMipMaps, samplingMode, invertY) {
         if (width === void 0) { width = 0; }
         if (height === void 0) { height = 0; }
         if (generateMipMaps === void 0) { generateMipMaps = false; }
         if (samplingMode === void 0) { samplingMode = babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Texture"].NEAREST_SAMPLINGMODE; }
-        var _this = _super.call(this, name, { width: width, height: height }, scene, generateMipMaps, samplingMode, babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTUREFORMAT_RGBA) || this;
+        var _this = _super.call(this, name, { width: width, height: height }, scene, generateMipMaps, samplingMode, babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Constants"].TEXTUREFORMAT_RGBA, invertY) || this;
         _this._isDirty = false;
         /** @hidden */
         _this._rootContainer = new _controls_container__WEBPACK_IMPORTED_MODULE_2__["Container"]("root");
@@ -1457,14 +1458,15 @@ var AdvancedDynamicTexture = /** @class */ (function (_super) {
      * @param height defines the texture height (1024 by default)
      * @param supportPointerMove defines a boolean indicating if the texture must capture move events (true by default)
      * @param onlyAlphaTesting defines a boolean indicating that alpha blending will not be used (only alpha testing) (false by default)
+     * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
      * @returns a new AdvancedDynamicTexture
      */
-    AdvancedDynamicTexture.CreateForMesh = function (mesh, width, height, supportPointerMove, onlyAlphaTesting) {
+    AdvancedDynamicTexture.CreateForMesh = function (mesh, width, height, supportPointerMove, onlyAlphaTesting, invertY) {
         if (width === void 0) { width = 1024; }
         if (height === void 0) { height = 1024; }
         if (supportPointerMove === void 0) { supportPointerMove = true; }
         if (onlyAlphaTesting === void 0) { onlyAlphaTesting = false; }
-        var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Texture"].TRILINEAR_SAMPLINGMODE);
+        var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Texture"].TRILINEAR_SAMPLINGMODE, invertY);
         var material = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["StandardMaterial"]("AdvancedDynamicTextureMaterial", mesh.getScene());
         material.backFaceCulling = false;
         material.diffuseColor = babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["Color3"].Black();
@@ -1530,7 +1532,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
@@ -1762,7 +1764,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/Maths/math.vector");
+/* 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___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");
@@ -1945,7 +1947,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/Maths/math.vector");
+/* 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___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");
@@ -3338,7 +3340,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/Maths/math.vector");
+/* 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___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");
@@ -3755,7 +3757,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/Maths/math.vector");
+/* 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___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");
@@ -5704,7 +5706,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -5937,7 +5939,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -6034,7 +6036,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
@@ -6492,7 +6494,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/Maths/math.vector");
+/* 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___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");
 
@@ -7429,7 +7431,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -7468,7 +7470,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/Maths/math.vector");
+/* 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___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");
@@ -8481,7 +8483,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/Maths/math.vector");
+/* 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___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");
@@ -8752,7 +8754,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/Maths/math.vector");
+/* 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___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");
@@ -9022,7 +9024,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/Maths/math.vector");
+/* 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___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");
@@ -9229,7 +9231,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -9379,7 +9381,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
@@ -10697,6 +10699,14 @@ var SelectionPanel = /** @class */ (function (_super) {
     SelectionPanel.prototype._getTypeName = function () {
         return "SelectionPanel";
     };
+    Object.defineProperty(SelectionPanel.prototype, "panel", {
+        /** Gets the (stack) panel of the SelectionPanel  */
+        get: function () {
+            return this._panel;
+        },
+        enumerable: false,
+        configurable: true
+    });
     Object.defineProperty(SelectionPanel.prototype, "headerColor", {
         /** Gets or sets the headerColor */
         get: function () {
@@ -11002,7 +11012,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/Maths/math.vector");
+/* 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___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");
@@ -11336,7 +11346,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -11929,7 +11939,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -12201,7 +12211,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/Maths/math.vector");
+/* 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___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");
@@ -12471,7 +12481,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/Maths/math.vector");
+/* 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___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");
@@ -13005,7 +13015,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/Maths/math.vector");
+/* 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___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");
@@ -13394,7 +13404,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -13619,7 +13629,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 var tmpRect = [
@@ -13784,7 +13794,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/Maths/math.vector");
+/* 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___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");
 
@@ -13927,7 +13937,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/Maths/math.vector");
+/* 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___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");
 
@@ -14233,7 +14243,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -14552,7 +14562,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/Maths/math.vector");
+/* 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___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");
 
@@ -14595,7 +14605,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/Maths/math.vector");
+/* 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___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");
@@ -14776,7 +14786,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/Maths/math.vector");
+/* 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___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");
 
@@ -14933,7 +14943,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/Maths/math.vector");
+/* 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___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");
 
@@ -15339,7 +15349,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/Maths/math.vector");
+/* 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___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");
@@ -15425,7 +15435,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/Maths/math.vector");
+/* 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___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");
@@ -15919,7 +15929,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/Maths/math.vector");
+/* 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___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");
@@ -15974,7 +15984,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/Maths/math.vector");
+/* 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___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");
@@ -16101,7 +16111,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/Maths/math.vector");
+/* 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___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");
@@ -16187,7 +16197,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/Maths/math.vector");
+/* 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___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");
 
@@ -16312,7 +16322,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/Maths/math.vector");
+/* 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___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");
 
@@ -16503,7 +16513,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/Maths/math.vector");
+/* 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___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");
 
@@ -16770,7 +16780,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/Maths/math.vector");
+/* 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___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");
@@ -17086,7 +17096,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentPixelShader';
@@ -17108,7 +17118,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentVertexShader';
@@ -17131,7 +17141,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/Maths/math.vector");
+/* 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___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -17433,14 +17443,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Maths/math.vector":
+/***/ "babylonjs/Misc/perfCounter":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__;
 
 /***/ })
 

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


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

@@ -524,8 +524,9 @@ declare module "babylonjs-gui/2D/advancedDynamicTexture" {
        * @param scene defines the hosting scene
        * @param generateMipMaps defines a boolean indicating if mipmaps must be generated (false by default)
        * @param samplingMode defines the texture sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
+       * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
        */
-        constructor(name: string, width: number | undefined, height: number | undefined, scene: Nullable<Scene>, generateMipMaps?: boolean, samplingMode?: number);
+        constructor(name: string, width: number | undefined, height: number | undefined, scene: Nullable<Scene>, generateMipMaps?: boolean, samplingMode?: number, invertY?: boolean);
         /**
         * Get the current class name of the texture useful for serialization or dynamic coding.
         * @returns "AdvancedDynamicTexture"
@@ -639,9 +640,10 @@ declare module "babylonjs-gui/2D/advancedDynamicTexture" {
          * @param height defines the texture height (1024 by default)
          * @param supportPointerMove defines a boolean indicating if the texture must capture move events (true by default)
          * @param onlyAlphaTesting defines a boolean indicating that alpha blending will not be used (only alpha testing) (false by default)
+         * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
          * @returns a new AdvancedDynamicTexture
          */
-        static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean): AdvancedDynamicTexture;
+        static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean, invertY?: boolean): AdvancedDynamicTexture;
         /**
         * Creates a new AdvancedDynamicTexture in fullscreen mode.
         * In this mode the texture will rely on a layer for its rendering.
@@ -2977,6 +2979,8 @@ declare module "babylonjs-gui/2D/controls/selector" {
         /** an array of SelectionGroups */
         groups?: SelectorGroup[]);
         protected _getTypeName(): string;
+        /** Gets the (stack) panel of the SelectionPanel  */
+        get panel(): StackPanel;
         /** Gets or sets the headerColor */
         get headerColor(): string;
         set headerColor(color: string);
@@ -4926,8 +4930,9 @@ declare module BABYLON.GUI {
        * @param scene defines the hosting scene
        * @param generateMipMaps defines a boolean indicating if mipmaps must be generated (false by default)
        * @param samplingMode defines the texture sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
+       * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
        */
-        constructor(name: string, width: number | undefined, height: number | undefined, scene: BABYLON.Nullable<BABYLON.Scene>, generateMipMaps?: boolean, samplingMode?: number);
+        constructor(name: string, width: number | undefined, height: number | undefined, scene: BABYLON.Nullable<BABYLON.Scene>, generateMipMaps?: boolean, samplingMode?: number, invertY?: boolean);
         /**
         * Get the current class name of the texture useful for serialization or dynamic coding.
         * @returns "AdvancedDynamicTexture"
@@ -5041,9 +5046,10 @@ declare module BABYLON.GUI {
          * @param height defines the texture height (1024 by default)
          * @param supportPointerMove defines a boolean indicating if the texture must capture move events (true by default)
          * @param onlyAlphaTesting defines a boolean indicating that alpha blending will not be used (only alpha testing) (false by default)
+         * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
          * @returns a new AdvancedDynamicTexture
          */
-        static CreateForMesh(mesh: BABYLON.AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean): AdvancedDynamicTexture;
+        static CreateForMesh(mesh: BABYLON.AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean, onlyAlphaTesting?: boolean, invertY?: boolean): AdvancedDynamicTexture;
         /**
         * Creates a new AdvancedDynamicTexture in fullscreen mode.
         * In this mode the texture will rely on a layer for its rendering.
@@ -7288,6 +7294,8 @@ declare module BABYLON.GUI {
         /** an array of SelectionGroups */
         groups?: SelectorGroup[]);
         protected _getTypeName(): string;
+        /** Gets the (stack) panel of the SelectionPanel  */
+        get panel(): StackPanel;
         /** Gets or sets the headerColor */
         get headerColor(): string;
         set headerColor(color: string);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 1 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -973,6 +973,7 @@ var KHR_materials_clearcoat = /** @class */ (function () {
         }
         var promises = new Array();
         babylonMaterial.clearCoat.isEnabled = true;
+        babylonMaterial.clearCoat.remapF0OnInterfaceChange = false;
         if (properties.clearcoatFactor != undefined) {
             babylonMaterial.clearCoat.intensity = properties.clearcoatFactor;
         }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 1 - 0
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3324,6 +3324,7 @@ var KHR_materials_clearcoat = /** @class */ (function () {
         }
         var promises = new Array();
         babylonMaterial.clearCoat.isEnabled = true;
+        babylonMaterial.clearCoat.remapF0OnInterfaceChange = false;
         if (properties.clearcoatFactor != undefined) {
             babylonMaterial.clearCoat.intensity = properties.clearcoatFactor;
         }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 1 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -4704,6 +4704,7 @@ var KHR_materials_clearcoat = /** @class */ (function () {
         }
         var promises = new Array();
         babylonMaterial.clearCoat.isEnabled = true;
+        babylonMaterial.clearCoat.remapF0OnInterfaceChange = false;
         if (properties.clearcoatFactor != undefined) {
             babylonMaterial.clearCoat.intensity = properties.clearcoatFactor;
         }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 3 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -260,6 +260,7 @@ declare module NODEEDITOR {
         private _expandRight;
         private _expandBottom;
         dispose(): void;
+        private serializePortData;
         serialize(): IFrameData;
         export(): void;
         static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent, map?: {
@@ -287,6 +288,8 @@ declare module NODEEDITOR {
         hasLabel(): boolean;
         get exposedOnFrame(): boolean;
         set exposedOnFrame(value: boolean);
+        get exposedPortPosition(): number;
+        set exposedPortPosition(value: number);
         private _isConnectedToNodeOutsideOfFrame;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.js


+ 52 - 6
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -68293,7 +68293,16 @@ var GraphFrame = /** @class */ (function () {
         this._ownerCanvas.frames.splice(this._ownerCanvas.frames.indexOf(this), 1);
         this.onExpandStateChanged.clear();
     };
+    GraphFrame.prototype.serializePortData = function (exposedPorts) {
+        if (exposedPorts.length > 0) {
+            for (var i = 0; i < exposedPorts.length; ++i) {
+                exposedPorts[i].exposedPortPosition = i;
+            }
+        }
+    };
     GraphFrame.prototype.serialize = function () {
+        this.serializePortData(this._exposedInPorts);
+        this.serializePortData(this._exposedOutPorts);
         return {
             x: this._x,
             y: this._y,
@@ -68324,10 +68333,10 @@ var GraphFrame = /** @class */ (function () {
         if (serializationData.blocks && map) {
             var _loop_1 = function () {
                 var actualId = map[blockId];
-                var node = canvas.nodes.filter(function (n) { return n.block.uniqueId === actualId; });
-                if (node.length) {
-                    newFrame.nodes.push(node[0]);
-                    node[0].enclosingFrameId = newFrame.id;
+                var node_1 = canvas.nodes.filter(function (n) { return n.block.uniqueId === actualId; });
+                if (node_1.length) {
+                    newFrame.nodes.push(node_1[0]);
+                    node_1[0].enclosingFrameId = newFrame.id;
                 }
             };
             for (var _i = 0, _a = serializationData.blocks; _i < _a.length; _i++) {
@@ -68338,6 +68347,33 @@ var GraphFrame = /** @class */ (function () {
         else {
             newFrame.refresh();
         }
+        for (var _b = 0, _c = newFrame.nodes; _b < _c.length; _b++) {
+            var node = _c[_b];
+            for (var _d = 0, _e = node.outputPorts; _d < _e.length; _d++) { // Output
+                var port = _e[_d];
+                if (port.exposedOnFrame) {
+                    port.isExposed = true;
+                    if (port.exposedPortPosition) {
+                        newFrame._exposedOutPorts[port.exposedPortPosition] = port;
+                    }
+                    else {
+                        newFrame._exposedOutPorts.push(port);
+                    }
+                }
+            }
+            for (var _f = 0, _g = node.inputPorts; _f < _g.length; _f++) { // Inports
+                var port = _g[_f];
+                if (port.exposedOnFrame) {
+                    port.isExposed = true;
+                    if (port.exposedPortPosition) {
+                        newFrame._exposedInPorts[port.exposedPortPosition] = port;
+                    }
+                    else {
+                        newFrame._exposedInPorts.push(port);
+                    }
+                }
+            }
+        }
         newFrame.isCollapsed = isCollapsed;
         if (isCollapsed) {
             canvas._frameIsMoving = true;
@@ -68345,8 +68381,8 @@ var GraphFrame = /** @class */ (function () {
             var diff = serializationData.x - newFrame.x;
             newFrame._moveFrame(diff, 0);
             newFrame.cleanAccumulation();
-            for (var _b = 0, _c = newFrame.nodes; _b < _c.length; _b++) {
-                var selectedNode = _c[_b];
+            for (var _h = 0, _j = newFrame.nodes; _h < _j.length; _h++) {
+                var selectedNode = _j[_h];
                 selectedNode.refresh();
             }
             canvas._frameIsMoving = false;
@@ -69098,6 +69134,16 @@ var NodePort = /** @class */ (function () {
         enumerable: false,
         configurable: true
     });
+    Object.defineProperty(NodePort.prototype, "exposedPortPosition", {
+        get: function () {
+            return this.connectionPoint.exposedPortPosition;
+        },
+        set: function (value) {
+            this.connectionPoint.exposedPortPosition = value;
+        },
+        enumerable: false,
+        configurable: true
+    });
     NodePort.prototype._isConnectedToNodeOutsideOfFrame = function () {
         var link = this.node.getLinksForConnectionPoint(this.connectionPoint);
         if (link.length) {

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


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

@@ -361,6 +361,7 @@ declare module "babylonjs-node-editor/diagram/graphFrame" {
         private _expandRight;
         private _expandBottom;
         dispose(): void;
+        private serializePortData;
         serialize(): IFrameData;
         export(): void;
         static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent, map?: {
@@ -399,6 +400,8 @@ declare module "babylonjs-node-editor/diagram/nodePort" {
         hasLabel(): boolean;
         get exposedOnFrame(): boolean;
         set exposedOnFrame(value: boolean);
+        get exposedPortPosition(): number;
+        set exposedPortPosition(value: number);
         private _isConnectedToNodeOutsideOfFrame;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);
@@ -2173,6 +2176,7 @@ declare module NODEEDITOR {
         private _expandRight;
         private _expandBottom;
         dispose(): void;
+        private serializePortData;
         serialize(): IFrameData;
         export(): void;
         static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent, map?: {
@@ -2200,6 +2204,8 @@ declare module NODEEDITOR {
         hasLabel(): boolean;
         get exposedOnFrame(): boolean;
         set exposedOnFrame(value: boolean);
+        get exposedPortPosition(): number;
+        set exposedPortPosition(value: number);
         private _isConnectedToNodeOutsideOfFrame;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);

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

@@ -1 +1 @@
-{"thinEngineOnly":117927,"engineOnly":154367,"sceneOnly":519894,"minGridMaterial":659986,"minStandardMaterial":810521}
+{"thinEngineOnly":118576,"engineOnly":155016,"sceneOnly":521091,"minGridMaterial":661878,"minStandardMaterial":816230}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1501 - 1120
dist/preview release/viewer/babylon.module.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 114 - 94
dist/preview release/viewer/babylon.viewer.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -5,7 +5,7 @@
 - Added particle editor to the Inspector ([Deltakosh](https://github.com/deltakosh))
 - Added sprite editor to the Inspector ([Deltakosh](https://github.com/deltakosh))
 - Added the `ShadowDepthWrapper` class to support accurate shadow generation for custom as well as node material shaders. [Doc](https://doc.babylonjs.com/babylon101/shadows#custom-shadow-map-shaders) ([Popov72](https://github.com/Popov72))
-- Added HDR texture filtering tools to the sandbox ([Sebavan](https://github.com/sebavan/))
+- Added HDR texture filtering tools to the sandbox. [Doc](https://medium.com/@babylonjs/real-time-pbr-filtering-is-coming-to-babylon-cb0e81159d79) ([Sebavan](https://github.com/sebavan/))
 - Reflection probes can now be used to give accurate shading with PBR ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Added SubSurfaceScattering on PBR materials ([CraigFeldpsar](https://github.com/craigfeldspar) and ([Sebavan](https://github.com/sebavan/)))
 - Added edition of PBR materials, Post processes and Particle fragment shaders in the node material editor ([Popov72](https://github.com/Popov72))
@@ -243,7 +243,7 @@
 
 ### Post Processes
 
-- SSAO 2 is now using the brand new `PrePassRenderer` to avoid rendering the scene twice ([CraigFeldpsar](https://github.com/craigfeldspar)
+- SSAO 2, motion blur and screen space reflections are now using the brand new `PrePassRenderer` to avoid rendering the scene twice ([CraigFeldpsar](https://github.com/craigfeldspar)
 - Added Screen Space Curvature post process: [Doc](https://doc.babylonjs.com/how_to/how_to_use_postprocesses#screen-space-curvature) ([Popov72](https://github.com/Popov72) and [Sebavan](https://github.com/sebavan/))
 
 ## Bugs

+ 6 - 4
gui/src/2D/advancedDynamicTexture.ts

@@ -334,9 +334,10 @@ export class AdvancedDynamicTexture extends DynamicTexture {
    * @param scene defines the hosting scene
    * @param generateMipMaps defines a boolean indicating if mipmaps must be generated (false by default)
    * @param samplingMode defines the texture sampling mode (Texture.NEAREST_SAMPLINGMODE by default)
+   * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
    */
-    constructor(name: string, width = 0, height = 0, scene: Nullable<Scene>, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE) {
-        super(name, { width: width, height: height }, scene, generateMipMaps, samplingMode, Constants.TEXTUREFORMAT_RGBA);
+    constructor(name: string, width = 0, height = 0, scene: Nullable<Scene>, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE, invertY?: boolean) {
+        super(name, { width: width, height: height }, scene, generateMipMaps, samplingMode, Constants.TEXTUREFORMAT_RGBA, invertY);
         scene = this.getScene();
         if (!scene || !this._texture) {
             return;
@@ -897,10 +898,11 @@ export class AdvancedDynamicTexture extends DynamicTexture {
      * @param height defines the texture height (1024 by default)
      * @param supportPointerMove defines a boolean indicating if the texture must capture move events (true by default)
      * @param onlyAlphaTesting defines a boolean indicating that alpha blending will not be used (only alpha testing) (false by default)
+     * @param invertY defines if the texture needs to be inverted on the y axis during loading (true by default)
      * @returns a new AdvancedDynamicTexture
      */
-    public static CreateForMesh(mesh: AbstractMesh, width = 1024, height = 1024, supportPointerMove = true, onlyAlphaTesting = false): AdvancedDynamicTexture {
-        var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, Texture.TRILINEAR_SAMPLINGMODE);
+    public static CreateForMesh(mesh: AbstractMesh, width = 1024, height = 1024, supportPointerMove = true, onlyAlphaTesting = false, invertY?: boolean): AdvancedDynamicTexture {
+        var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, Texture.TRILINEAR_SAMPLINGMODE, invertY);
         var material = new StandardMaterial("AdvancedDynamicTextureMaterial", mesh.getScene());
         material.backFaceCulling = false;
         material.diffuseColor = Color3.Black();

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

@@ -325,6 +325,11 @@ export class SelectionPanel extends Rectangle {
         return "SelectionPanel";
     }
 
+    /** Gets the (stack) panel of the SelectionPanel  */
+    public get panel(): StackPanel {
+        return this._panel;
+    }
+
     /** Gets or sets the headerColor */
     public get headerColor(): string {
         return this._headerColor;

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -176,6 +176,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                             <SliderLineComponent label="Intensity" target={material.clearCoat} propertyName="intensity" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <SliderLineComponent label="Roughness" target={material.clearCoat} propertyName="roughness" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <SliderLineComponent label="IOR" target={material.clearCoat} propertyName="indexOfRefraction" minimum={1.0} maximum={3} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <CheckBoxLineComponent label="Remap F0" target={material.clearCoat} propertyName="remapF0OnInterfaceChange" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <TextureLinkLineComponent label="Clear coat" texture={material.clearCoat.texture} onTextureCreated={(texture) => material.clearCoat.texture = texture} onTextureRemoved={() => material.clearCoat.texture = null} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} />
                             <TextureLinkLineComponent label="Bump" texture={material.clearCoat.bumpTexture} onTextureCreated={(texture) => material.clearCoat.bumpTexture = texture} onTextureRemoved={() => material.clearCoat.bumpTexture = null} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} />
                             {

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -375,7 +375,7 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             };});
 
         materialOptions.splice(0, 0, {
-            label: "None",
+            label: "None (Default Fallback)",
             value: -1
         });
 

+ 1 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts

@@ -61,6 +61,7 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         const promises = new Array<Promise<any>>();
 
         babylonMaterial.clearCoat.isEnabled = true;
+        babylonMaterial.clearCoat.remapF0OnInterfaceChange = false;
 
         if (properties.clearcoatFactor != undefined) {
             babylonMaterial.clearCoat.intensity = properties.clearcoatFactor;

+ 39 - 2
nodeEditor/src/diagram/graphFrame.ts

@@ -1370,7 +1370,18 @@ export class GraphFrame {
         this.onExpandStateChanged.clear();
     }
 
+    private serializePortData(exposedPorts: NodePort[])
+    {
+        if(exposedPorts.length > 0) {
+            for(let i = 0; i < exposedPorts.length; ++i) {
+                exposedPorts[i].exposedPortPosition = i;
+            }
+        }
+    }
+
     public serialize(): IFrameData {
+        this.serializePortData(this._exposedInPorts);
+        this.serializePortData(this._exposedOutPorts);
         return {
             x: this._x,
             y: this._y,
@@ -1406,7 +1417,7 @@ export class GraphFrame {
             for (var blockId of serializationData.blocks) {
                 let actualId = map[blockId];
                 let node = canvas.nodes.filter(n => n.block.uniqueId === actualId);
-
+                
                 if (node.length) {
                     newFrame.nodes.push(node[0]);
                     node[0].enclosingFrameId = newFrame.id;
@@ -1415,9 +1426,35 @@ export class GraphFrame {
         } else {
             newFrame.refresh();
         }
+        
+        
+        for (var node of newFrame.nodes) {
+            for (var port of node.outputPorts) { // Output
+                if(port.exposedOnFrame) {
+                    port.isExposed = true;
+                    if(port.exposedPortPosition) { 
+                        newFrame._exposedOutPorts[port.exposedPortPosition] = port;
+                    }
+                    else {
+                        newFrame._exposedOutPorts.push(port);
+                    }
+                }
+            }
+
+            for (var port of node.inputPorts) { // Inports
+                if(port.exposedOnFrame) {
+                    port.isExposed = true;
+                    if(port.exposedPortPosition) { 
+                        newFrame._exposedInPorts[port.exposedPortPosition] = port;
+                    }
+                    else {
+                        newFrame._exposedInPorts.push(port);
+                    }
+                }
+            }
+        }
 
         newFrame.isCollapsed = isCollapsed;
-
         if (isCollapsed) {
             canvas._frameIsMoving = true;
             newFrame._moveFrame(-(newFrame.width - newFrame.CollapsedWidth) / 2, 0);

+ 8 - 0
nodeEditor/src/diagram/nodePort.ts

@@ -79,6 +79,14 @@ export class NodePort {
         this.connectionPoint.isExposedOnFrame = value;
     }
     
+    public get exposedPortPosition()
+    {
+        return this.connectionPoint.exposedPortPosition;
+    }
+
+    public set exposedPortPosition(value: number) {
+        this.connectionPoint.exposedPortPosition = value;
+    }
     
     private _isConnectedToNodeOutsideOfFrame() {
         const link = this.node.getLinksForConnectionPoint(this.connectionPoint)

+ 12 - 0
src/Cameras/camera.ts

@@ -625,6 +625,12 @@ export class Camera extends Node {
             this._postProcesses.splice(insertAt, 0, postProcess);
         }
         this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
+
+        // Update prePass
+        if (this._scene.prePassRenderer) {
+            this._scene.prePassRenderer.markAsDirty();
+        }
+
         return this._postProcesses.indexOf(postProcess);
     }
 
@@ -638,6 +644,12 @@ export class Camera extends Node {
         if (idx !== -1) {
             this._postProcesses[idx] = null;
         }
+
+        // Update prePass
+        if (this._scene.prePassRenderer) {
+            this._scene.prePassRenderer.markAsDirty();
+        }
+
         this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
     }
 

+ 3 - 0
src/Debug/ISkeletonViewer.ts

@@ -43,6 +43,9 @@ export interface ISkeletonViewerDisplayOptions{
    /** Ratio for the Sphere Size */
    sphereFactor? : number;
 
+   /** Whether a spur should attach its far end to the child bone position */
+   spurFollowsChild? : boolean;
+
    /** Whether to show local axes or not  */
    showLocalAxes? : boolean;
 

+ 35 - 24
src/Debug/skeletonViewer.ts

@@ -389,6 +389,7 @@ export class SkeletonViewer {
         options.displayOptions.sphereBaseSize = options.displayOptions.sphereBaseSize ?? 0.15;
         options.displayOptions.sphereScaleUnit = options.displayOptions.sphereScaleUnit ?? 2;
         options.displayOptions.sphereFactor = options.displayOptions.sphereFactor ?? 0.865;
+        options.displayOptions.spurFollowsChild = options.displayOptions.spurFollowsChild ?? false;
         options.displayOptions.showLocalAxes = options.displayOptions.showLocalAxes ?? false;
         options.displayOptions.localAxesSize = options.displayOptions.localAxesSize ?? 0.075;
         options.computeBonesUsingShaders = options.computeBonesUsingShaders ?? true;
@@ -560,13 +561,14 @@ export class SkeletonViewer {
         }
     }
 
-    private getAbsoluteRestPose(bone: Nullable<Bone>, matrix: Matrix) {
+    /** function to get the absolute bind pose of a bone by accumulating transformations up the bone hierarchy. */
+    private _getAbsoluteBindPoseToRef(bone: Nullable<Bone>, matrix: Matrix) {
         if (bone === null || bone._index === -1) {
             matrix.copyFrom(Matrix.Identity());
             return;
         }
 
-        this.getAbsoluteRestPose(bone.getParent(), matrix);
+        this._getAbsoluteBindPoseToRef(bone.getParent(), matrix);
         bone.getBindPose().multiplyToRef(matrix, matrix);
         return;
     }
@@ -611,18 +613,18 @@ export class SkeletonViewer {
                     continue;
                 }
 
-                let boneAbsoluteRestTransform = new Matrix();
-                this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
+                let boneAbsoluteBindPoseTransform = new Matrix();
+                this._getAbsoluteBindPoseToRef(bone, boneAbsoluteBindPoseTransform);
 
                 let anchorPoint = new Vector3();
 
-                boneAbsoluteRestTransform.decompose(undefined, undefined, anchorPoint);
+                boneAbsoluteBindPoseTransform.decompose(undefined, undefined, anchorPoint);
 
                 bone.children.forEach((bc, i) => {
-                    let childAbsoluteRestTransform : Matrix = new Matrix();
-                    bc.getRestPose().multiplyToRef(boneAbsoluteRestTransform, childAbsoluteRestTransform);
+                    let childAbsoluteBindPoseTransform : Matrix = new Matrix();
+                    bc.getBindPose().multiplyToRef(boneAbsoluteBindPoseTransform, childAbsoluteBindPoseTransform);
                     let childPoint = new Vector3();
-                    childAbsoluteRestTransform.decompose(undefined, undefined, childPoint);
+                    childAbsoluteBindPoseTransform.decompose(undefined, undefined, childPoint);
                     let distanceFromParent = Vector3.Distance(anchorPoint, childPoint);
                     if (distanceFromParent > longestBoneLength) {
                         longestBoneLength = distanceFromParent;
@@ -665,19 +667,27 @@ export class SkeletonViewer {
                         updatable: false
                     },  scene);
 
-                    spur.convertToFlatShadedMesh();
-
                     let numVertices = spur.getTotalVertices();
                     let mwk: number[] = [], mik: number[] = [];
 
                     for (let i = 0; i < numVertices; i++) {
                         mwk.push(1, 0, 0, 0);
-                        mik.push(bone.getIndex(), 0, 0, 0);
+
+                        // Select verts at end of spur (ie vert 10 to 14) and bind to child
+                        // bone if spurFollowsChild is enabled.
+                        if (displayOptions.spurFollowsChild && i > 9) {
+                            mik.push(bc.getIndex(), 0, 0, 0);
+                        }
+                        else {
+                            mik.push(bone.getIndex(), 0, 0, 0);
+                        }
                     }
+
                     spur.position = anchorPoint.clone();
 
                     spur.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
                     spur.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
+                    spur.convertToFlatShadedMesh();
 
                     spurs.push(spur);
                 });
@@ -775,11 +785,11 @@ export class SkeletonViewer {
                 continue;
             }
 
-            let boneAbsoluteRestTransform = new Matrix();
+            let boneAbsoluteBindPoseTransform = new Matrix();
             let boneOrigin = new Vector3();
 
-            this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
-            boneAbsoluteRestTransform.decompose(undefined, undefined, boneOrigin);
+            this._getAbsoluteBindPoseToRef(bone, boneAbsoluteBindPoseTransform);
+            boneAbsoluteBindPoseTransform.decompose(undefined, undefined, boneOrigin);
 
             let m = bone.getBindPose().getRotationMatrix();
 
@@ -864,16 +874,17 @@ export class SkeletonViewer {
     }
 
     /** Sets a display option of the skeleton viewer
-	 *
-     * | Option          | Type    | Default | Description |
-     * | --------------- | ------- | ------- | ----------- |
-     * | midStep         | float   | 0.235   | A percentage between a bone and its child that determines the widest part of a spur. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
-     * | midStepFactor   | float   | 0.15    | Mid step width expressed as a factor of the length. A value of 0.5 makes the spur width half of the spur length. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
-     * | sphereBaseSize  | float   | 2       | Sphere base size. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
-     * | sphereScaleUnit | float   | 0.865   | Sphere scale factor used to scale spheres in relation to the longest bone. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
-     * | showLocalAxes   | boolean | false   | Displays local axes on all bones. |
-	 * | localAxesSize   | float   | 0.075   | Determines the length of each local axis. |
-	 *
+     *
+     * | Option           | Type    | Default | Description |
+     * | ---------------- | ------- | ------- | ----------- |
+     * | midStep          | float   | 0.235   | A percentage between a bone and its child that determines the widest part of a spur. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
+     * | midStepFactor    | float   | 0.15    | Mid step width expressed as a factor of the length. A value of 0.5 makes the spur width half of the spur length. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
+     * | sphereBaseSize   | float   | 2       | Sphere base size. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
+     * | sphereScaleUnit  | float   | 0.865   | Sphere scale factor used to scale spheres in relation to the longest bone. Only used when `displayMode` is set to `DISPLAY_SPHERE_AND_SPURS`. |
+     * | spurFollowsChild | boolean | false   | Whether a spur should attach its far end to the child bone. |
+     * | showLocalAxes    | boolean | false   | Displays local axes on all bones. |
+     * | localAxesSize    | float   | 0.075   | Determines the length of each local axis. |
+     *
      * @param option String of the option name
      * @param value The numerical option value
      */

+ 5 - 1
src/Engines/constants.ts

@@ -284,9 +284,13 @@ export class Constants {
      */
     public static readonly MATERIAL_MiscDirtyFlag = 16;
     /**
+     * The dirty prepass flag value
+     */
+    public static readonly MATERIAL_PrePassDirtyFlag = 32;
+    /**
      * The all dirty flag value
      */
-    public static readonly MATERIAL_AllDirtyFlag = 31;
+    public static readonly MATERIAL_AllDirtyFlag = 63;
 
     /**
      * Returns the triangle fill mode

+ 14 - 0
src/Engines/nativeEngine.ts

@@ -755,6 +755,20 @@ export class NativeEngine extends Engine {
 
         Tools.Log("Babylon Native (v" + Engine.Version + ") launched");
 
+        Tools.LoadScript = function (scriptUrl, onSuccess, onError, scriptId) {
+            Tools.LoadFile(scriptUrl, (data) => {
+                Function(data as string).apply(null);
+                if (onSuccess) {
+                    onSuccess();
+                }
+            }, undefined, undefined, false,
+            (request, exception) => {
+                if (onError) {
+                    onError("LoadScript Error", exception);
+                }
+            });
+        };
+
         // Wrappers
         if (typeof URL === "undefined") {
             (window.URL as any) = {

+ 41 - 5
src/Engines/thinEngine.ts

@@ -130,6 +130,11 @@ export interface EngineOptions extends WebGLContextAttributes {
      * Make the matrix computations to be performed in 64 bits instead of 32 bits. False by default
      */
     useHighPrecisionMatrix?: boolean;
+
+    /**
+     * Will prevent the system from falling back to software implementation if a hardware device cannot be created
+     */
+    failIfMajorPerformanceCaveat?: boolean;
 }
 
 /**
@@ -4432,25 +4437,56 @@ export class ThinEngine {
 
     // Statics
 
-    private static _isSupported: Nullable<boolean> = null;
+    private static _IsSupported: Nullable<boolean> = null;
+    private static _HasMajorPerformanceCaveat : Nullable<boolean> = null;
+
+    /**
+     * Gets a boolean indicating if the engine can be instanciated (ie. if a webGL context can be found)
+     */
+    public static get IsSupported(): boolean {
+        return this.isSupported(); // Backward compat
+    }
+
     /**
      * Gets a boolean indicating if the engine can be instanciated (ie. if a webGL context can be found)
      * @returns true if the engine can be created
      * @ignorenaming
      */
     public static isSupported(): boolean {
-        if (this._isSupported === null) {
+        if (this._HasMajorPerformanceCaveat !== null) {
+            return !this._HasMajorPerformanceCaveat; // We know it is performant so WebGL is supported
+        }
+
+        if (this._IsSupported === null) {
             try {
                 var tempcanvas = CanvasGenerator.CreateCanvas(1, 1);
                 var gl = tempcanvas.getContext("webgl") || (tempcanvas as any).getContext("experimental-webgl");
 
-                this._isSupported = gl != null && !!window.WebGLRenderingContext;
+                this._IsSupported = gl != null && !!window.WebGLRenderingContext;
+            } catch (e) {
+                this._IsSupported = false;
+            }
+        }
+
+        return this._IsSupported;
+    }
+
+    /**
+     * Gets a boolean indicating if the engine can be instanciated on a performant device (ie. if a webGL context can be found and it does not use a slow implementation)
+     */
+    public static get HasMajorPerformanceCaveat(): boolean {
+        if (this._HasMajorPerformanceCaveat === null) {
+            try {
+                var tempcanvas = CanvasGenerator.CreateCanvas(1, 1);
+                var gl = tempcanvas.getContext("webgl", { failIfMajorPerformanceCaveat: true }) || (tempcanvas as any).getContext("experimental-webgl", { failIfMajorPerformanceCaveat: true });
+
+                this._HasMajorPerformanceCaveat = !gl;
             } catch (e) {
-                this._isSupported = false;
+                this._HasMajorPerformanceCaveat = false;
             }
         }
 
-        return this._isSupported;
+        return this._HasMajorPerformanceCaveat;
     }
 
     /**

+ 3 - 3
src/Materials/Node/Blocks/PBR/ambientOcclusionBlock.ts

@@ -29,8 +29,8 @@ export class AmbientOcclusionBlock extends NodeMaterialBlock {
         this.registerInput("intensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("directLightIntensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
 
-        this.registerOutput("ambientOcclusion", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
-            new NodeMaterialConnectionPointCustomObject("ambientOcclusion", this, NodeMaterialConnectionPointDirection.Output, AmbientOcclusionBlock, "AOBlock", "ambientOcc"));
+        this.registerOutput("ambientOcc", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("ambientOcc", this, NodeMaterialConnectionPointDirection.Output, AmbientOcclusionBlock, "AOBlock", "ambientOcc"));
     }
 
     /**
@@ -79,7 +79,7 @@ export class AmbientOcclusionBlock extends NodeMaterialBlock {
     /**
      * Gets the ambient occlusion object output component
      */
-    public get ambientOcclusion(): NodeMaterialConnectionPoint {
+    public get ambientOcc(): NodeMaterialConnectionPoint {
         return this._outputs[0];
     }
 

+ 2 - 2
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -437,7 +437,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     /**
      * Gets the ambient occlusion object parameters
      */
-    public get ambientOcclusion(): NodeMaterialConnectionPoint {
+    public get ambientOcc(): NodeMaterialConnectionPoint {
         return this._inputs[8];
     }
 
@@ -917,7 +917,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state.compilationString += state._emitCodeFromInclude("depthPrePass", comments);
 
         // _____________________________ AO  _______________________________
-        const aoBlock = this.ambientOcclusion.connectedPoint?.ownerBlock as Nullable<AmbientOcclusionBlock>;
+        const aoBlock = this.ambientOcc.connectedPoint?.ownerBlock as Nullable<AmbientOcclusionBlock>;
 
         state.compilationString += AmbientOcclusionBlock.GetCode(aoBlock);
 

+ 2 - 0
src/Materials/Node/nodeMaterialBlock.ts

@@ -741,6 +741,7 @@ export class NodeMaterialBlock {
                 }
                 if (port.isExposedOnFrame) {
                     this.inputs[i].isExposedOnFrame = port.isExposedOnFrame;
+                    this.inputs[i].exposedPortPosition = port.exposedPortPosition;
                 }
             });
         }
@@ -751,6 +752,7 @@ export class NodeMaterialBlock {
                 }
                 if (port.isExposedOnFrame) {
                     this.outputs[i].isExposedOnFrame = port.isExposedOnFrame;
+                    this.outputs[i].exposedPortPosition = port.exposedPortPosition;
                 }
             });
         }

+ 7 - 0
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -152,6 +152,11 @@ export class NodeMaterialConnectionPoint {
     public isExposedOnFrame: boolean =  false;
 
     /**
+     * Gets or sets number indicating the position that the port is exposed to on a frame
+     */
+    public exposedPortPosition: number = -1;
+
+    /**
      * Gets or sets a string indicating that this uniform must be defined under a #ifdef
      */
     public define: string;
@@ -462,10 +467,12 @@ export class NodeMaterialConnectionPoint {
             serializationObject.targetBlockId = this.connectedPoint.ownerBlock.uniqueId;
             serializationObject.targetConnectionName = this.connectedPoint.name;
             serializationObject.isExposedOnFrame = true;
+            serializationObject.exposedPortPosition = this.exposedPortPosition;
         }
 
         if (this.isExposedOnFrame) {
             serializationObject.isExposedOnFrame = this.isExposedOnFrame;
+            serializationObject.exposedPortPosition = this.exposedPortPosition;
         }
 
         return serializationObject;

+ 22 - 1
src/Materials/PBR/pbrBaseMaterial.ts

@@ -15,6 +15,7 @@ import { IMaterialAnisotropicDefines, PBRAnisotropicConfiguration } from "./pbrA
 import { IMaterialBRDFDefines, PBRBRDFConfiguration } from "./pbrBRDFConfiguration";
 import { IMaterialSheenDefines, PBRSheenConfiguration } from "./pbrSheenConfiguration";
 import { IMaterialSubSurfaceDefines, PBRSubSurfaceConfiguration } from "./pbrSubSurfaceConfiguration";
+import { PrePassConfiguration } from "../prePassConfiguration";
 import { Color3, TmpColors } from '../../Maths/math.color';
 import { Scalar } from "../../Maths/math.scalar";
 
@@ -169,11 +170,18 @@ export class PBRMaterialDefines extends MaterialDefines
     public PREPASS_ALBEDO_INDEX = -1;
     public PREPASS_DEPTHNORMAL = false;
     public PREPASS_DEPTHNORMAL_INDEX = -1;
+    public PREPASS_POSITION = false;
+    public PREPASS_POSITION_INDEX = -1;
+    public PREPASS_VELOCITY = false;
+    public PREPASS_VELOCITY_INDEX = -1;
+    public PREPASS_REFLECTIVITY = false;
+    public PREPASS_REFLECTIVITY_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
+    public BONES_VELOCITY_ENABLED = false;
 
     public NONUNIFORMSCALING = false;
 
@@ -223,6 +231,7 @@ export class PBRMaterialDefines extends MaterialDefines
     public CLEARCOAT_TEXTUREDIRECTUV = 0;
     public CLEARCOAT_BUMP = false;
     public CLEARCOAT_BUMPDIRECTUV = 0;
+    public CLEARCOAT_REMAP_F0 = true;
     public CLEARCOAT_TINT = false;
     public CLEARCOAT_TINT_TEXTURE = false;
     public CLEARCOAT_TINT_TEXTUREDIRECTUV = 0;
@@ -816,6 +825,11 @@ export abstract class PBRBaseMaterial extends PushMaterial {
     public readonly subSurface: PBRSubSurfaceConfiguration;
 
     /**
+     * Defines additionnal PrePass parameters for the material.
+     */
+    public readonly prePassConfiguration: PrePassConfiguration;
+
+    /**
      * Defines the detail map parameters for the material.
      */
     public readonly detailMap = new DetailMapConfiguration(this._markAllSubMeshesAsTexturesDirty.bind(this));
@@ -848,6 +862,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
         this._environmentBRDFTexture = BRDFTextureTools.GetEnvironmentBRDFTexture(scene);
         this.subSurface = new PBRSubSurfaceConfiguration(this._markAllSubMeshesAsTexturesDirty.bind(this), this._markScenePrePassDirty.bind(this), scene);
+        this.prePassConfiguration = new PrePassConfiguration();
     }
 
     /**
@@ -1280,6 +1295,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         PBRSheenConfiguration.AddUniforms(uniforms);
         PBRSheenConfiguration.AddSamplers(samplers);
 
+        PrePassConfiguration.AddUniforms(uniforms);
+        PrePassConfiguration.AddSamplers(uniforms);
+
         if (ImageProcessingConfiguration) {
             ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
             ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
@@ -1772,6 +1790,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             this.bindOnlyWorldMatrix(world);
         }
 
+        // PrePass
+        this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen);
+
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
             world.toNormalMatrix(this._normalMatrix);
@@ -1781,7 +1802,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
         // Bones
-        MaterialHelper.BindBonesParameters(mesh, this._activeEffect);
+        MaterialHelper.BindBonesParameters(mesh, this._activeEffect, this.prePassConfiguration);
 
         let reflectionTexture: Nullable<BaseTexture> = null;
         let ubo = this._uniformBuffer;

+ 10 - 0
src/Materials/PBR/pbrClearCoatConfiguration.ts

@@ -21,6 +21,7 @@ export interface IMaterialClearCoatDefines {
     CLEARCOAT_TEXTUREDIRECTUV: number;
     CLEARCOAT_BUMP: boolean;
     CLEARCOAT_BUMPDIRECTUV: number;
+    CLEARCOAT_REMAP_F0: boolean;
 
     CLEARCOAT_TINT: boolean;
     CLEARCOAT_TINT_TEXTURE: boolean;
@@ -79,6 +80,14 @@ export class PBRClearCoatConfiguration {
     @expandToProperty("_markAllSubMeshesAsTexturesDirty")
     public texture: Nullable<BaseTexture> = null;
 
+    private _remapF0OnInterfaceChange = true;
+    /**
+     * Defines if the F0 value should be remapped to account for the interface change in the material.
+     */
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public remapF0OnInterfaceChange = true;
+
     private _bumpTexture: Nullable<BaseTexture> = null;
     /**
      * Define the clear coat specific bump texture.
@@ -186,6 +195,7 @@ export class PBRClearCoatConfiguration {
     public prepareDefines(defines: IMaterialClearCoatDefines, scene: Scene): void {
         if (this._isEnabled) {
             defines.CLEARCOAT = true;
+            defines.CLEARCOAT_REMAP_F0 = this._remapF0OnInterfaceChange;
 
             if (defines._areTexturesDirty) {
                 if (scene.texturesEnabled) {

+ 1 - 0
src/Materials/PBR/pbrSubSurfaceConfiguration.ts

@@ -253,6 +253,7 @@ export class PBRSubSurfaceConfiguration {
     }
     /** @hidden */
     public _markScenePrePassDirty(): void {
+        this._internalMarkAllSubMeshesAsTexturesDirty();
         this._internalMarkScenePrePassDirty();
     }
 

+ 3 - 2
src/Materials/Textures/dynamicTexture.ts

@@ -24,10 +24,11 @@ export class DynamicTexture extends Texture {
      * @param generateMipMaps defines the use of MinMaps or not (default is false)
      * @param samplingMode defines the sampling mode to use (default is Texture.TRILINEAR_SAMPLINGMODE)
      * @param format defines the texture format to use (default is Engine.TEXTUREFORMAT_RGBA)
+     * @param invertY defines if the texture needs to be inverted on the y axis during loading
      */
 
-    constructor(name: string, options: any, scene: Nullable<Scene> = null, generateMipMaps: boolean, samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, format: number = Constants.TEXTUREFORMAT_RGBA) {
-        super(null, scene, !generateMipMaps, undefined, samplingMode, undefined, undefined, undefined, undefined, format);
+    constructor(name: string, options: any, scene: Nullable<Scene> = null, generateMipMaps: boolean, samplingMode: number = Constants.TEXTURE_TRILINEAR_SAMPLINGMODE, format: number = Constants.TEXTUREFORMAT_RGBA, invertY?: boolean) {
+        super(null, scene, !generateMipMaps, invertY, samplingMode, undefined, undefined, undefined, undefined, format);
 
         this.name = name;
         this.wrapU = Texture.CLAMP_ADDRESSMODE;

+ 17 - 0
src/Materials/material.ts

@@ -130,6 +130,11 @@ export class Material implements IAnimatable {
     public static readonly MiscDirtyFlag = Constants.MATERIAL_MiscDirtyFlag;
 
     /**
+     * The dirty prepass flag value
+     */
+    public static readonly PrePassDirtyFlag = Constants.MATERIAL_PrePassDirtyFlag;
+
+    /**
      * The all dirty flag value
      */
     public static readonly AllDirtyFlag = Constants.MATERIAL_AllDirtyFlag;
@@ -1156,6 +1161,7 @@ export class Material implements IAnimatable {
     private static readonly _TextureDirtyCallBack = (defines: MaterialDefines) => defines.markAsTexturesDirty();
     private static readonly _FresnelDirtyCallBack = (defines: MaterialDefines) => defines.markAsFresnelDirty();
     private static readonly _MiscDirtyCallBack = (defines: MaterialDefines) => defines.markAsMiscDirty();
+    private static readonly _PrePassDirtyCallBack = (defines: MaterialDefines) => defines.markAsPrePassDirty();
     private static readonly _LightsDirtyCallBack = (defines: MaterialDefines) => defines.markAsLightDirty();
     private static readonly _AttributeDirtyCallBack = (defines: MaterialDefines) => defines.markAsAttributesDirty();
 
@@ -1207,6 +1213,10 @@ export class Material implements IAnimatable {
             Material._DirtyCallbackArray.push(Material._MiscDirtyCallBack);
         }
 
+        if (flag & Material.PrePassDirtyFlag) {
+            Material._DirtyCallbackArray.push(Material._PrePassDirtyCallBack);
+        }
+
         if (Material._DirtyCallbackArray.length) {
             this._markAllSubMeshesAsDirty(Material._RunDirtyCallBacks);
         }
@@ -1313,6 +1323,13 @@ export class Material implements IAnimatable {
     }
 
     /**
+     * Indicates that prepass needs to be re-calculated for all submeshes
+     */
+    protected _markAllSubMeshesAsPrePassDirty() {
+        this._markAllSubMeshesAsDirty(Material._MiscDirtyCallBack);
+    }
+
+    /**
      * Indicates that textures and misc need to be re-calculated for all submeshes
      */
     protected _markAllSubMeshesAsTexturesAndMiscDirty() {

+ 11 - 0
src/Materials/materialDefines.ts

@@ -21,6 +21,8 @@ export class MaterialDefines {
     /** @hidden */
     public _areMiscDirty = true;
     /** @hidden */
+    public _arePrePassDirty = true;
+    /** @hidden */
     public _areImageProcessingDirty = true;
 
     /** @hidden */
@@ -53,6 +55,7 @@ export class MaterialDefines {
         this._areLightsDirty = false;
         this._areLightsDisposed = false;
         this._areMiscDirty = false;
+        this._arePrePassDirty = false;
         this._areImageProcessingDirty = false;
     }
 
@@ -127,6 +130,14 @@ export class MaterialDefines {
     }
 
     /**
+     * Marks the prepass state as changed
+     */
+    public markAsPrePassDirty() {
+        this._arePrePassDirty = true;
+        this._isDirty = true;
+    }
+
+    /**
      * Rebuilds the material defines
      */
     public rebuild() {

+ 71 - 23
src/Materials/materialHelper.ts

@@ -9,6 +9,7 @@ import { Mesh } from "../Meshes/mesh";
 import { VertexBuffer } from "../Meshes/buffer";
 import { Light } from "../Lights/light";
 import { Constants } from "../Engines/constants";
+import { PrePassConfiguration } from "../Materials/prePassConfiguration";
 
 import { UniformBuffer } from "./uniformBuffer";
 import { Effect, IEffectCreationOptions } from "./effect";
@@ -203,6 +204,12 @@ export class MaterialHelper {
             } else {
                 defines["BonesPerMesh"] = (mesh.skeleton.bones.length + 1);
                 defines["BONETEXTURE"] = materialSupportsBoneTexture ? false : undefined;
+
+                const prePassRenderer = mesh.getScene().prePassRenderer;
+                if (prePassRenderer && prePassRenderer.enabled) {
+                    const nonExcluded = prePassRenderer.excludedSkinnedMesh.indexOf(mesh) === -1;
+                    defines["BONES_VELOCITY_ENABLED"] = nonExcluded;
+                }
             }
         } else {
             defines["NUM_BONE_INFLUENCERS"] = 0;
@@ -303,37 +310,63 @@ export class MaterialHelper {
      * @param canRenderToMRT Indicates if this material renders to several textures in the prepass
      */
     public static PrepareDefinesForPrePass(scene: Scene, defines: any, canRenderToMRT: boolean) {
-        var previousPrePass = defines.PREPASS;
+        const previousPrePass = defines.PREPASS;
+
+        if (!defines._arePrePassDirty) {
+            return;
+        }
+
+        const texturesList = [
+        {
+            type: Constants.PREPASS_POSITION_TEXTURE_TYPE,
+            define: "PREPASS_POSITION",
+            index: "PREPASS_POSITION_INDEX",
+        },
+        {
+            type: Constants.PREPASS_VELOCITY_TEXTURE_TYPE,
+            define: "PREPASS_VELOCITY",
+            index: "PREPASS_VELOCITY_INDEX",
+        },
+        {
+            type: Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE,
+            define: "PREPASS_REFLECTIVITY",
+            index: "PREPASS_REFLECTIVITY_INDEX",
+        },
+        {
+            type: Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE,
+            define: "PREPASS_IRRADIANCE",
+            index: "PREPASS_IRRADIANCE_INDEX",
+        },
+        {
+            type: Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
+            define: "PREPASS_ALBEDO",
+            index: "PREPASS_ALBEDO_INDEX",
+        },
+        {
+            type: Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+            define: "PREPASS_DEPTHNORMAL",
+            index: "PREPASS_DEPTHNORMAL_INDEX",
+        }];
 
         if (scene.prePassRenderer && scene.prePassRenderer.enabled && canRenderToMRT) {
             defines.PREPASS = true;
             defines.SCENE_MRT_COUNT = scene.prePassRenderer.mrtCount;
 
-            const irradianceIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE);
-            if (irradianceIndex !== -1) {
-                defines.PREPASS_IRRADIANCE = true;
-                defines.PREPASS_IRRADIANCE_INDEX = irradianceIndex;
-            } else {
-                defines.PREPASS_IRRADIANCE = false;
-            }
-
-            const albedoIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_ALBEDO_TEXTURE_TYPE);
-            if (albedoIndex !== -1) {
-                defines.PREPASS_ALBEDO = true;
-                defines.PREPASS_ALBEDO_INDEX = albedoIndex;
-            } else {
-                defines.PREPASS_ALBEDO = false;
+            for (let i = 0; i < texturesList.length; i++) {
+                const index = scene.prePassRenderer.getIndex(texturesList[i].type);
+                if (index !== -1) {
+                    defines[texturesList[i].define] = true;
+                    defines[texturesList[i].index] = index;
+                } else {
+                    defines[texturesList[i].define] = false;
+                }
             }
 
-            const depthNormalIndex = scene.prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE);
-            if (depthNormalIndex !== -1) {
-                defines.PREPASS_DEPTHNORMAL = true;
-                defines.PREPASS_DEPTHNORMAL_INDEX = depthNormalIndex;
-            } else {
-                defines.PREPASS_DEPTHNORMAL = false;
-            }
         } else {
             defines.PREPASS = false;
+            for (let i = 0; i < texturesList.length; i++) {
+                defines[texturesList[i].define] = false;
+            }
         }
 
         if (defines.PREPASS != previousPrePass) {
@@ -802,8 +835,9 @@ export class MaterialHelper {
      * Binds the bones information from the mesh to the effect.
      * @param mesh The mesh we are binding the information to render
      * @param effect The effect we are binding the data to
+     * @param prePassConfiguration Configuration for the prepass, in case prepass is activated
      */
-    public static BindBonesParameters(mesh?: AbstractMesh, effect?: Effect): void {
+    public static BindBonesParameters(mesh?: AbstractMesh, effect?: Effect, prePassConfiguration?: PrePassConfiguration): void {
         if (!effect || !mesh) {
             return;
         }
@@ -823,11 +857,25 @@ export class MaterialHelper {
 
                 if (matrices) {
                     effect.setMatrices("mBones", matrices);
+                    if (prePassConfiguration && mesh.getScene().prePassRenderer && mesh.getScene().prePassRenderer!.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE)) {
+                        if (prePassConfiguration.previousBones[mesh.uniqueId]) {
+                            effect.setMatrices("mPreviousBones", prePassConfiguration.previousBones[mesh.uniqueId]);
+                        }
+
+                        MaterialHelper._CopyBonesTransformationMatrices(matrices, prePassConfiguration.previousBones[mesh.uniqueId]);
+                    }
                 }
             }
         }
     }
 
+    // Copies the bones transformation matrices into the target array and returns the target's reference
+    private static _CopyBonesTransformationMatrices(source: Float32Array, target: Float32Array): Float32Array {
+        target.set(source);
+
+        return target;
+    }
+
     /**
      * Binds the morph targets information from the mesh to the effect.
      * @param abstractMesh The mesh we are binding the information to render

+ 70 - 0
src/Materials/prePassConfiguration.ts

@@ -0,0 +1,70 @@
+import { Matrix } from "../Maths/math.vector";
+import { Mesh } from "../Meshes/mesh";
+import { Scene } from "../scene";
+import { Effect } from "../Materials/effect";
+import { Constants } from "../Engines/constants";
+
+/**
+ * Configuration needed for prepass-capable materials
+ */
+export class PrePassConfiguration {
+    /**
+     * Previous world matrices of meshes carrying this material
+     * Used for computing velocity
+     */
+    public previousWorldMatrices: { [index: number]: Matrix } = {};
+    /**
+     * Previous view project matrix
+     * Used for computing velocity
+     */
+    public previousViewProjection: Matrix;
+    /**
+     * Previous bones of meshes carrying this material
+     * Used for computing velocity
+     */
+    public previousBones: { [index: number]: Float32Array } = {};
+
+    /**
+     * Add the required uniforms to the current list.
+     * @param uniforms defines the current uniform list.
+     */
+    public static AddUniforms(uniforms: string[]): void {
+        uniforms.push("previousWorld", "previousViewProjection");
+    }
+
+    /**
+     * Add the required samplers to the current list.
+     * @param samplers defines the current sampler list.
+     */
+    public static AddSamplers(samplers: string[]): void {
+        // pass
+    }
+
+    /**
+     * Binds the material data.
+     * @param effect defines the effect to update
+     * @param scene defines the scene the material belongs to.
+     * @param mesh The mesh
+     * @param world World matrix of this mesh
+     * @param isFrozen Is the material frozen
+     */
+    public bindForSubMesh(effect: Effect, scene: Scene, mesh: Mesh, world: Matrix, isFrozen: boolean): void {
+        if (scene.prePassRenderer && scene.prePassRenderer.enabled) {
+            if (scene.prePassRenderer.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE) !== -1) {
+                if (!this.previousWorldMatrices[mesh.uniqueId]) {
+                    this.previousWorldMatrices[mesh.uniqueId] = Matrix.Identity();
+                }
+
+                if (!this.previousViewProjection) {
+                    this.previousViewProjection = scene.getTransformMatrix();
+                }
+
+                effect.setMatrix("previousWorld", this.previousWorldMatrices[mesh.uniqueId]);
+                effect.setMatrix("previousViewProjection", this.previousViewProjection);
+
+                this.previousWorldMatrices[mesh.uniqueId] = world.clone();
+                this.previousViewProjection = scene.getTransformMatrix().clone();
+            }
+        }
+    }
+}

+ 20 - 0
src/Materials/standardMaterial.ts

@@ -11,6 +11,7 @@ import { VertexBuffer } from "../Meshes/buffer";
 import { SubMesh } from "../Meshes/subMesh";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Mesh } from "../Meshes/mesh";
+import { PrePassConfiguration } from "./prePassConfiguration";
 
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "./imageProcessingConfiguration";
 import { ColorCurves } from "./colorCurves";
@@ -86,6 +87,7 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
+    public BONES_VELOCITY_ENABLED = false;
     public INSTANCES = false;
     public THIN_INSTANCES = false;
     public GLOSSINESS = false;
@@ -132,6 +134,12 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public PREPASS_ALBEDO_INDEX = -1;
     public PREPASS_DEPTHNORMAL = false;
     public PREPASS_DEPTHNORMAL_INDEX = -1;
+    public PREPASS_POSITION = false;
+    public PREPASS_POSITION_INDEX = -1;
+    public PREPASS_VELOCITY = false;
+    public PREPASS_VELOCITY_INDEX = -1;
+    public PREPASS_REFLECTIVITY = false;
+    public PREPASS_REFLECTIVITY_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public RGBDLIGHTMAP = false;
@@ -581,6 +589,11 @@ export class StandardMaterial extends PushMaterial {
     }
 
     /**
+     * Defines additionnal PrePass parameters for the material.
+     */
+    public readonly prePassConfiguration: PrePassConfiguration;
+
+    /**
      * Gets wether the color curves effect is enabled.
      */
     public get cameraColorCurvesEnabled(): boolean {
@@ -713,6 +726,7 @@ export class StandardMaterial extends PushMaterial {
 
         // Setup the default processing configuration to the scene.
         this._attachImageProcessingConfiguration(null);
+        this.prePassConfiguration = new PrePassConfiguration();
 
         this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
             this._renderTargets.reset();
@@ -1190,6 +1204,9 @@ export class StandardMaterial extends PushMaterial {
             DetailMapConfiguration.AddUniforms(uniforms);
             DetailMapConfiguration.AddSamplers(samplers);
 
+            PrePassConfiguration.AddUniforms(uniforms);
+            PrePassConfiguration.AddSamplers(uniforms);
+
             if (ImageProcessingConfiguration) {
                 ImageProcessingConfiguration.PrepareUniforms(uniforms, defines);
                 ImageProcessingConfiguration.PrepareSamplers(samplers, defines);
@@ -1362,6 +1379,9 @@ export class StandardMaterial extends PushMaterial {
             this.bindOnlyWorldMatrix(world);
         }
 
+        // PrePass
+        this.prePassConfiguration.bindForSubMesh(this._activeEffect, scene, mesh, world, this.isFrozen);
+
         // Normal Matrix
         if (defines.OBJECTSPACE_NORMALMAP) {
             world.toNormalMatrix(this._normalMatrix);

+ 35 - 6
src/Misc/khronosTextureContainer2.ts

@@ -7,7 +7,6 @@ declare var KTX2DECODER: any;
 
 /**
  * Class for loading KTX2 files
- * @hidden
  */
 export class KhronosTextureContainer2 {
     private static _WorkerPoolPromise?: Promise<WorkerPool>;
@@ -15,9 +14,24 @@ export class KhronosTextureContainer2 {
     private static _Ktx2Decoder: any; // used when no worker pool is used
 
     /**
-     * URL to use when loading the KTX2 decoder module
+     * URLs to use when loading the KTX2 decoder module as well as its dependencies
+     * If a url is null, the default url is used (pointing to https://preview.babylonjs.com)
+     * Note that jsDecoderModule can't be null and that the other dependencies will only be loaded if necessary
+     * Urls you can change:
+     *     URLConfig.jsDecoderModule
+     *     URLConfig.wasmUASTCToASTC
+     *     URLConfig.wasmUASTCToBC7
+     *     URLConfig.jsMSCTranscoder
+     *     URLConfig.wasmMSCTranscoder
+     * You can see their default values in this PG: https://playground.babylonjs.com/#EIJH8L#9
      */
-    public static JSModuleURL = "https://preview.babylonjs.com/babylon.ktx2Decoder.js";
+    public static URLConfig = {
+        jsDecoderModule: "https://preview.babylonjs.com/babylon.ktx2Decoder.js",
+        wasmUASTCToASTC: null,
+        wasmUASTCToBC7: null,
+        jsMSCTranscoder: null,
+        wasmMSCTranscoder: null
+    };
 
     /**
      * Default number of workers used to handle data decoding
@@ -66,7 +80,7 @@ export class KhronosTextureContainer2 {
 
                         worker.postMessage({
                             action: "init",
-                            jsPath: KhronosTextureContainer2.JSModuleURL
+                            urls: KhronosTextureContainer2.URLConfig
                         });
                     });
                 }
@@ -83,6 +97,7 @@ export class KhronosTextureContainer2 {
 
     /**
      * Constructor
+     * @param engine The engine to use
      * @param numWorkers The number of workers for async operations. Specify `0` to disable web workers and run synchronously in the current context.
      */
     public constructor(engine: ThinEngine, numWorkers = KhronosTextureContainer2.DefaultNumWorkers) {
@@ -93,6 +108,7 @@ export class KhronosTextureContainer2 {
         }
     }
 
+    /** @hidden */
     public uploadAsync(data: ArrayBufferView, internalTexture: InternalTexture): Promise<void> {
         const caps = this._engine.getCaps();
 
@@ -237,13 +253,26 @@ declare function postMessage(message: any, transfer?: any[]): void;
 
 declare var KTX2DECODER: any;
 
-export function workerFunc(): void {
+function workerFunc(): void {
     let ktx2Decoder: any;
 
     onmessage = (event) => {
         switch (event.data.action) {
             case "init":
-                importScripts(event.data.jsPath);
+                const urls = event.data.urls;
+                importScripts(urls.jsDecoderModule);
+                if (urls.wasmUASTCToASTC !== null) {
+                    KTX2DECODER.LiteTranscoder_UASTC_ASTC.WasmModuleURL = urls.wasmUASTCToASTC;
+                }
+                if (urls.wasmUASTCToBC7 !== null) {
+                    KTX2DECODER.LiteTranscoder_UASTC_BC7.WasmModuleURL = urls.wasmUASTCToBC7;
+                }
+                if (urls.jsMSCTranscoder !== null) {
+                    KTX2DECODER.MSCTranscoder.JSModuleURL = urls.jsMSCTranscoder;
+                }
+                if (urls.wasmMSCTranscoder !== null) {
+                    KTX2DECODER.MSCTranscoder.WasmModuleURL = urls.wasmMSCTranscoder;
+                }
                 ktx2Decoder = new KTX2DECODER.KTX2Decoder();
                 postMessage({ action: "init" });
                 break;

+ 1 - 1
src/Navigation/Plugins/recastJSPlugin.ts

@@ -92,7 +92,7 @@ export class RecastJSPlugin implements INavigationEnginePlugin {
                     continue;
                 }
 
-                const wm = mesh.computeWorldMatrix(false);
+                const wm = mesh.computeWorldMatrix(true);
 
                 for (tri = 0; tri < meshIndices.length; tri++) {
                     indices.push(meshIndices[tri] + offset);

+ 4 - 21
src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts

@@ -119,8 +119,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
     */
     private _sampleSphere: number[];
 
-    private _ssao2PrePassConfiguration: SSAO2Configuration;
-
     /**
     * Blur filter offsets
     */
@@ -212,7 +210,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             scene.enableGeometryBufferRenderer();
         } else {
             this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
-            this._prePassRenderer.markAsDirty();
         }
 
         this._createRandomTexture();
@@ -235,7 +232,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         if (cameras) {
             scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
         }
-
     }
 
     // Public Methods
@@ -269,7 +265,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         }
 
         this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
-        this._ssao2PrePassConfiguration.enabled = false;
 
         super.dispose();
     }
@@ -450,6 +445,10 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             effect.setTextureFromPostProcess("originalColor", this._originalColorPostProcess);
         };
         this._ssaoCombinePostProcess.samples = this.textureSamples;
+
+        if (!this._forceGeometryBuffer) {
+            this._ssaoCombinePostProcess._prePassEffectConfiguration = new SSAO2Configuration();
+        }
     }
 
     private _createRandomTexture(): void {
@@ -508,22 +507,6 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
     public static Parse(source: any, scene: Scene, rootUrl: string): SSAO2RenderingPipeline {
         return SerializationHelper.Parse(() => new SSAO2RenderingPipeline(source._name, scene, source._ratio), source, scene, rootUrl);
     }
-
-    /**
-     * Sets the required values to the prepass renderer.
-     * @param prePassRenderer defines the prepass renderer to setup
-     * @returns true if the pre pass is needed.
-     */
-    public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
-        let cfg = this._ssao2PrePassConfiguration;
-        if (!cfg) {
-            cfg = new SSAO2Configuration();
-        }
-
-        cfg.enabled = true;
-        this._ssao2PrePassConfiguration = prePassRenderer.addEffectConfiguration(cfg);
-        return true;
-    }
 }
 
 _TypeStore.RegisteredTypes["BABYLON.SSAO2RenderingPipeline"] = SSAO2RenderingPipeline;

+ 48 - 12
src/PostProcesses/motionBlurPostProcess.ts

@@ -7,6 +7,8 @@ import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Constants } from "../Engines/constants";
 import { GeometryBufferRenderer } from "../Rendering/geometryBufferRenderer";
 import { AbstractMesh } from "../Meshes/abstractMesh";
+import { MotionBlurConfiguration } from "../Rendering/motionBlurConfiguration";
+import { PrePassRenderer } from "../Rendering/prePassRenderer";
 
 import "../Animations/animatable";
 import '../Rendering/geometryBufferRendererSceneComponent';
@@ -56,7 +58,10 @@ export class MotionBlurPostProcess extends PostProcess {
 
     @serialize("motionBlurSamples")
     private _motionBlurSamples: number = 32;
+
+    private _forceGeometryBuffer: boolean = false;
     private _geometryBufferRenderer: Nullable<GeometryBufferRenderer>;
+    private _prePassRenderer: PrePassRenderer;
 
     /**
      * Gets a string identifying the name of the class
@@ -77,20 +82,31 @@ export class MotionBlurPostProcess extends PostProcess {
      * @param reusable If the post process can be reused on the same frame. (default: false)
      * @param textureType Type of textures used when performing the post process. (default: 0)
      * @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)
+     * @param forceGeometryBuffer If this post process should use geometry buffer instead of prepass (default: false)
      */
-    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false, forceGeometryBuffer = false) {
         super(name, "motionBlur", ["motionStrength", "motionScale", "screenSize"], ["velocitySampler"], options, camera, samplingMode, engine, reusable, "#define GEOMETRY_SUPPORTED\n#define SAMPLES 64.0", textureType, undefined, null, blockCompilation);
 
-        this._geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+        this._forceGeometryBuffer = forceGeometryBuffer;
+
+        // Set up assets
+        if (this._forceGeometryBuffer) {
+            this._geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+
+            if (this._geometryBufferRenderer) {
+                this._geometryBufferRenderer.enableVelocity = true;
+            }
+        } else {
+            this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
+            this._prePassRenderer.markAsDirty();
+            this._prePassEffectConfiguration = new MotionBlurConfiguration();
+        }
 
-        if (!this._geometryBufferRenderer) {
-            // Geometry buffer renderer is not supported. So, work as a passthrough.
+        if (!this._geometryBufferRenderer && !this._prePassRenderer) {
+            // We can't get a velocity texture. So, work as a passthrough.
             Logger.Warn("Multiple Render Target support needed to compute object based motion blur");
             this.updateEffect();
         } else {
-            // Geometry buffer renderer is supported.
-            this._geometryBufferRenderer.enableVelocity = true;
-
             this.onApply = (effect: Effect) => {
                 effect.setVector2("screenSize", new Vector2(this.width, this.height));
 
@@ -100,6 +116,9 @@ export class MotionBlurPostProcess extends PostProcess {
                 if (this._geometryBufferRenderer) {
                     const velocityIndex = this._geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE);
                     effect.setTexture("velocitySampler", this._geometryBufferRenderer.getGBuffer().textures[velocityIndex]);
+                } else {
+                    const velocityIndex = this._prePassRenderer.getIndex(Constants.PREPASS_VELOCITY_TEXTURE_TYPE);
+                    effect.setTexture("velocitySampler", this._prePassRenderer.prePassRT.textures[velocityIndex]);
                 }
             };
         }
@@ -111,8 +130,16 @@ export class MotionBlurPostProcess extends PostProcess {
      * @param skinnedMesh The mesh containing the skeleton to ignore when computing the velocity map.
      */
     public excludeSkinnedMesh(skinnedMesh: AbstractMesh): void {
-        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
-            this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.push(skinnedMesh);
+        if (skinnedMesh.skeleton) {
+            let list;
+            if (this._geometryBufferRenderer) {
+                list = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity;
+            } else if (this._prePassRenderer) {
+                list = this._prePassRenderer.excludedSkinnedMesh;
+            } else {
+                return;
+            }
+            list.push(skinnedMesh);
         }
     }
 
@@ -122,10 +149,19 @@ export class MotionBlurPostProcess extends PostProcess {
      * @see excludeSkinnedMesh to exclude a skinned mesh from bones velocity computation.
      */
     public removeExcludedSkinnedMesh(skinnedMesh: AbstractMesh): void {
-        if (this._geometryBufferRenderer && skinnedMesh.skeleton) {
-            const index = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.indexOf(skinnedMesh);
+        if (skinnedMesh.skeleton) {
+            let list;
+            if (this._geometryBufferRenderer) {
+                list = this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity;
+            } else if (this._prePassRenderer) {
+                list = this._prePassRenderer.excludedSkinnedMesh;
+            } else {
+                return;
+            }
+
+            const index = list.indexOf(skinnedMesh);
             if (index !== -1) {
-                this._geometryBufferRenderer.excludedSkinnedMeshesFromVelocity.splice(index, 1);
+                list.splice(index, 1);
             }
         }
     }

+ 23 - 0
src/PostProcesses/postProcess.ts

@@ -19,6 +19,8 @@ declare type Scene = import("../scene").Scene;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
 declare type WebVRFreeCamera = import("../Cameras/VR/webVRCamera").WebVRFreeCamera;
 declare type Animation = import("../Animations/animation").Animation;
+declare type PrePassRenderer = import("../Rendering/prePassRenderer").PrePassRenderer;
+declare type PrePassEffectConfiguration = import("../Rendering/prePassEffectConfiguration").PrePassEffectConfiguration;
 
 /**
  * Size options for a post process
@@ -187,6 +189,12 @@ export class PostProcess {
     private _forcedOutputTexture: Nullable<InternalTexture>;
 
     /**
+    * Prepass configuration in case this post process needs a texture from prepass
+    * @hidden
+    */
+    public _prePassEffectConfiguration: PrePassEffectConfiguration;
+
+    /**
      * Returns the fragment url or shader name used in the post process.
      * @returns the fragment url or name in the shader store.
      */
@@ -679,6 +687,21 @@ export class PostProcess {
     }
 
     /**
+     * Sets the required values to the prepass renderer.
+     * @param prePassRenderer defines the prepass renderer to setup.
+     * @returns true if the pre pass is needed.
+     */
+    public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
+        if (this._prePassEffectConfiguration) {
+            this._prePassEffectConfiguration = prePassRenderer.addEffectConfiguration(this._prePassEffectConfiguration);
+            this._prePassEffectConfiguration.enabled = true;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Disposes the post process.
      * @param camera The camera to dispose the post process on.
      */

+ 47 - 17
src/PostProcesses/screenSpaceReflectionPostProcess.ts

@@ -5,6 +5,8 @@ import { PostProcess, PostProcessOptions } from "./postProcess";
 import { Constants } from "../Engines/constants";
 import { GeometryBufferRenderer } from '../Rendering/geometryBufferRenderer';
 import { serialize, SerializationHelper } from '../Misc/decorators';
+import { PrePassRenderer } from "../Rendering/prePassRenderer";
+import { ScreenSpaceReflectionsConfiguration } from "../Rendering/screenSpaceReflectionsConfiguration";
 
 import "../Shaders/screenSpaceReflection.fragment";
 import { _TypeStore } from '../Misc/typeStore';
@@ -43,7 +45,9 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
     @serialize()
     public roughnessFactor: number = 0.2;
 
+    private _forceGeometryBuffer: boolean = false;
     private _geometryBufferRenderer: Nullable<GeometryBufferRenderer>;
+    private _prePassRenderer: PrePassRenderer;
     private _enableSmoothReflections: boolean = false;
     private _reflectionSamples: number = 64;
     private _smoothSteps: number = 5;
@@ -67,8 +71,9 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
      * @param reusable If the post process can be reused on the same frame. (default: false)
      * @param textureType Type of textures used when performing the post process. (default: 0)
      * @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)
+     * @param forceGeometryBuffer If this post process should use geometry buffer instead of prepass (default: false)
      */
-    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+    constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false, forceGeometryBuffer = false) {
         super(name, "screenSpaceReflection", [
             "projection", "view", "threshold", "reflectionSpecularFalloffExponent", "strength", "step", "roughnessFactor"
         ], [
@@ -77,31 +82,53 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
         "#define SSR_SUPPORTED\n#define REFLECTION_SAMPLES 64\n#define SMOOTH_STEPS 5\n",
         textureType, undefined, null, blockCompilation);
 
-        // Get geometry buffer renderer and update effect
-        const geometryBufferRenderer = scene.enableGeometryBufferRenderer();
-        if (geometryBufferRenderer) {
-            if (geometryBufferRenderer.isSupported) {
-                geometryBufferRenderer.enablePosition = true;
-                geometryBufferRenderer.enableReflectivity = true;
-                this._geometryBufferRenderer = geometryBufferRenderer;
+        this._forceGeometryBuffer = forceGeometryBuffer;
+
+        if (this._forceGeometryBuffer) {
+            // Get geometry buffer renderer and update effect
+            const geometryBufferRenderer = scene.enableGeometryBufferRenderer();
+            if (geometryBufferRenderer) {
+                if (geometryBufferRenderer.isSupported) {
+                    geometryBufferRenderer.enablePosition = true;
+                    geometryBufferRenderer.enableReflectivity = true;
+                    this._geometryBufferRenderer = geometryBufferRenderer;
+                }
             }
+        } else {
+            this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
+            this._prePassRenderer.markAsDirty();
+            this._prePassEffectConfiguration = new ScreenSpaceReflectionsConfiguration();
         }
 
         this._updateEffectDefines();
 
         // On apply, send uniforms
         this.onApply = (effect: Effect) => {
-            if (!geometryBufferRenderer) {
+            const geometryBufferRenderer = this._geometryBufferRenderer;
+            const prePassRenderer = this._prePassRenderer;
+
+            if (!prePassRenderer && !geometryBufferRenderer) {
                 return;
             }
 
-            // Samplers
-            const positionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
-            const roughnessIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE);
-
-            effect.setTexture("normalSampler", geometryBufferRenderer.getGBuffer().textures[1]);
-            effect.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[positionIndex]);
-            effect.setTexture("reflectivitySampler", geometryBufferRenderer.getGBuffer().textures[roughnessIndex]);
+            if (geometryBufferRenderer) {
+                // Samplers
+                const positionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
+                const roughnessIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE);
+
+                effect.setTexture("normalSampler", geometryBufferRenderer.getGBuffer().textures[1]);
+                effect.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[positionIndex]);
+                effect.setTexture("reflectivitySampler", geometryBufferRenderer.getGBuffer().textures[roughnessIndex]);
+            } else {
+                // Samplers
+                const positionIndex = prePassRenderer.getIndex(Constants.PREPASS_POSITION_TEXTURE_TYPE);
+                const roughnessIndex = prePassRenderer.getIndex(Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE);
+                const normalIndex = prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE);
+
+                effect.setTexture("normalSampler", prePassRenderer.prePassRT.textures[normalIndex]);
+                effect.setTexture("positionSampler", prePassRenderer.prePassRT.textures[positionIndex]);
+                effect.setTexture("reflectivitySampler", prePassRenderer.prePassRT.textures[roughnessIndex]);
+            }
 
             // Uniforms
             const camera = scene.activeCamera;
@@ -192,8 +219,11 @@ export class ScreenSpaceReflectionPostProcess extends PostProcess {
 
     private _updateEffectDefines(): void {
         const defines: string[] = [];
-        if (this._geometryBufferRenderer) {
+        if (this._geometryBufferRenderer || this._prePassRenderer) {
             defines.push("#define SSR_SUPPORTED");
+            if (this._prePassRenderer) {
+                defines.push("#define PREPASS_LAYOUT");
+            }
         }
         if (this._enableSmoothReflections) {
             defines.push("#define ENABLE_SMOOTH_REFLECTIONS");

+ 26 - 0
src/Rendering/motionBlurConfiguration.ts

@@ -0,0 +1,26 @@
+import { Constants } from "../Engines/constants";
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+
+/**
+ * Contains all parameters needed for the prepass to perform
+ * motion blur
+ */
+export class MotionBlurConfiguration implements PrePassEffectConfiguration {
+    /**
+     * Is motion blur enabled
+     */
+    public enabled = false;
+
+    /**
+     * Name of the configuration
+     */
+    public name = "motionBlur";
+
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    public readonly texturesRequired: number[] = [
+        Constants.PREPASS_VELOCITY_TEXTURE_TYPE
+    ];
+}

+ 1 - 1
src/Rendering/prePassEffectConfiguration.ts

@@ -23,7 +23,7 @@ export interface PrePassEffectConfiguration {
     /**
      * Disposes the effect configuration
      */
-    dispose(): void;
+    dispose?: () => void;
     /**
      * Creates the associated post process
      */

+ 36 - 35
src/Rendering/prePassRenderer.ts

@@ -5,10 +5,13 @@ import { Constants } from "../Engines/constants";
 import { ImageProcessingPostProcess } from "../PostProcesses/imageProcessingPostProcess";
 import { PostProcess } from "../PostProcesses/postProcess";
 import { Effect } from "../Materials/effect";
-import { Logger } from '../Misc/logger';
 import { _DevTools } from '../Misc/devTools';
 import { Color4 } from "../Maths/math.color";
 import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { Nullable } from "../types";
+import { AbstractMesh } from '../Meshes/abstractMesh';
+import { Material } from '../Materials/material';
+
 /**
  * Renders a pre pass of the scene
  * This means every mesh in the scene will be rendered to a render target texture
@@ -50,7 +53,12 @@ export class PrePassRenderer {
             type: Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
             format: Constants.TEXTURETYPE_UNSIGNED_INT,
         },
-];
+    ];
+
+    /**
+     * To save performance, we can excluded skinned meshes from the prepass
+     */
+    public excludedSkinnedMesh: AbstractMesh[] = [];
 
     private _textureIndices: number[] = [];
 
@@ -86,16 +94,6 @@ export class PrePassRenderer {
      */
     private _effectConfigurations: PrePassEffectConfiguration[] = [];
 
-    /**
-     * Should materials render their geometry on the MRT
-     */
-    public materialsShouldRenderGeometry: boolean = false;
-
-    /**
-     * Should materials render the irradiance information on the MRT
-     */
-    public materialsShouldRenderIrradiance: boolean = false;
-
     private _mrtFormats: number[] = [];
     private _mrtLayout: number[];
 
@@ -259,16 +257,6 @@ export class PrePassRenderer {
         }
     }
 
-    private _checkTextureType(type: number) : boolean {
-        if (type < 0 || type >= this._textureFormats.length) {
-            Logger.Error("PrePassRenderer : Unknown texture type");
-            return false;
-        }
-
-        return true;
-
-    }
-
     /**
      * Adds an effect configuration to the prepass.
      * If an effect has already been added, it won't add it twice and will return the configuration
@@ -294,10 +282,6 @@ export class PrePassRenderer {
      * @return The index
      */
     public getIndex(type: number) : number {
-        if (!this._checkTextureType(type)) {
-            return -1;
-        }
-
         return this._textureIndices[type];
     }
 
@@ -389,9 +373,6 @@ export class PrePassRenderer {
     private _enableTextures(types: number[]) {
         for (let i = 0; i < types.length; i++) {
             let type = types[i];
-            if (!this._checkTextureType(type)) {
-                return;
-            }
 
             if (this._textureIndices[type] === -1) {
                 this._textureIndices[type] = this._mrtLayout.length;
@@ -413,13 +394,22 @@ export class PrePassRenderer {
             }
         }
 
-        const pipelines = this._scene.postProcessRenderPipelineManager.supportedPipelines;
-        for (let i = 0; i < pipelines.length; i++) {
-            if (pipelines[i].setPrePassRenderer(this)) {
-                enablePrePass = true;
+        const camera = this._scene.activeCamera;
+        if (!camera) {
+            return;
+        }
+
+        const postProcesses = (<Nullable<PostProcess[]>>camera._postProcesses.filter((pp) => { return pp != null; }));
+
+        if (postProcesses) {
+            for (let i = 0; i < postProcesses.length; i++) {
+                if (postProcesses[i].setPrePassRenderer(this)) {
+                    enablePrePass = true;
+                }
             }
         }
 
+        this._markAllMaterialsAsPrePassDirty();
         this._isDirty = false;
 
         if (enablePrePass) {
@@ -427,7 +417,16 @@ export class PrePassRenderer {
         }
 
         if (!this.enabled) {
-            this._engine.bindAttachments(this._defaultAttachments);
+            // Prepass disabled, we render only on 1 color attachment
+            this._engine.bindAttachments([this._engine._gl.COLOR_ATTACHMENT0]);
+        }
+    }
+
+    private _markAllMaterialsAsPrePassDirty() {
+        const materials = this._scene.materials;
+
+        for (let i = 0; i < materials.length; i++) {
+            materials[i].markAsDirty(Material.PrePassDirtyFlag);
         }
     }
 
@@ -436,7 +435,9 @@ export class PrePassRenderer {
      */
     public dispose() {
         for (let i = 0; i < this._effectConfigurations.length; i++) {
-            this._effectConfigurations[i].dispose();
+            if (this._effectConfigurations[i].dispose) {
+                this._effectConfigurations[i].dispose!();
+            }
         }
 
         this.imageProcessingPostProcess.dispose();

+ 28 - 0
src/Rendering/screenSpaceReflectionsConfiguration.ts

@@ -0,0 +1,28 @@
+import { Constants } from "../Engines/constants";
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+
+/**
+ * Contains all parameters needed for the prepass to perform
+ * screen space reflections
+ */
+export class ScreenSpaceReflectionsConfiguration implements PrePassEffectConfiguration {
+    /**
+     * Is ssr enabled
+     */
+    public enabled = false;
+
+    /**
+     * Name of the configuration
+     */
+    public name = "screenSpaceReflections";
+
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    public readonly texturesRequired: number[] = [
+        Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+        Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE,
+        Constants.PREPASS_POSITION_TEXTURE_TYPE,
+    ];
+}

+ 0 - 15
src/Rendering/ssao2Configuration.ts

@@ -23,19 +23,4 @@ export class SSAO2Configuration implements PrePassEffectConfiguration {
     public readonly texturesRequired: number[] = [
         Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE
     ];
-
-    /**
-     * Builds a ssao2 configuration object
-     * @param scene The scene
-     */
-    constructor() {
-
-    }
-
-    /**
-     * Disposes the configuration
-     */
-    public dispose() {
-        // pass
-    }
 }

+ 4 - 1
src/Shaders/ShadersInclude/bonesDeclaration.fx

@@ -4,7 +4,10 @@
 		uniform float boneTextureWidth;
 	#else
 		uniform mat4 mBones[BonesPerMesh];
-	#endif	
+		#ifdef BONES_VELOCITY_ENABLED
+		    uniform mat4 mPreviousBones[BonesPerMesh];
+		#endif
+	#endif
 
 	attribute vec4 matricesIndices;
 	attribute vec4 matricesWeights;

+ 5 - 1
src/Shaders/ShadersInclude/pbrBlockClearcoat.fx

@@ -128,7 +128,11 @@ struct clearcoatOutParams
         // clearCoatRoughness = mix(0.089, 0.6, clearCoatRoughness);
 
         // Remap F0 to account for the change of interface within the material.
-        vec3 specularEnvironmentR0Updated = getR0RemappedForClearCoat(specularEnvironmentR0);
+        #ifdef CLEARCOAT_REMAP_F0
+            vec3 specularEnvironmentR0Updated = getR0RemappedForClearCoat(specularEnvironmentR0);
+        #else
+            vec3 specularEnvironmentR0Updated = specularEnvironmentR0;
+        #endif
         outParams.specularEnvironmentR0 = mix(specularEnvironmentR0, specularEnvironmentR0Updated, clearCoatIntensity);
 
         // Needs to use the geometric normal before bump for this.

+ 3 - 1
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -136,8 +136,10 @@ uniform mat4 view;
     uniform vec3 vDiffusionDistance;
     uniform vec4 vTintColor;
     uniform vec3 vSubSurfaceIntensity;
+#endif
 
-    #ifdef SS_SCATTERING
+#ifdef PREPASS
+    #ifdef PREPASS_IRRADIANCE
         uniform float scatteringDiffusionProfile;
     #endif
 #endif

+ 0 - 16
src/Shaders/ShadersInclude/pbrFragmentExtraDeclaration.fx

@@ -12,19 +12,3 @@ varying vec3 vPositionW;
 #ifdef VERTEXCOLOR
     varying vec4 vColor;
 #endif
-
-#if DEBUGMODE > 0
-    varying vec4 vClipSpacePosition;
-#endif
-
-#ifdef MAINUV1
-    varying vec2 vMainUV1;
-#endif
-
-#ifdef MAINUV2
-    varying vec2 vMainUV2;
-#endif
-
-#ifdef PREPASS
-	varying vec3 vViewPos;
-#endif

+ 9 - 0
src/Shaders/ShadersInclude/prePassDeclaration.fx

@@ -2,4 +2,13 @@
 #extension GL_EXT_draw_buffers : require
 layout(location = 0) out vec4 glFragData[{X}];
 vec4 gl_FragColor;
+
+#ifdef PREPASS_DEPTHNORMAL
+    varying vec3 vViewPos;
+#endif
+#ifdef PREPASS_VELOCITY
+    varying vec4 vCurrentPosition;
+    varying vec4 vPreviousPosition;
+#endif
+
 #endif

+ 37 - 0
src/Shaders/ShadersInclude/prePassVertex.fx

@@ -0,0 +1,37 @@
+#ifdef PREPASS_DEPTHNORMAL
+    vViewPos = (view * worldPos).rgb;
+#endif
+
+#if defined(PREPASS_VELOCITY) && defined(BONES_VELOCITY_ENABLED)
+    vCurrentPosition = viewProjection * worldPos;
+
+#if NUM_BONE_INFLUENCERS > 0
+    mat4 previousInfluence;
+    previousInfluence = mPreviousBones[int(matricesIndices[0])] * matricesWeights[0];
+    #if NUM_BONE_INFLUENCERS > 1
+        previousInfluence += mPreviousBones[int(matricesIndices[1])] * matricesWeights[1];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 2
+        previousInfluence += mPreviousBones[int(matricesIndices[2])] * matricesWeights[2];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 3
+        previousInfluence += mPreviousBones[int(matricesIndices[3])] * matricesWeights[3];
+    #endif
+    #if NUM_BONE_INFLUENCERS > 4
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 5
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 6
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+    #endif  
+    #if NUM_BONE_INFLUENCERS > 7
+        previousInfluence += mPreviousBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+    #endif
+
+    vPreviousPosition = previousViewProjection * previousWorld * previousInfluence * vec4(positionUpdated, 1.0);
+#else
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+#endif

+ 11 - 0
src/Shaders/ShadersInclude/prePassVertexDeclaration.fx

@@ -0,0 +1,11 @@
+#ifdef PREPASS
+#ifdef PREPASS_DEPTHNORMAL
+    varying vec3 vViewPos;
+#endif
+#ifdef PREPASS_VELOCITY
+    uniform mat4 previousWorld;
+    uniform mat4 previousViewProjection;
+    varying vec4 vCurrentPosition;
+    varying vec4 vPreviousPosition;
+#endif
+#endif

+ 6 - 0
src/Shaders/ShadersInclude/subSurfaceScatteringFunctions.fx

@@ -1,8 +1,14 @@
+#ifdef SS_SCATTERING
 vec3 tagLightingForSSS(vec3 color) {
     color.b = max(color.b, HALF_MIN);
 
     return color;
 }
+#else
+vec3 tagLightingForSSS(vec3 color) {
+    return vec3(0., 0., 0.);
+}
+#endif
 
 bool testLightingForSSS(vec3 color)
 {

+ 21 - 4
src/Shaders/default.fragment.fx

@@ -37,10 +37,6 @@ varying vec4 vColor;
 	varying vec2 vMainUV2;
 #endif
 
-#ifdef PREPASS
-	varying vec3 vViewPos;
-#endif
-
 // Helper functions
 #include<helperFunctions>
 
@@ -482,6 +478,20 @@ color.rgb = max(color.rgb, 0.);
 #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 #ifdef PREPASS
     gl_FragData[0] = color; // We can't split irradiance on std material
+    
+    #ifdef PREPASS_POSITION
+    gl_FragData[PREPASS_POSITION_INDEX] = vec4(vPositionW, 1.0);
+    #endif
+
+    #ifdef PREPASS_VELOCITY
+    vec2 a = (vCurrentPosition.xy / vCurrentPosition.w) * 0.5 + 0.5;
+    vec2 b = (vPreviousPosition.xy / vPreviousPosition.w) * 0.5 + 0.5;
+
+    vec2 velocity = abs(a - b);
+    velocity = vec2(pow(velocity.x, 1.0 / 3.0), pow(velocity.y, 1.0 / 3.0)) * sign(a - b) * 0.5 + 0.5;
+
+    gl_FragData[PREPASS_VELOCITY_INDEX] = vec4(velocity, 0.0, 1.0);
+    #endif
 
     #ifdef PREPASS_IRRADIANCE
         gl_FragData[PREPASS_IRRADIANCE_INDEX] = vec4(0.0, 0.0, 0.0, 1.0); //  We can't split irradiance on std material
@@ -494,6 +504,13 @@ color.rgb = max(color.rgb, 0.);
     #ifdef PREPASS_ALBEDO
         gl_FragData[PREPASS_ALBEDO_INDEX] = vec4(0.0, 0.0, 0.0, 1.0); // We can't split albedo on std material
     #endif
+    #ifdef PREPASS_REFLECTIVITY
+        #if defined(SPECULAR)
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = specularMapColor;
+        #else
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(0.0, 0.0, 0.0, 1.0);
+        #endif
+    #endif
 #endif
 	gl_FragColor = color;
 

+ 10 - 7
src/Shaders/default.vertex.fx

@@ -26,10 +26,7 @@ attribute vec4 color;
 
 // Uniforms
 #include<instancesDeclaration>
-
-#ifdef PREPASS
-varying vec3 vViewPos;
-#endif
+#include<prePassVertexDeclaration>
 
 #ifdef MAINUV1
 	varying vec2 vMainUV1;
@@ -128,6 +125,13 @@ void main(void) {
 #define CUSTOM_VERTEX_UPDATE_NORMAL
 
 #include<instancesVertex>
+
+#if defined(PREPASS) && defined(PREPASS_VELOCITY) && !defined(BONES_VELOCITY_ENABLED)
+    // Compute velocity before bones computation
+    vCurrentPosition = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+
 #include<bonesVertex>
 
 	vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
@@ -160,9 +164,8 @@ void main(void) {
 #endif	
 
 	vPositionW = vec3(worldPos);
-	#ifdef PREPASS
-	    vViewPos = (view * worldPos).rgb;
-	#endif
+	
+#include<prePassVertex>
 
 #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
 	vDirectionW = normalize(vec3(finalWorld * vec4(positionUpdated, 0.0)));

+ 23 - 0
src/Shaders/pbr.fragment.fx

@@ -147,6 +147,7 @@ void main(void) {
 
 #if defined(REFLECTIVITY)
     vec4 surfaceMetallicOrReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
+    vec4 baseReflectivity = surfaceMetallicOrReflectivityColorMap;
     #ifndef METALLICWORKFLOW
         surfaceMetallicOrReflectivityColorMap = toLinearSpace(surfaceMetallicOrReflectivityColorMap);
         surfaceMetallicOrReflectivityColorMap.rgb *= vReflectivityInfos.y;
@@ -506,6 +507,20 @@ void main(void) {
     #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 
 #ifdef PREPASS
+    #ifdef PREPASS_POSITION
+    gl_FragData[PREPASS_POSITION_INDEX] = vec4(vPositionW, 1.0);
+    #endif
+
+    #ifdef PREPASS_VELOCITY
+    vec2 a = (vCurrentPosition.xy / vCurrentPosition.w) * 0.5 + 0.5;
+    vec2 b = (vPreviousPosition.xy / vPreviousPosition.w) * 0.5 + 0.5;
+
+    vec2 velocity = abs(a - b);
+    velocity = vec2(pow(velocity.x, 1.0 / 3.0), pow(velocity.y, 1.0 / 3.0)) * sign(a - b) * 0.5 + 0.5;
+
+    gl_FragData[PREPASS_VELOCITY_INDEX] = vec4(velocity, 0.0, 1.0);
+    #endif
+
     #ifdef PREPASS_IRRADIANCE
         vec3 irradiance = finalDiffuse;
         #ifndef UNLIT
@@ -533,6 +548,14 @@ void main(void) {
     #ifdef PREPASS_ALBEDO
         gl_FragData[PREPASS_ALBEDO_INDEX] = vec4(sqAlbedo, 1.0); // albedo, for pre and post scatter
     #endif
+
+    #ifdef PREPASS_REFLECTIVITY
+        #if defined(REFLECTIVITY)
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(baseReflectivity.rgb, 1.0);
+        #else
+            gl_FragData[PREPASS_REFLECTIVITY_INDEX] = vec4(0.0, 0.0, 0.0, 1.0);
+        #endif
+    #endif
 #endif
 
     gl_FragColor = finalColor;

+ 12 - 39
src/Shaders/pbr.vertex.fx

@@ -38,42 +38,9 @@ attribute vec3 position;
 #include<helperFunctions>
 #include<bonesDeclaration>
 
-// Output
-varying vec3 vPositionW;
-
-#ifdef NORMAL
-    varying vec3 vNormalW;
-
-    #if defined(USESPHERICALFROMREFLECTIONMAP) && defined(USESPHERICALINVERTEX)
-        varying vec3 vEnvironmentIrradiance;
-        
-        #include<harmonicsFunctions>
-    #endif
-#endif
-
-#ifdef VERTEXCOLOR
-    varying vec4 vColor;
-#endif
-
-#ifdef REFLECTIONMAP_SKYBOX
-    varying vec3 vPositionUVW;
-#endif
-
-#if DEBUGMODE > 0
-    varying vec4 vClipSpacePosition;
-#endif
-
-#ifdef MAINUV1
-    varying vec2 vMainUV1;
-#endif
-
-#ifdef MAINUV2
-    varying vec2 vMainUV2;
-#endif
-
-#ifdef PREPASS
-varying vec3 vViewPos;
-#endif
+// Uniforms
+#include<instancesDeclaration>
+#include<prePassVertexDeclaration>
 
 #if defined(ALBEDO) && ALBEDODIRECTUV == 0
 varying vec2 vAlbedoUV;
@@ -183,13 +150,19 @@ void main(void) {
 #define CUSTOM_VERTEX_UPDATE_NORMAL
 
 #include<instancesVertex>
+
+#if defined(PREPASS) && defined(PREPASS_VELOCITY) && !defined(BONES_VELOCITY_ENABLED)
+    // Compute velocity before bones computation
+    vCurrentPosition = viewProjection * finalWorld * vec4(positionUpdated, 1.0);
+    vPreviousPosition = previousViewProjection * previousWorld * vec4(positionUpdated, 1.0);
+#endif
+
 #include<bonesVertex>
 
     vec4 worldPos = finalWorld * vec4(positionUpdated, 1.0);
     vPositionW = vec3(worldPos);
-#ifdef PREPASS
-    vViewPos = (view * worldPos).rgb;
-#endif
+
+#include<prePassVertex>
 
 #ifdef NORMAL
     mat3 normalWorld = mat3(finalWorld);

+ 4 - 0
src/Shaders/screenSpaceReflection.fragment.fx

@@ -135,7 +135,11 @@ void main()
         }
         
         // Get coordinates of the pixel to pick according to the pixel's position and normal.
+        #ifdef PREPASS_LAYOUT
+        vec3 normal = (texture2D(normalSampler, vUV)).gba;
+        #else
         vec3 normal = (texture2D(normalSampler, vUV)).xyz;
+        #endif
         vec3 position = (view * texture2D(positionSampler, vUV)).xyz;
         vec3 reflected = normalize(reflect(normalize(position), normalize(normal)));
 

+ 1 - 1
src/XR/webXRFeaturesManager.ts

@@ -342,7 +342,7 @@ export class WebXRFeaturesManager implements IDisposable {
 
             if (attachIfPossible) {
                 // if session started already, request and enable
-                if (this._xrSessionManager.session && !feature.featureImplementation.attached) {
+                if (this._xrSessionManager.session && !this._features[name].featureImplementation.attached) {
                     // enable feature
                     this.attachFeature(name);
                 }

binární
tests/validation/ReferenceImages/geometrybufferrenderer.png


binární
tests/validation/ReferenceImages/motionBlur.png


binární
tests/validation/ReferenceImages/ssr.png


+ 22 - 1
tests/validation/config.json

@@ -79,7 +79,7 @@
         },    
         {
             "title": "Node material PBR 1",
-            "playgroundId": "#D8AK3Z#7",
+            "playgroundId": "#D8AK3Z#15",
             "referenceImage": "node-material-pbr-1.png"
         },    
         {
@@ -908,6 +908,27 @@
             "playgroundId": "#EIJH8L#1",
             "referenceImage": "ktx2decoder.png",
             "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Motion Blur",
+            "playgroundId": "#E5YGEL#2",
+            "referenceImage": "motionBlur.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Screen space reflections",
+            "playgroundId": "#PIZ1GK#172",
+            "referenceImage": "ssr.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
+        },
+        {
+            "title": "Geometry buffer renderer",
+            "playgroundId": "#PIZ1GK#173",
+            "referenceImage": "geometrybufferrenderer.png",
+            "renderCount": 10,
+            "excludeFromAutomaticTesting": true
         }
     ]
 }