Parcourir la source

Merge branch 'master' into resize-editor

Alejandro Toledo il y a 5 ans
Parent
commit
42db1887f5
93 fichiers modifiés avec 7414 ajouts et 2324 suppressions
  1. 26 7
      Playground/src/tools/monacoManager.ts
  2. 549 207
      dist/preview release/babylon.d.ts
  3. 2 2
      dist/preview release/babylon.js
  4. 1591 241
      dist/preview release/babylon.max.js
  5. 1 1
      dist/preview release/babylon.max.js.map
  6. 1292 597
      dist/preview release/babylon.module.d.ts
  7. 549 207
      dist/preview release/documentation.d.ts
  8. 1 1
      dist/preview release/glTF2Interface/package.json
  9. 2 2
      dist/preview release/gui/package.json
  10. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  11. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  12. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  13. 7 7
      dist/preview release/inspector/package.json
  14. 3 3
      dist/preview release/loaders/package.json
  15. 2 2
      dist/preview release/materialsLibrary/package.json
  16. 2 2
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  17. 17 10
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  18. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  19. 2 2
      dist/preview release/nodeEditor/package.json
  20. 1 1
      dist/preview release/package.json
  21. 1 1
      dist/preview release/packagesSizeBaseLine.json
  22. 2 2
      dist/preview release/postProcessesLibrary/package.json
  23. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  24. 12 12
      dist/preview release/serializers/babylon.glTF2Serializer.js
  25. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.js.map
  26. 4 4
      dist/preview release/serializers/babylon.objSerializer.js
  27. 1 1
      dist/preview release/serializers/babylon.objSerializer.js.map
  28. 14 14
      dist/preview release/serializers/babylonjs.serializers.js
  29. 1 1
      dist/preview release/serializers/babylonjs.serializers.js.map
  30. 3 3
      dist/preview release/serializers/package.json
  31. 1292 597
      dist/preview release/viewer/babylon.module.d.ts
  32. 46 34
      dist/preview release/viewer/babylon.viewer.js
  33. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  34. 4 0
      dist/preview release/what's new.md
  35. 2 2
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  36. 1 2
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/defaultTools/defaultTools.ts
  37. 1 1
      nodeEditor/src/components/preview/svgs/directionalLeft.svg
  38. 1 1
      nodeEditor/src/components/preview/svgs/directionalRight.svg
  39. 1 1
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  40. 0 2
      nodeEditor/src/diagram/graphCanvas.tsx
  41. 1 1
      nodeEditor/src/diagram/graphFrame.ts
  42. 12 4
      nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx
  43. 6 1
      nodeEditor/src/sharedComponents/colorPickerComponent.tsx
  44. 1 1
      package.json
  45. 3 2
      src/Bones/bone.ts
  46. 1 1
      src/Bones/skeleton.ts
  47. 6 0
      src/Debug/ISkeletonViewer.ts
  48. 96 13
      src/Debug/skeletonViewer.ts
  49. 28 12
      src/Engines/constants.ts
  50. 66 44
      src/Engines/nativeEngine.ts
  51. 60 20
      src/Engines/nullEngine.ts
  52. 72 34
      src/Engines/thinEngine.ts
  53. 2 2
      src/Gizmos/axisDragGizmo.ts
  54. 2 2
      src/Gizmos/axisScaleGizmo.ts
  55. 2 2
      src/Gizmos/cameraGizmo.ts
  56. 13 0
      src/Gizmos/gizmo.ts
  57. 15 0
      src/Gizmos/gizmoManager.ts
  58. 2 2
      src/Gizmos/lightGizmo.ts
  59. 2 2
      src/Gizmos/planeDragGizmo.ts
  60. 2 2
      src/Gizmos/planeRotationGizmo.ts
  61. 12 0
      src/Gizmos/positionGizmo.ts
  62. 12 0
      src/Gizmos/rotationGizmo.ts
  63. 11 0
      src/Gizmos/scaleGizmo.ts
  64. 5 0
      src/Loading/Plugins/babylonFileLoader.ts
  65. 13 3
      src/Materials/PBR/pbrBaseMaterial.ts
  66. 4 4
      src/Materials/PBR/pbrSubSurfaceConfiguration.ts
  67. 44 18
      src/Materials/Textures/multiRenderTarget.ts
  68. 39 19
      src/Materials/effect.ts
  69. 26 1
      src/Materials/materialHelper.ts
  70. 6 0
      src/Materials/standardMaterial.ts
  71. 1 2
      src/Maths/math.vector.ts
  72. 0 2
      src/Meshes/Builders/capsuleBuilder.ts
  73. 1 1
      src/Meshes/linesMesh.ts
  74. 23 16
      src/Meshes/mesh.ts
  75. 2 2
      src/Misc/decorators.ts
  76. 2 1
      src/Misc/index.ts
  77. 885 0
      src/Misc/trajectoryClassifier.ts
  78. 1 1
      src/Particles/particleSystem.ts
  79. 15 6
      src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts
  80. 9 9
      src/PostProcesses/subSurfaceScatteringPostProcess.ts
  81. 7 5
      src/Rendering/depthRendererSceneComponent.ts
  82. 1 0
      src/Rendering/index.ts
  83. 11 3
      src/Rendering/prePassEffectConfiguration.ts
  84. 153 27
      src/Rendering/prePassRenderer.ts
  85. 2 57
      src/Rendering/prePassRendererSceneComponent.ts
  86. 41 0
      src/Rendering/ssao2Configuration.ts
  87. 26 0
      src/Rendering/subSurfaceConfiguration.ts
  88. 181 0
      src/Rendering/subSurfaceSceneComponent.ts
  89. 13 4
      src/Shaders/default.fragment.fx
  90. 2 2
      src/Shaders/particles.vertex.fx
  91. 22 15
      src/Shaders/pbr.fragment.fx
  92. 9 2
      src/XR/webXRCamera.ts
  93. 1 0
      src/sceneComponent.ts

+ 26 - 7
Playground/src/tools/monacoManager.ts

@@ -120,18 +120,37 @@ export class MonacoManager {
 
     private _setNewContent() {
         this._createEditor();
-        this._editor?.setValue(`// You have to create a function called createScene. This function must return a BABYLON.Scene object
-    // You can reference the following variables: scene, canvas
-    // You must at least define a camera
 
-    var createScene = function() {
+        if(this.globalState.language === "JS"){
+            this._editor?.setValue(`// You have to create a function called createScene. This function must return a BABYLON.Scene object
+// You can reference the following variables: engine, canvas
+// You must at least define a camera
+
+var createScene = function() {
+    var scene = new BABYLON.Scene(engine);
+
+    //var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 12, BABYLON.Vector3.Zero(), scene);
+    var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
+    camera.attachControl(canvas, true);
+
+    return scene;
+};`);
+        } else {
+            this._editor?.setValue(`// You have to create a class called Playground. This class must provide a static function named CreateScene(engine, canvas) which must return a Scene object
+// You must at least define a camera inside the CreateScene function
+
+class Playground {
+    public static CreateScene(engine: BABYLON.Engine, canvas: HTMLCanvasElement): BABYLON.Scene {
         var scene = new BABYLON.Scene(engine);
-        var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 12, BABYLON.Vector3.Zero(), scene);
+
+        //var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 12, BABYLON.Vector3.Zero(), scene);
+        var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
         camera.attachControl(canvas, true);
 
         return scene;
-    };
-        `);
+    }
+}`);
+        }
 
         this.globalState.onRunRequiredObservable.notifyObservers();
 

Fichier diff supprimé car celui-ci est trop grand
+ 549 - 207
dist/preview release/babylon.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/babylon.js


Fichier diff supprimé car celui-ci est trop grand
+ 1591 - 241
dist/preview release/babylon.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/babylon.max.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1292 - 597
dist/preview release/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 549 - 207
dist/preview release/documentation.d.ts


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

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

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

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

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


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

@@ -69738,8 +69738,8 @@ var PBRMaterialPropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Mask From Thickness", target: material.subSurface, propertyName: "useMaskFromThicknessTexture", onValueChanged: function () { return _this.forceUpdate(); }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Tint Color", target: material.subSurface, propertyName: "tintColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable, isLinear: true }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Scattering Enabled", target: material.subSurface, propertyName: "isScatteringEnabled", onValueChanged: function () { return _this.forceUpdate(); }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                material.subSurface.isScatteringEnabled && material.getScene().prePassRenderer &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_7__["SliderLineComponent"], { label: "Meters per unit", target: material.getScene().prePassRenderer.subSurfaceConfiguration, propertyName: "metersPerUnit", minimum: 0.01, maximum: 2, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                material.subSurface.isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_7__["SliderLineComponent"], { label: "Meters per unit", target: material.getScene().subSurfaceConfiguration, propertyName: "metersPerUnit", minimum: 0.01, maximum: 2, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Refraction Enabled", target: material.subSurface, propertyName: "isRefractionEnabled", onValueChanged: function () { return _this.forceUpdate(); }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 material.subSurface.isRefractionEnabled &&
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "fragment" },

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

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

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

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

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

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

Fichier diff supprimé car celui-ci est trop grand
+ 2 - 2
dist/preview release/nodeEditor/babylon.nodeEditor.js


Fichier diff supprimé car celui-ci est trop grand
+ 17 - 10
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


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

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

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

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

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

@@ -1 +1 @@
-{"thinEngineOnly":117404,"engineOnly":153844,"sceneOnly":519314,"minGridMaterial":659006,"minStandardMaterial":809217}
+{"thinEngineOnly":117927,"engineOnly":154367,"sceneOnly":519868,"minGridMaterial":659956,"minStandardMaterial":810491}

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

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

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

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

+ 12 - 12
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-serializers"] = factory(require("babylonjs"));
 	else
 		root["SERIALIZERS"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -400,7 +400,7 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return KHR_lights_punctual; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
@@ -592,7 +592,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return KHR_materials_sheen; });
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
-/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -694,7 +694,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME,
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_unlit", function() { return KHR_materials_unlit; });
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
-/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -761,7 +761,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME,
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return KHR_texture_transform; });
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _shaders_textureTransform_fragment__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../shaders/textureTransform.fragment */ "./glTF/2.0/shaders/textureTransform.fragment.ts");
@@ -944,7 +944,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFAnimation", function() { return _GLTFAnimation; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
 
@@ -1867,7 +1867,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Exporter", function() { return _Exporter; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_BinaryWriter", function() { return _BinaryWriter; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _glTFMaterialExporter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./glTFMaterialExporter */ "./glTF/2.0/glTFMaterialExporter.ts");
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
@@ -3752,7 +3752,7 @@ var __IGLTFExporterExtensionV2 = 0; // I am here to allow dts to be created
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFMaterialExporter", function() { return _GLTFMaterialExporter; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -4972,7 +4972,7 @@ var GLTF2Export = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFUtilities", function() { return _GLTFUtilities; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -5240,7 +5240,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "textureTransformPixelShader", function() { return textureTransformPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'textureTransformPixelShader';
@@ -5356,14 +5356,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/tools":
+/***/ "babylonjs/Maths/math.vector":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
 
 /***/ })
 

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.js.map


+ 4 - 4
dist/preview release/serializers/babylon.objSerializer.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-serializers"] = factory(require("babylonjs"));
 	else
 		root["SERIALIZERS"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -154,7 +154,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OBJExport", function() { return OBJExport; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -341,14 +341,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/tools":
+/***/ "babylonjs/Maths/math.vector":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
 
 /***/ })
 

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylon.objSerializer.js.map


+ 14 - 14
dist/preview release/serializers/babylonjs.serializers.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-serializers"] = factory(require("babylonjs"));
 	else
 		root["SERIALIZERS"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -417,7 +417,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OBJExport", function() { return OBJExport; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -585,7 +585,7 @@ var OBJExport = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return KHR_lights_punctual; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
@@ -777,7 +777,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return KHR_materials_sheen; });
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
-/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -879,7 +879,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME,
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_unlit", function() { return KHR_materials_unlit; });
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
-/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -946,7 +946,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME,
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return KHR_texture_transform; });
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
 /* harmony import */ var _shaders_textureTransform_fragment__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../shaders/textureTransform.fragment */ "./glTF/2.0/shaders/textureTransform.fragment.ts");
@@ -1129,7 +1129,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFAnimation", function() { return _GLTFAnimation; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
 
@@ -2052,7 +2052,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Exporter", function() { return _Exporter; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_BinaryWriter", function() { return _BinaryWriter; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _glTFMaterialExporter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./glTFMaterialExporter */ "./glTF/2.0/glTFMaterialExporter.ts");
 /* harmony import */ var _glTFUtilities__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./glTFUtilities */ "./glTF/2.0/glTFUtilities.ts");
@@ -3937,7 +3937,7 @@ var __IGLTFExporterExtensionV2 = 0; // I am here to allow dts to be created
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFMaterialExporter", function() { return _GLTFMaterialExporter; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -5157,7 +5157,7 @@ var GLTF2Export = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_GLTFUtilities", function() { return _GLTFUtilities; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -5425,7 +5425,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "textureTransformPixelShader", function() { return textureTransformPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'textureTransformPixelShader';
@@ -5769,7 +5769,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "STLExport", function() { return STLExport; });
-/* harmony import */ var babylonjs_Meshes_buffer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Meshes/buffer */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Meshes_buffer__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Meshes/buffer */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Meshes_buffer__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_buffer__WEBPACK_IMPORTED_MODULE_0__);
 
 
@@ -5881,14 +5881,14 @@ var STLExport = /** @class */ (function () {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/tools":
+/***/ "babylonjs/Maths/math.vector":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_tools__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
 
 /***/ })
 

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.js.map


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

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

Fichier diff supprimé car celui-ci est trop grand
+ 1292 - 597
dist/preview release/viewer/babylon.module.d.ts


Fichier diff supprimé car celui-ci est trop grand
+ 46 - 34
dist/preview release/viewer/babylon.viewer.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -23,6 +23,7 @@
 - Refactored React refs from old string API to React.createRef() API ([belfortk](https://github.com/belfortk))
 - Scale on one axis for `BoundingBoxGizmo` ([cedricguillemet](https://github.com/cedricguillemet))
 - Camera gizmo ([cedricguillemet](https://github.com/cedricguillemet))
+- gizmo isHovered boolean ([cedricguillemet](https://github.com/cedricguillemet))
 - Node support (Transform, Bone) for gizmos ([cedricguillemet](https://github.com/cedricguillemet))
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
@@ -105,6 +106,7 @@
 ### Debug
 - Added new view modes to the `SkeletonViewer` class. ([Pryme8](https://github.com/Pryme8))
 - Added static methods to create debug shaders materials for a mesh with a skeleton. ([Pryme8](https://github.com/Pryme8))
+- Added ability to view local rotation axes of bones using new `displayOptions`: `showLocalAxes` and `localAxesSize` ([reimund](https://github.com/reimund))
 
 ### Sprites
 
@@ -197,6 +199,7 @@
 - WebXR hand-tracking module is available, able to track hand-joints on selected devices including optional physics interactions ([RaananW](https://github.com/RaananW))
 - Fixed an issue with moving backwards in XR ([#8854](https://github.com/BabylonJS/Babylon.js/issues/8854)) ([RaananW](https://github.com/RaananW))
 - Hit-Test results can be an empty array ([#8887](https://github.com/BabylonJS/Babylon.js/issues/8887)) ([RaananW](https://github.com/RaananW))
+- XR's main camera uses the first eye's projection matrix ([#8944](https://github.com/BabylonJS/Babylon.js/issues/8944)) ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 
@@ -317,6 +320,7 @@
 - Fixed an issue in `DeviceSourceManager.getDeviceSources()` where null devices are returned ([Drigax](https://github.com/drigax))
 - Fix issue in glTF2 `_Exporter.createSkinsAsync()` that exported an incorrect joint indexing list ([drigax](https://github.com/drigax))
 - Fix gltf2 Morph Target export code style, add additional test case for non-animation group created morph targets ([drigax](https://github.com/drigax))
+- Fix "Uncaught ReferenceError: name is not defined" ([outermeasure](https://github.com/outermeasure))
 
 ## Breaking changes
 

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

@@ -246,8 +246,8 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                     <CheckBoxLineComponent label="Scattering Enabled" target={material.subSurface} propertyName="isScatteringEnabled"
                         onValueChanged={() => this.forceUpdate()}
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    { (material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer &&
-                        <SliderLineComponent label="Meters per unit" target={ material.getScene().prePassRenderer!.subSurfaceConfiguration } propertyName="metersPerUnit" minimum={0.01} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    { (material.subSurface as any).isScatteringEnabled && material.getScene().prePassRenderer && material.getScene().subSurfaceConfiguration &&
+                        <SliderLineComponent label="Meters per unit" target={ material.getScene().subSurfaceConfiguration! } propertyName="metersPerUnit" minimum={0.01} maximum={2} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
                     <CheckBoxLineComponent label="Refraction Enabled" target={material.subSurface} propertyName="isRefractionEnabled"
                         onValueChanged={() => this.forceUpdate()}

+ 1 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/defaultTools/defaultTools.ts

@@ -1,7 +1,6 @@
 import { Paintbrush } from './paintbrush';
 import { Eyedropper } from './eyedropper';
 import { Floodfill } from './floodfill';
-import { Contrast } from './contrast';
 import { RectangleSelect } from './rectangleSelect';
 
-export default [RectangleSelect, Paintbrush, Eyedropper, Floodfill, Contrast];
+export default [RectangleSelect, Paintbrush, Eyedropper, Floodfill];

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
nodeEditor/src/components/preview/svgs/directionalLeft.svg


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
nodeEditor/src/components/preview/svgs/directionalRight.svg


+ 1 - 1
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -67,7 +67,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                 this.setState({ currentNode: null, currentFrame: selection, currentFrameNodePort: null, currentNodePort: null });
             } else if (isFramePortData(selection)) {
                 this.setState({ currentNode: null, currentFrame: selection.frame, currentFrameNodePort: selection.port, currentNodePort: null });
-            } else if (selection instanceof NodePort && selection.hasLabel()) {
+            } else if (selection instanceof NodePort) {
                 this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null, currentNodePort: selection});
             } else {
                 this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null, currentNodePort: null });

+ 0 - 2
nodeEditor/src/diagram/graphCanvas.tsx

@@ -198,8 +198,6 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                     } else {                    
                         this._selectedNodes = [selection];
                     }
-                } else if(selection instanceof NodePort && !selection.hasLabel()){ // if node port is uneditable, select graphNode instead
-                    props.globalState.onSelectionChangedObservable.notifyObservers(selection.node)
                 } else if(selection instanceof NodePort){
                     this._selectedNodes = [];
                     this._selectedFrame = null;

+ 1 - 1
nodeEditor/src/diagram/graphFrame.ts

@@ -1299,7 +1299,7 @@ export class GraphFrame {
             height: this._height,
             color: this._color.asArray(),
             name: this.name,
-            isCollapsed: false, //keeping closed to make reimporting cleaner
+            isCollapsed: true, //keeping closed to make reimporting cleaner
             blocks: this.nodes.map(n => n.block.uniqueId),
             comments: this._comments
         }

+ 12 - 4
nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx

@@ -11,6 +11,7 @@ import { GraphNode } from '../graphNode';
 import { NodeLink } from '../nodeLink';
 import { FramePortData } from '../graphCanvas';
 import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
+import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 
 export interface IFrameNodePortPropertyTabComponentProps {
     globalState: GlobalState
@@ -34,6 +35,14 @@ export class NodePortPropertyTabComponent extends React.Component<IFrameNodePort
     }
 
     render() {
+
+        let info =  this.props.nodePort.hasLabel() ?
+            <>
+            {this.props.nodePort.hasLabel() && <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portName" target={this.props.nodePort} />}
+            {this.props.nodePort.node.enclosingFrameId !== -1 && <CheckBoxLineComponent label= "Expose Port on Frame" target={this.props.nodePort} isSelected={() => this.props.nodePort.exposedOnFrame} onSelect={(value: boolean) => this.toggleExposeOnFrame(value)}  propertyName="exposedOnFrame" disabled={this.props.nodePort.disabled} />}
+            </> :
+            <TextLineComponent label="This node is a constant input node and cannot be exposed to the frame." value=" " ></TextLineComponent>
+
         return (
             <div id="propertyTab">
                 <div id="header">
@@ -43,10 +52,9 @@ export class NodePortPropertyTabComponent extends React.Component<IFrameNodePort
                 </div>
                 </div>
                 <div>
-                    <LineContainerComponent title="GENERAL">
-                        {this.props.nodePort.hasLabel() && <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portName" target={this.props.nodePort} />}
-                        {this.props.nodePort.node.enclosingFrameId !== -1 && <CheckBoxLineComponent label= "Expose Port on Frame" target={this.props.nodePort} isSelected={() => this.props.nodePort.exposedOnFrame} onSelect={(value: boolean) => this.toggleExposeOnFrame(value)}  propertyName="exposedOnFrame" disabled={this.props.nodePort.disabled} />}
-                    </LineContainerComponent>
+                <LineContainerComponent title="GENERAL">
+                   {info}
+                </LineContainerComponent>
                 </div>
             </div>
         );

+ 6 - 1
nodeEditor/src/sharedComponents/colorPickerComponent.tsx

@@ -65,7 +65,12 @@ export class ColorPickerLineComponent extends React.Component<IColorPickerCompon
             || nextState.pickerEnabled !== this.state.pickerEnabled;
         
         if(result) {
-            nextState.color = nextProps.value;
+            nextState.color =  {
+                r: nextProps.value.r * 255,
+                g: nextProps.value.g * 255,
+                b: nextProps.value.b * 255,
+                a: nextProps.value instanceof Color4 ? nextProps.value.a : 1,
+            };
             nextState.hex = nextProps.value.toHexString();
         }
         return result;   

+ 1 - 1
package.json

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

+ 3 - 2
src/Bones/bone.ts

@@ -242,9 +242,9 @@ export class Bone extends Node {
      */
     public returnToRest(): void {
         if (this._skeleton._numBonesWithLinkedTransformNode > 0) {
-            this.updateMatrix(this._restPose.clone(), false, false);
+            this.updateMatrix(this._restPose, false, false);
         } else {
-            this.updateMatrix(this._restPose.clone());
+            this.updateMatrix(this._restPose, false, true);
         }
     }
 
@@ -384,6 +384,7 @@ export class Bone extends Node {
         }
 
         if (updateLocalMatrix) {
+            this._needToCompose = false; // in case there was a pending compose
             this._localMatrix.copyFrom(matrix);
             this._markAsDirtyAndDecompose();
         }

+ 1 - 1
src/Bones/skeleton.ts

@@ -416,7 +416,7 @@ export class Skeleton implements IAnimatable {
      * @returns the original skeleton
      */
     public static MakeAnimationAdditive(skeleton: Skeleton, referenceFrame = 0, range: string): Nullable<Skeleton> {
-        var rangeValue = skeleton.getAnimationRange(name);
+        var rangeValue = skeleton.getAnimationRange(range);
 
         // We can't make a range additive if it doesn't exist
         if (!rangeValue) {

+ 6 - 0
src/Debug/ISkeletonViewer.ts

@@ -42,6 +42,12 @@ export interface ISkeletonViewerDisplayOptions{
 
    /** Ratio for the Sphere Size */
    sphereFactor? : number;
+
+   /** Whether to show local axes or not  */
+   showLocalAxes? : boolean;
+
+   /** Length of each local axis */
+   localAxesSize? : number;
 }
 
 /**

+ 96 - 13
src/Debug/skeletonViewer.ts

@@ -1,5 +1,5 @@
 import { Vector3, Matrix, TmpVectors } from "../Maths/math.vector";
-import { Color3 } from '../Maths/math.color';
+import { Color3, Color4 } from '../Maths/math.color';
 import { Scene } from "../scene";
 import { Nullable } from "../types";
 import { Bone } from "../Bones/bone";
@@ -300,6 +300,9 @@ export class SkeletonViewer {
     /** The SkeletonViewers Mesh. */
     private _debugMesh: Nullable<LinesMesh>;
 
+    /** The local axes Meshes. */
+    private _localAxes: Nullable<LinesMesh> = null;
+
     /** If SkeletonViewer is enabled. */
     private _isEnabled = false;
 
@@ -386,6 +389,8 @@ 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.showLocalAxes = options.displayOptions.showLocalAxes ?? false;
+        options.displayOptions.localAxesSize = options.displayOptions.localAxesSize ?? 0.075;
         options.computeBonesUsingShaders = options.computeBonesUsingShaders ?? true;
         options.useAllBones = options.useAllBones ?? true;
 
@@ -447,6 +452,8 @@ export class SkeletonViewer {
                 break;
             }
         }
+
+        this._buildLocalAxes();
     }
 
     /** Gets or sets a boolean indicating if the viewer is enabled */
@@ -553,6 +560,17 @@ export class SkeletonViewer {
         }
     }
 
+    private getAbsoluteRestPose(bone: Nullable<Bone>, matrix: Matrix) {
+        if (bone === null || bone._index === -1) {
+            matrix.copyFrom(Matrix.Identity());
+            return;
+        }
+
+        this.getAbsoluteRestPose(bone.getParent(), matrix);
+        bone.getBindPose().multiplyToRef(matrix, matrix);
+        return;
+    }
+
     /** function to build and bind sphere joint points and spur bone representations. */
     private _buildSpheresAndSpurs(spheresOnly = true): void {
 
@@ -584,16 +602,6 @@ export class SkeletonViewer {
             }
 
             let longestBoneLength = Number.NEGATIVE_INFINITY;
-            let getAbsoluteRestPose = function(bone: Nullable<Bone>, matrix: Matrix) {
-                if (bone === null || bone._index === -1) {
-                    matrix.copyFrom(Matrix.Identity());
-                    return;
-                }
-                getAbsoluteRestPose(bone.getParent(), matrix);
-                bone.getBindPose().multiplyToRef(matrix, matrix);
-                return;
-            };
-
             let displayOptions = this.options.displayOptions || {};
 
             for (let i = 0; i < bones.length; i++) {
@@ -604,7 +612,7 @@ export class SkeletonViewer {
                 }
 
                 let boneAbsoluteRestTransform = new Matrix();
-                getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
+                this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
 
                 let anchorPoint = new Vector3();
 
@@ -735,6 +743,75 @@ export class SkeletonViewer {
         }
     }
 
+    private _buildLocalAxes(): void {
+        if (this._localAxes) {
+            this._localAxes.dispose();
+        }
+
+        this._localAxes = null;
+
+        let displayOptions = this.options.displayOptions || {};
+
+        if (!displayOptions.showLocalAxes) {
+            return;
+        }
+
+        const targetScene = this._utilityLayer!.utilityLayerScene;
+        const size = displayOptions.localAxesSize || 0.075;
+        let lines = [];
+        let colors = [];
+        let red = new Color4(1, 0, 0, 1);
+        let green = new Color4(0, 1, 0, 1);
+        let blue = new Color4(0, 0, 1, 1);
+
+        let mwk: number[] = [];
+        let mik: number[] = [];
+        const vertsPerBone = 6;
+
+        for (let i in this.skeleton.bones) {
+            let bone = this.skeleton.bones[i];
+
+            if (bone._index === -1 || (!this._boneIndices.has(bone.getIndex()) && !this.options.useAllBones)) {
+                continue;
+            }
+
+            let boneAbsoluteRestTransform = new Matrix();
+            let boneOrigin = new Vector3();
+
+            this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
+            boneAbsoluteRestTransform.decompose(undefined, undefined, boneOrigin);
+
+            let m = bone.getBindPose().getRotationMatrix();
+
+            let boneAxisX = Vector3.TransformCoordinates(new Vector3(0 + size, 0, 0), m);
+            let boneAxisY = Vector3.TransformCoordinates(new Vector3(0, 0 + size, 0), m);
+            let boneAxisZ = Vector3.TransformCoordinates(new Vector3(0, 0, 0 + size), m);
+
+            let axisX = [boneOrigin, boneOrigin.add(boneAxisX)];
+            let axisY = [boneOrigin, boneOrigin.add(boneAxisY)];
+            let axisZ = [boneOrigin, boneOrigin.add(boneAxisZ)];
+
+            let linePoints = [axisX, axisY, axisZ];
+            let lineColors = [[red, red], [green, green], [blue, blue]];
+
+            lines.push(...linePoints);
+            colors.push(...lineColors);
+
+            for (let j = 0; j < vertsPerBone; j++) {
+                mwk.push(1, 0, 0, 0);
+                mik.push(bone.getIndex(), 0, 0, 0);
+            }
+        }
+
+        this._localAxes = LinesBuilder.CreateLineSystem('localAxes', { lines: lines, colors: colors, updatable: true }, targetScene);
+        this._localAxes.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
+        this._localAxes.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
+        this._localAxes.skeleton = this.skeleton;
+        this._localAxes.renderingGroupId = this.renderingGroupId;
+        this._localAxes.parent = this.mesh;
+        this._localAxes.computeBonesUsingShaders = this.options.computeBonesUsingShaders ?? true;
+    }
+
     /** Update the viewer to sync with current skeleton state, only used for the line display. */
     private  _displayLinesUpdate(): void {
         if (!this._utilityLayer) {
@@ -786,7 +863,13 @@ export class SkeletonViewer {
         }
     }
 
-    /** Changes the displayMode of the skeleton viewer
+    /** Sets a display option of the skeleton viewer
+     *
+     * | Option          | Type    | Default | Description |
+     * | --------------- | ------- | ------- | ----------- |
+     * | 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
      */

+ 28 - 12
src/Engines/constants.ts

@@ -486,22 +486,38 @@ export class Constants {
     public static readonly SCENELOADER_DETAILED_LOGGING = 3;
 
     /**
-     * Prepass texture index for color
+     * Constant used to retrieve the irradiance texture index in the textures array in the prepass
+     * using getIndex(Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE)
      */
-    public static readonly PREPASS_COLOR_INDEX = 0;
-
+    public static readonly PREPASS_IRRADIANCE_TEXTURE_TYPE = 0;
     /**
-     * Prepass texture index for irradiance
+     * Constant used to retrieve the position texture index in the textures array in the prepass
+     * using getIndex(Constants.PREPASS_POSITION_TEXTURE_INDEX)
      */
-    public static readonly PREPASS_IRRADIANCE_INDEX = 1;
-
+    public static readonly PREPASS_POSITION_TEXTURE_TYPE = 1;
     /**
-     * Prepass texture index for depth + normal
+     * Constant used to retrieve the velocity texture index in the textures array in the prepass
+     * using getIndex(Constants.PREPASS_VELOCITY_TEXTURE_INDEX)
      */
-    public static readonly PREPASS_DEPTHNORMAL_INDEX = 2;
-
+    public static readonly PREPASS_VELOCITY_TEXTURE_TYPE = 2;
+    /**
+     * Constant used to retrieve the reflectivity texture index in the textures array in the prepass
+     * using the getIndex(Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE)
+     */
+    public static readonly PREPASS_REFLECTIVITY_TEXTURE_TYPE = 3;
+    /**
+     * Constant used to retrieve the lit color texture index in the textures array in the prepass
+     * using the getIndex(Constants.PREPASS_COLOR_TEXTURE_TYPE)
+     */
+    public static readonly PREPASS_COLOR_TEXTURE_TYPE = 4;
+    /**
+     * Constant used to retrieve depth + normal index in the textures array in the prepass
+     * using the getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE)
+     */
+    public static readonly PREPASS_DEPTHNORMAL_TEXTURE_TYPE = 5;
     /**
-     * Prepass texture index for albedo
+     * Constant used to retrieve albedo index in the textures array in the prepass
+     * using the getIndex(Constants.PREPASS_ALBEDO_TEXTURE_TYPE)
      */
-    public static readonly PREPASS_ALBEDO_INDEX = 3;
-}
+    public static readonly PREPASS_ALBEDO_TEXTURE_TYPE = 6;
+}

+ 66 - 44
src/Engines/nativeEngine.ts

@@ -691,180 +691,202 @@ export class NativeEngine extends Engine {
         return this._alphaMode;
     }
 
-    public setInt(uniform: WebGLUniformLocation, int: number): void {
+    public setInt(uniform: WebGLUniformLocation, int: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setInt(uniform, int);
+        return true;
     }
 
-    public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setIntArray(uniform, array);
+        return true;
     }
 
-    public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setIntArray2(uniform, array);
+        return true;
     }
 
-    public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setIntArray3(uniform, array);
+        return true;
     }
 
-    public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setIntArray4(uniform, array);
+        return true;
     }
 
-    public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray(uniform, array);
+        return true;
     }
 
-    public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray2(uniform, array);
+        return true;
     }
 
-    public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray3(uniform, array);
+        return true;
     }
 
-    public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray4(uniform, array);
+        return true;
     }
 
-    public setArray(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray(uniform: WebGLUniformLocation, array: number[]): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray(uniform, array);
+        return true;
     }
 
-    public setArray2(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray2(uniform: WebGLUniformLocation, array: number[]): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray2(uniform, array);
+        return true;
     }
 
-    public setArray3(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray3(uniform: WebGLUniformLocation, array: number[]): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray3(uniform, array);
+        return true;
     }
 
-    public setArray4(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray4(uniform: WebGLUniformLocation, array: number[]): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloatArray4(uniform, array);
+        return true;
     }
 
-    public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
+    public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setMatrices(uniform, matrices);
+        return true;
     }
 
-    public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
+    public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setMatrix3x3(uniform, matrix);
+        return true;
     }
 
-    public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void {
+    public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setMatrix2x2(uniform, matrix);
+        return true;
     }
 
-    public setFloat(uniform: WebGLUniformLocation, value: number): void {
+    public setFloat(uniform: WebGLUniformLocation, value: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat(uniform, value);
+        return true;
     }
 
-    public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void {
+    public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat2(uniform, x, y);
+        return true;
     }
 
-    public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void {
+    public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat3(uniform, x, y, z);
+        return true;
     }
 
-    public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
+    public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat4(uniform, x, y, z, w);
+        return true;
     }
 
-    public setColor3(uniform: WebGLUniformLocation, color3: Color3): void {
+    public setColor3(uniform: WebGLUniformLocation, color3: Color3): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat3(uniform, color3.r, color3.g, color3.b);
+        return true;
     }
 
-    public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): void {
+    public setColor4(uniform: WebGLUniformLocation, color3: Color3, alpha: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._native.setFloat4(uniform, color3.r, color3.g, color3.b, alpha);
+        return true;
     }
 
     public wipeCaches(bruteForce?: boolean): void {

+ 60 - 20
src/Engines/nullEngine.ts

@@ -290,128 +290,160 @@ export class NullEngine extends Engine {
      * Set the value of an uniform to an array of int32
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if value was set
      */
-    public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray(uniform: WebGLUniformLocation, array: Int32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if value was set
      */
-    public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray2(uniform: WebGLUniformLocation, array: Int32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if value was set
      */
-    public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray3(uniform: WebGLUniformLocation, array: Int32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec4)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if value was set
      */
-    public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): void {
+    public setIntArray4(uniform: WebGLUniformLocation, array: Int32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of float32 to store
+     * @returns true if value was set
      */
-    public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray(uniform: WebGLUniformLocation, array: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32 (stored as vec2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of float32 to store
+     * @returns true if value was set
      */
-    public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray2(uniform: WebGLUniformLocation, array: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32 (stored as vec3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of float32 to store
+     * @returns true if value was set
      */
-    public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray3(uniform: WebGLUniformLocation, array: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32 (stored as vec4)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of float32 to store
+     * @returns true if value was set
      */
-    public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): void {
+    public setFloatArray4(uniform: WebGLUniformLocation, array: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if value was set
      */
-    public setArray(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray(uniform: WebGLUniformLocation, array: number[]): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if value was set
      */
-    public setArray2(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray2(uniform: WebGLUniformLocation, array: number[]): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if value was set
      */
-    public setArray3(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray3(uniform: WebGLUniformLocation, array: number[]): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec4)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if value was set
      */
-    public setArray4(uniform: WebGLUniformLocation, array: number[]): void {
+    public setArray4(uniform: WebGLUniformLocation, array: number[]): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32 (stored as matrices)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrices defines the array of float32 to store
+     * @returns true if value was set
      */
-    public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): void {
+    public setMatrices(uniform: WebGLUniformLocation, matrices: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to a matrix (3x3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrix defines the Float32Array representing the 3x3 matrix to store
+     * @returns true if value was set
      */
-    public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): void {
+    public setMatrix3x3(uniform: WebGLUniformLocation, matrix: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to a matrix (2x2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrix defines the Float32Array representing the 2x2 matrix to store
+     * @returns true if value was set
      */
-    public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): void {
+    public setMatrix2x2(uniform: WebGLUniformLocation, matrix: Float32Array): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to a number (float)
      * @param uniform defines the webGL uniform location where to store the value
      * @param value defines the float number to store
+     * @returns true if value was set
      */
-    public setFloat(uniform: WebGLUniformLocation, value: number): void {
+    public setFloat(uniform: WebGLUniformLocation, value: number): boolean {
+        return true;
     }
 
     /**
@@ -419,8 +451,10 @@ export class NullEngine extends Engine {
      * @param uniform defines the webGL uniform location where to store the value
      * @param x defines the 1st component of the value
      * @param y defines the 2nd component of the value
+     * @returns true if value was set
      */
-    public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): void {
+    public setFloat2(uniform: WebGLUniformLocation, x: number, y: number): boolean {
+        return true;
     }
 
     /**
@@ -429,16 +463,20 @@ export class NullEngine extends Engine {
      * @param x defines the 1st component of the value
      * @param y defines the 2nd component of the value
      * @param z defines the 3rd component of the value
+     * @returns true if value was set
      */
-    public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): void {
+    public setFloat3(uniform: WebGLUniformLocation, x: number, y: number, z: number): boolean {
+        return true;
     }
 
     /**
      * Set the value of an uniform to a boolean
      * @param uniform defines the webGL uniform location where to store the value
      * @param bool defines the boolean to store
+     * @returns true if value was set
      */
-    public setBool(uniform: WebGLUniformLocation, bool: number): void {
+    public setBool(uniform: WebGLUniformLocation, bool: number): boolean {
+        return true;
     }
 
     /**
@@ -448,8 +486,10 @@ export class NullEngine extends Engine {
      * @param y defines the 2nd component of the value
      * @param z defines the 3rd component of the value
      * @param w defines the 4th component of the value
+     * @returns true if value was set
      */
-    public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void {
+    public setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): boolean {
+        return true;
     }
 
     /**

+ 72 - 34
src/Engines/thinEngine.ts

@@ -152,14 +152,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.2.0-beta.1";
+        return "babylonjs@4.2.0-beta.3";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.2.0-beta.1";
+        return "4.2.0-beta.3";
     }
 
     /**
@@ -2371,169 +2371,198 @@ export class ThinEngine {
      * Set the value of an uniform to a number (int)
      * @param uniform defines the webGL uniform location where to store the value
      * @param value defines the int number to store
+     * @returns true if the value was set
      */
-    public setInt(uniform: Nullable<WebGLUniformLocation>, value: number): void {
+    public setInt(uniform: Nullable<WebGLUniformLocation>, value: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform1i(uniform, value);
+
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if the value was set
      */
-    public setIntArray(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): void {
+    public setIntArray(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform1iv(uniform, array);
+
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if the value was set
      */
-    public setIntArray2(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): void {
+    public setIntArray2(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): boolean {
         if (!uniform || array.length % 2 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform2iv(uniform, array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if the value was set
      */
-    public setIntArray3(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): void {
+    public setIntArray3(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): boolean {
         if (!uniform || array.length % 3 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform3iv(uniform, array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of int32 (stored as vec4)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of int32 to store
+     * @returns true if the value was set
      */
-    public setIntArray4(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): void {
+    public setIntArray4(uniform: Nullable<WebGLUniformLocation>, array: Int32Array): boolean {
         if (!uniform || array.length % 4 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform4iv(uniform, array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if the value was set
      */
-    public setArray(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): void {
+    public setArray(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform1fv(uniform, array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if the value was set
      */
-    public setArray2(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): void {
+    public setArray2(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): boolean {
         if (!uniform || array.length % 2 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform2fv(uniform, <any>array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if the value was set
      */
-    public setArray3(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): void {
+    public setArray3(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): boolean {
         if (!uniform || array.length % 3 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform3fv(uniform, <any>array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of number (stored as vec4)
      * @param uniform defines the webGL uniform location where to store the value
      * @param array defines the array of number to store
+     * @returns true if the value was set
      */
-    public setArray4(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): void {
+    public setArray4(uniform: Nullable<WebGLUniformLocation>, array: number[] | Float32Array): boolean {
         if (!uniform || array.length % 4 !== 0) {
-            return;
+            return false;
         }
 
         this._gl.uniform4fv(uniform, <any>array);
+        return true;
     }
 
     /**
      * Set the value of an uniform to an array of float32 (stored as matrices)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrices defines the array of float32 to store
+     * @returns true if the value was set
      */
-    public setMatrices(uniform: Nullable<WebGLUniformLocation>, matrices: Float32Array): void {
+    public setMatrices(uniform: Nullable<WebGLUniformLocation>, matrices: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniformMatrix4fv(uniform, false, matrices);
+        return true;
     }
 
     /**
      * Set the value of an uniform to a matrix (3x3)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrix defines the Float32Array representing the 3x3 matrix to store
+     * @returns true if the value was set
      */
-    public setMatrix3x3(uniform: Nullable<WebGLUniformLocation>, matrix: Float32Array): void {
+    public setMatrix3x3(uniform: Nullable<WebGLUniformLocation>, matrix: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniformMatrix3fv(uniform, false, matrix);
+        return true;
     }
 
     /**
      * Set the value of an uniform to a matrix (2x2)
      * @param uniform defines the webGL uniform location where to store the value
      * @param matrix defines the Float32Array representing the 2x2 matrix to store
+     * @returns true if the value was set
      */
-    public setMatrix2x2(uniform: Nullable<WebGLUniformLocation>, matrix: Float32Array): void {
+    public setMatrix2x2(uniform: Nullable<WebGLUniformLocation>, matrix: Float32Array): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniformMatrix2fv(uniform, false, matrix);
+        return true;
     }
 
     /**
      * Set the value of an uniform to a number (float)
      * @param uniform defines the webGL uniform location where to store the value
      * @param value defines the float number to store
+     * @returns true if the value was transfered
      */
-    public setFloat(uniform: Nullable<WebGLUniformLocation>, value: number): void {
+    public setFloat(uniform: Nullable<WebGLUniformLocation>, value: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform1f(uniform, value);
+
+        return true;
     }
 
     /**
@@ -2541,13 +2570,16 @@ export class ThinEngine {
      * @param uniform defines the webGL uniform location where to store the value
      * @param x defines the 1st component of the value
      * @param y defines the 2nd component of the value
+     * @returns true if the value was set
      */
-    public setFloat2(uniform: Nullable<WebGLUniformLocation>, x: number, y: number): void {
+    public setFloat2(uniform: Nullable<WebGLUniformLocation>, x: number, y: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform2f(uniform, x, y);
+
+        return true;
     }
 
     /**
@@ -2556,13 +2588,16 @@ export class ThinEngine {
      * @param x defines the 1st component of the value
      * @param y defines the 2nd component of the value
      * @param z defines the 3rd component of the value
+     * @returns true if the value was set
      */
-    public setFloat3(uniform: Nullable<WebGLUniformLocation>, x: number, y: number, z: number): void {
+    public setFloat3(uniform: Nullable<WebGLUniformLocation>, x: number, y: number, z: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform3f(uniform, x, y, z);
+
+        return true;
     }
 
     /**
@@ -2572,13 +2607,16 @@ export class ThinEngine {
      * @param y defines the 2nd component of the value
      * @param z defines the 3rd component of the value
      * @param w defines the 4th component of the value
+     * @returns true if the value was set
      */
-    public setFloat4(uniform: Nullable<WebGLUniformLocation>, x: number, y: number, z: number, w: number): void {
+    public setFloat4(uniform: Nullable<WebGLUniformLocation>, x: number, y: number, z: number, w: number): boolean {
         if (!uniform) {
-            return;
+            return false;
         }
 
         this._gl.uniform4f(uniform, x, y, z, w);
+
+        return true;
     }
 
     // States

+ 2 - 2
src/Gizmos/axisDragGizmo.ts

@@ -137,8 +137,8 @@ export class AxisDragGizmo extends Gizmo {
             if (this._customMeshSet) {
                 return;
             }
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            var material = isHovered ? this._hoverMaterial : this._coloredMaterial;
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            var material = this._isHovered ? this._hoverMaterial : this._coloredMaterial;
             this._rootMesh.getChildMeshes().forEach((m) => {
                 m.material = material;
                 if ((<LinesMesh>m).color) {

+ 2 - 2
src/Gizmos/axisScaleGizmo.ts

@@ -144,8 +144,8 @@ export class AxisScaleGizmo extends Gizmo {
             if (this._customMeshSet) {
                 return;
             }
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            var material = isHovered ? this._hoverMaterial : this._coloredMaterial;
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            var material = this._isHovered ? this._hoverMaterial : this._coloredMaterial;
             this._rootMesh.getChildMeshes().forEach((m) => {
                 m.material = material;
                 if ((<LinesMesh>m).color) {

+ 2 - 2
src/Gizmos/cameraGizmo.ts

@@ -44,8 +44,8 @@ export class CameraGizmo extends Gizmo {
                 return;
             }
 
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            if (isHovered && pointerInfo.event.button === 0) {
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            if (this._isHovered && pointerInfo.event.button === 0) {
                 this.onClickedObservable.notifyObservers(this._camera);
             }
         }, PointerEventTypes.POINTERDOWN);

+ 13 - 0
src/Gizmos/gizmo.ts

@@ -28,6 +28,11 @@ export class Gizmo implements IDisposable {
     protected _scaleRatio = 1;
 
     /**
+     * boolean updated by pointermove when a gizmo mesh is hovered
+     */
+    protected _isHovered = false;
+
+    /**
      * Ratio for the scale of the gizmo (Default: 1)
      */
     public set scaleRatio(value: number) {
@@ -37,6 +42,14 @@ export class Gizmo implements IDisposable {
     public get scaleRatio() {
         return this._scaleRatio;
     }
+
+    /**
+     * True when the mouse pointer is hovered a gizmo mesh
+     */
+    public get isHovered() {
+        return this._isHovered;
+    }
+
     /**
      * If a custom mesh has been set (Default: false)
      */

+ 15 - 0
src/Gizmos/gizmoManager.ts

@@ -72,6 +72,21 @@ export class GizmoManager implements IDisposable {
     }
 
     /**
+     * True when the mouse pointer is hovering a gizmo mesh
+     */
+    public get isHovered() {
+        var hovered = false;
+        for (var key in this.gizmos) {
+            var gizmo = <Nullable<Gizmo>>((<any>this.gizmos)[key]);
+            if (gizmo && gizmo.isHovered) {
+                hovered = true;
+                break;
+            }
+        }
+        return hovered;
+    }
+
+    /**
      * Instatiates a gizmo manager
      * @param scene the scene to overlay the gizmos on top of
      * @param thickness display gizmo axis thickness

+ 2 - 2
src/Gizmos/lightGizmo.ts

@@ -53,8 +53,8 @@ export class LightGizmo extends Gizmo {
                 return;
             }
 
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            if (isHovered && pointerInfo.event.button === 0) {
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            if (this._isHovered && pointerInfo.event.button === 0) {
                 this.onClickedObservable.notifyObservers(this._light);
             }
         }, PointerEventTypes.POINTERDOWN);

+ 2 - 2
src/Gizmos/planeDragGizmo.ts

@@ -121,8 +121,8 @@ export class PlaneDragGizmo extends Gizmo {
             if (this._customMeshSet) {
                 return;
             }
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            var material = isHovered ? this._hoverMaterial : this._coloredMaterial;
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            var material = this._isHovered ? this._hoverMaterial : this._coloredMaterial;
             this._rootMesh.getChildMeshes().forEach((m) => {
                 m.material = material;
             });

+ 2 - 2
src/Gizmos/planeRotationGizmo.ts

@@ -181,8 +181,8 @@ export class PlaneRotationGizmo extends Gizmo {
             if (this._customMeshSet) {
                 return;
             }
-            var isHovered = pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1);
-            var material = isHovered ? hoverMaterial : coloredMaterial;
+            this._isHovered = !!(pointerInfo.pickInfo && (this._rootMesh.getChildMeshes().indexOf(<Mesh>pointerInfo.pickInfo.pickedMesh) != -1));
+            var material = this._isHovered ? hoverMaterial : coloredMaterial;
             this._rootMesh.getChildMeshes().forEach((m) => {
                 m.material = material;
                 if ((<LinesMesh>m).color) {

+ 12 - 0
src/Gizmos/positionGizmo.ts

@@ -87,6 +87,18 @@ export class PositionGizmo extends Gizmo {
             }
         });
     }
+
+    /**
+     * True when the mouse pointer is hovering a gizmo mesh
+     */
+    public get isHovered() {
+        var hovered = false;
+        [this.xGizmo, this.yGizmo, this.zGizmo, this.xPlaneGizmo, this.yPlaneGizmo, this.zPlaneGizmo].forEach((gizmo) => {
+            hovered = hovered || gizmo.isHovered;
+        });
+        return hovered;
+    }
+
     /**
      * Creates a PositionGizmo
      * @param gizmoLayer The utility layer the gizmo will be added to

+ 12 - 0
src/Gizmos/rotationGizmo.ts

@@ -65,6 +65,18 @@ export class RotationGizmo extends Gizmo {
             }
         });
     }
+
+    /**
+     * True when the mouse pointer is hovering a gizmo mesh
+     */
+    public get isHovered() {
+        var hovered = false;
+        [this.xGizmo, this.yGizmo, this.zGizmo].forEach((gizmo) => {
+            hovered = hovered || gizmo.isHovered;
+        });
+        return hovered;
+    }
+
     /**
      * Creates a RotationGizmo
      * @param gizmoLayer The utility layer the gizmo will be added to

+ 11 - 0
src/Gizmos/scaleGizmo.ts

@@ -77,6 +77,17 @@ export class ScaleGizmo extends Gizmo {
     }
 
     /**
+     * True when the mouse pointer is hovering a gizmo mesh
+     */
+    public get isHovered() {
+        var hovered = false;
+        [this.xGizmo, this.yGizmo, this.zGizmo].forEach((gizmo) => {
+            hovered = hovered || gizmo.isHovered;
+        });
+        return hovered;
+    }
+
+    /**
      * Creates a ScaleGizmo
      * @param gizmoLayer The utility layer the gizmo will be added to
      * @param thickness display gizmo axis thickness

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

@@ -300,6 +300,11 @@ var loadAssetContainer = (scene: Scene, data: string, rootUrl: string, onError?:
                 var parsedMesh = parsedData.meshes[index];
                 var mesh = <AbstractMesh>Mesh.Parse(parsedMesh, scene, rootUrl);
                 container.meshes.push(mesh);
+                if (mesh.hasInstances) {
+                    for (var instance of (mesh as Mesh).instances) {
+                        container.meshes.push(instance);
+                    }
+                }
                 log += (index === 0 ? "\n\tMeshes:" : "");
                 log += "\n\t\t" + mesh.toString(fullDetails);
             }

+ 13 - 3
src/Materials/PBR/pbrBaseMaterial.ts

@@ -164,6 +164,12 @@ export class PBRMaterialDefines extends MaterialDefines
     public THIN_INSTANCES = false;
 
     public PREPASS = false;
+    public PREPASS_IRRADIANCE = false;
+    public PREPASS_IRRADIANCE_INDEX = -1;
+    public PREPASS_ALBEDO = false;
+    public PREPASS_ALBEDO_INDEX = -1;
+    public PREPASS_DEPTHNORMAL = false;
+    public PREPASS_DEPTHNORMAL_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public NUM_BONE_INFLUENCERS = 0;
@@ -2232,11 +2238,15 @@ export abstract class PBRBaseMaterial extends PushMaterial {
      */
     public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
         if (this.subSurface.isScatteringEnabled) {
-            prePassRenderer.subSurfaceConfiguration.enabled = true;
-            prePassRenderer.materialsShouldRenderIrradiance = true;
+            let subSurfaceConfiguration = this.getScene().enableSubSurfaceForPrePass();
+            if (subSurfaceConfiguration) {
+                subSurfaceConfiguration.enabled = true;
+            }
+
+            return true;
         }
 
-        return true;
+        return false;
     }
 
     /**

+ 4 - 4
src/Materials/PBR/pbrSubSurfaceConfiguration.ts

@@ -80,22 +80,22 @@ export class PBRSubSurfaceConfiguration {
      * Useful for better scattering in the skins or foliages.
      */
     public get scatteringDiffusionProfile() : Nullable<Color3> {
-        if (!this._scene.prePassRenderer) {
+        if (!this._scene.subSurfaceConfiguration) {
             return null;
         }
 
-        return this._scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionProfileColors[this._scatteringDiffusionProfileIndex];
+        return this._scene.subSurfaceConfiguration.ssDiffusionProfileColors[this._scatteringDiffusionProfileIndex];
     }
 
     public set scatteringDiffusionProfile(c: Nullable<Color3>) {
-        if (!this._scene.enablePrePassRenderer()) {
+        if (!this._scene.enableSubSurfaceForPrePass()) {
             // Not supported
             return;
         }
 
         // addDiffusionProfile automatically checks for doubles
         if (c) {
-            this._scatteringDiffusionProfileIndex = this._scene.prePassRenderer!.subSurfaceConfiguration.addDiffusionProfile(c);
+            this._scatteringDiffusionProfileIndex = this._scene.subSurfaceConfiguration!.addDiffusionProfile(c);
         }
     }
 

+ 44 - 18
src/Materials/Textures/multiRenderTarget.ts

@@ -138,22 +138,9 @@ export class MultiRenderTarget extends RenderTargetTexture {
             return;
         }
 
-        var types = [];
-        var samplingModes = [];
-
-        for (var i = 0; i < count; i++) {
-            if (options && options.types && options.types[i] !== undefined) {
-                types.push(options.types[i]);
-            } else {
-                types.push(options && options.defaultType ? options.defaultType : Constants.TEXTURETYPE_UNSIGNED_INT);
-            }
-
-            if (options && options.samplingModes && options.samplingModes[i] !== undefined) {
-                samplingModes.push(options.samplingModes[i]);
-            } else {
-                samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
-            }
-        }
+        var types: number[] = [];
+        var samplingModes: number[] = [];
+        this._initTypes(count, types, samplingModes, options);
 
         var generateDepthBuffer = !options || options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
         var generateStencilBuffer = !options || options.generateStencilBuffer === undefined ? false : options.generateStencilBuffer;
@@ -175,11 +162,31 @@ export class MultiRenderTarget extends RenderTargetTexture {
         this._createTextures();
     }
 
+    private _initTypes(count: number, types: number[], samplingModes: number[], options?: IMultiRenderTargetOptions) {
+        for (var i = 0; i < count; i++) {
+            if (options && options.types && options.types[i] !== undefined) {
+                types.push(options.types[i]);
+            } else {
+                types.push(options && options.defaultType ? options.defaultType : Constants.TEXTURETYPE_UNSIGNED_INT);
+            }
+
+            if (options && options.samplingModes && options.samplingModes[i] !== undefined) {
+                samplingModes.push(options.samplingModes[i]);
+            } else {
+                samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
+            }
+        }
+    }
+
     /** @hidden */
-    public _rebuild(): void {
+    public _rebuild(forceFullRebuild: boolean = false): void {
         this.releaseInternalTextures();
         this._createInternalTextures();
 
+        if (forceFullRebuild) {
+            this._createTextures();
+        }
+
         for (var i = 0; i < this._internalTextures.length; i++) {
             var texture = this._textures[i];
             texture._texture = this._internalTextures[i];
@@ -226,7 +233,7 @@ export class MultiRenderTarget extends RenderTargetTexture {
 
     /**
      * Resize all the textures in the multi render target.
-     * Be carrefull as it will recreate all the data in the new texture.
+     * Be careful as it will recreate all the data in the new texture.
      * @param size Define the new size
      */
     public resize(size: any) {
@@ -234,6 +241,25 @@ export class MultiRenderTarget extends RenderTargetTexture {
         this._rebuild();
     }
 
+    /**
+     * Changes the number of render targets in this MRT
+     * Be careful as it will recreate all the data in the new texture.
+     * @param count new texture count
+     * @param options Specifies texture types and sampling modes for new textures
+     */
+    public updateCount(count: number, options?: IMultiRenderTargetOptions) {
+        this._multiRenderTargetOptions.textureCount = count;
+        this._count = count;
+
+        const types: number[] = [];
+        const samplingModes: number[] = [];
+
+        this._initTypes(count, types, samplingModes, options);
+        this._multiRenderTargetOptions.types = types;
+        this._multiRenderTargetOptions.samplingModes = samplingModes;
+        this._rebuild(true);
+    }
+
     protected unbindFrameBuffer(engine: Engine, faceIndex: number): void {
         engine.unBindMultiColorAttachmentFramebuffer(this._internalTextures, this.isCube, () => {
             this.onAfterRenderObservable.notifyObservers(faceIndex);

+ 39 - 19
src/Materials/effect.ts

@@ -974,9 +974,9 @@ export class Effect implements IDisposable {
             return this;
         }
 
-        this._valueCache[uniformName] = value;
-
-        this._engine.setInt(this._uniforms[uniformName], value);
+        if (this._engine.setInt(this._uniforms[uniformName], value)) {
+            this._valueCache[uniformName] = value;
+        }
 
         return this;
     }
@@ -1162,7 +1162,9 @@ export class Effect implements IDisposable {
      */
     public setMatrix(uniformName: string, matrix: IMatrixLike): Effect {
         if (this._cacheMatrix(uniformName, matrix)) {
-            this._engine.setMatrices(this._uniforms[uniformName], matrix.toArray() as Float32Array);
+            if (!this._engine.setMatrices(this._uniforms[uniformName], matrix.toArray() as Float32Array)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1205,9 +1207,9 @@ export class Effect implements IDisposable {
             return this;
         }
 
-        this._valueCache[uniformName] = value;
-
-        this._engine.setFloat(this._uniforms[uniformName], value);
+        if (this._engine.setFloat(this._uniforms[uniformName], value)) {
+            this._valueCache[uniformName] = value;
+        }
 
         return this;
     }
@@ -1224,9 +1226,9 @@ export class Effect implements IDisposable {
             return this;
         }
 
-        this._valueCache[uniformName] = bool;
-
-        this._engine.setInt(this._uniforms[uniformName], bool ? 1 : 0);
+        if (this._engine.setInt(this._uniforms[uniformName], bool ? 1 : 0)) {
+            this._valueCache[uniformName] = bool;
+        }
 
         return this;
     }
@@ -1239,7 +1241,9 @@ export class Effect implements IDisposable {
      */
     public setVector2(uniformName: string, vector2: IVector2Like): Effect {
         if (this._cacheFloat2(uniformName, vector2.x, vector2.y)) {
-            this._engine.setFloat2(this._uniforms[uniformName], vector2.x, vector2.y);
+            if (!this._engine.setFloat2(this._uniforms[uniformName], vector2.x, vector2.y)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1253,7 +1257,9 @@ export class Effect implements IDisposable {
      */
     public setFloat2(uniformName: string, x: number, y: number): Effect {
         if (this._cacheFloat2(uniformName, x, y)) {
-            this._engine.setFloat2(this._uniforms[uniformName], x, y);
+            if (!this._engine.setFloat2(this._uniforms[uniformName], x, y)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1266,7 +1272,9 @@ export class Effect implements IDisposable {
      */
     public setVector3(uniformName: string, vector3: IVector3Like): Effect {
         if (this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z)) {
-            this._engine.setFloat3(this._uniforms[uniformName], vector3.x, vector3.y, vector3.z);
+            if (!this._engine.setFloat3(this._uniforms[uniformName], vector3.x, vector3.y, vector3.z)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1281,7 +1289,9 @@ export class Effect implements IDisposable {
      */
     public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
         if (this._cacheFloat3(uniformName, x, y, z)) {
-            this._engine.setFloat3(this._uniforms[uniformName], x, y, z);
+            if (!this._engine.setFloat3(this._uniforms[uniformName], x, y, z)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1294,7 +1304,9 @@ export class Effect implements IDisposable {
      */
     public setVector4(uniformName: string, vector4: IVector4Like): Effect {
         if (this._cacheFloat4(uniformName, vector4.x, vector4.y, vector4.z, vector4.w)) {
-            this._engine.setFloat4(this._uniforms[uniformName], vector4.x, vector4.y, vector4.z, vector4.w);
+            if (!this._engine.setFloat4(this._uniforms[uniformName], vector4.x, vector4.y, vector4.z, vector4.w)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1310,7 +1322,9 @@ export class Effect implements IDisposable {
      */
     public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
         if (this._cacheFloat4(uniformName, x, y, z, w)) {
-            this._engine.setFloat4(this._uniforms[uniformName], x, y, z, w);
+            if (!this._engine.setFloat4(this._uniforms[uniformName], x, y, z, w)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1323,7 +1337,9 @@ export class Effect implements IDisposable {
      */
     public setColor3(uniformName: string, color3: IColor3Like): Effect {
         if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
-            this._engine.setFloat3(this._uniforms[uniformName], color3.r, color3.g, color3.b);
+            if (!this._engine.setFloat3(this._uniforms[uniformName], color3.r, color3.g, color3.b)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1337,7 +1353,9 @@ export class Effect implements IDisposable {
      */
     public setColor4(uniformName: string, color3: IColor3Like, alpha: number): Effect {
         if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
-            this._engine.setFloat4(this._uniforms[uniformName], color3.r, color3.g, color3.b, alpha);
+            if (!this._engine.setFloat4(this._uniforms[uniformName], color3.r, color3.g, color3.b, alpha)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }
@@ -1350,7 +1368,9 @@ export class Effect implements IDisposable {
      */
     public setDirectColor4(uniformName: string, color4: IColor4Like): Effect {
         if (this._cacheFloat4(uniformName, color4.r, color4.g, color4.b, color4.a)) {
-            this._engine.setFloat4(this._uniforms[uniformName], color4.r, color4.g, color4.b, color4.a);
+            if (!this._engine.setFloat4(this._uniforms[uniformName], color4.r, color4.g, color4.b, color4.a)) {
+                this._valueCache[uniformName] = null;
+            }
         }
         return this;
     }

+ 26 - 1
src/Materials/materialHelper.ts

@@ -8,6 +8,7 @@ import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Mesh } from "../Meshes/mesh";
 import { VertexBuffer } from "../Meshes/buffer";
 import { Light } from "../Lights/light";
+import { Constants } from "../Engines/constants";
 
 import { UniformBuffer } from "./uniformBuffer";
 import { Effect, IEffectCreationOptions } from "./effect";
@@ -304,9 +305,33 @@ export class MaterialHelper {
     public static PrepareDefinesForPrePass(scene: Scene, defines: any, canRenderToMRT: boolean) {
         var previousPrePass = defines.PREPASS;
 
-        if (scene.prePassRenderer && canRenderToMRT) {
+        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;
+            }
+
+            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;
         }

+ 6 - 0
src/Materials/standardMaterial.ts

@@ -126,6 +126,12 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public ALPHABLEND = true;
 
     public PREPASS = false;
+    public PREPASS_IRRADIANCE = false;
+    public PREPASS_IRRADIANCE_INDEX = -1;
+    public PREPASS_ALBEDO = false;
+    public PREPASS_ALBEDO_INDEX = -1;
+    public PREPASS_DEPTHNORMAL = false;
+    public PREPASS_DEPTHNORMAL_INDEX = -1;
     public SCENE_MRT_COUNT = 0;
 
     public RGBDLIGHTMAP = false;

+ 1 - 2
src/Maths/math.vector.ts

@@ -3113,7 +3113,7 @@ export class Quaternion {
 
     /**
      * Returns a new Vector3 set with the Euler angles translated from the current quaternion
-     * @param order is a reserved parameter and is ignore for now
+     * @param order is a reserved parameter and is ignored for now
      * @returns a new Vector3 containing the Euler angles
      */
     public toEulerAngles(order = "YZX"): Vector3 {
@@ -3125,7 +3125,6 @@ export class Quaternion {
     /**
      * Sets the given vector3 "result" with the Euler angles translated from the current quaternion
      * @param result defines the vector which will be filled with the Euler angles
-     * @param order is a reserved parameter and is ignore for now
      * @returns the current unchanged quaternion
      */
     public toEulerAnglesToRef(result: Vector3): Quaternion {

+ 0 - 2
src/Meshes/Builders/capsuleBuilder.ts

@@ -48,8 +48,6 @@ VertexData.CreateCapsule = function(
     halfHeight = heightMinusCaps * 0.5;
     let pi2 = Math.PI * 0.5;
 
-    console.log("halfHeight", halfHeight);
-
     var x, y;
     var normal = Vector3.Zero();
     var vertex = Vector3.Zero();

+ 1 - 1
src/Meshes/linesMesh.ts

@@ -134,7 +134,7 @@ export class LinesMesh extends Mesh {
         scene.clipPlane5 ? this._addClipPlaneDefine("CLIPPLANE5") : this._removeClipPlaneDefine("CLIPPLANE5");
         scene.clipPlane6 ? this._addClipPlaneDefine("CLIPPLANE6") : this._removeClipPlaneDefine("CLIPPLANE6");
 
-        if (!this._colorShader.isReady()) {
+        if (!this._colorShader.isReady(this)) {
             return false;
         }
 

+ 23 - 16
src/Meshes/mesh.ts

@@ -237,10 +237,12 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             return;
         }
 
-        if (value && this._internalMeshDataInfo._sourcePositions && this._internalMeshDataInfo._sourceNormals) {
+        if (value && this._internalMeshDataInfo._sourcePositions) {
             // switch from software to GPU computation: we need to reset the vertex and normal buffers that have been updated by the software process
             this.setVerticesData(VertexBuffer.PositionKind, this._internalMeshDataInfo._sourcePositions.slice(), true);
-            this.setVerticesData(VertexBuffer.NormalKind, this._internalMeshDataInfo._sourceNormals.slice(), true);
+            if (this._internalMeshDataInfo._sourceNormals) {
+                this.setVerticesData(VertexBuffer.NormalKind, this._internalMeshDataInfo._sourceNormals.slice(), true);
+            }
         }
 
         this._internalAbstractMeshDataInfo._computeBonesUsingShaders = value;
@@ -2095,9 +2097,9 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         let matricesIndices = (<FloatArray>this.getVerticesData(VertexBuffer.MatricesIndicesKind));
         let matricesIndicesExtra = (<FloatArray>this.getVerticesData(VertexBuffer.MatricesIndicesExtraKind));
         let numBadBoneIndices: number = 0;
-        for (var a = 0; a < numWeights; a++) {
+        for (var a = 0; a < numWeights; a += 4) {
             for (var b = 0; b < numInfluences; b++) {
-                let index = b < 4 ? matricesIndices[b] : matricesIndicesExtra[b - 4];
+                let index = b < 4 ? matricesIndices[a + b] : matricesIndicesExtra[a + b - 4];
                 if (index >= numBones || index < 0) { numBadBoneIndices++; }
             }
         }
@@ -4100,9 +4102,6 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         if (!this.isVerticesDataPresent(VertexBuffer.PositionKind)) {
             return this;
         }
-        if (!this.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-            return this;
-        }
         if (!this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind)) {
             return this;
         }
@@ -4110,6 +4109,8 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             return this;
         }
 
+        const hasNormals = this.isVerticesDataPresent(VertexBuffer.NormalKind);
+
         let internalDataInfo = this._internalMeshDataInfo;
 
         if (!internalDataInfo._sourcePositions) {
@@ -4118,7 +4119,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             this.subMeshes = submeshes;
         }
 
-        if (!internalDataInfo._sourceNormals) {
+        if (hasNormals && !internalDataInfo._sourceNormals) {
             this.setNormalsForCPUSkinning();
         }
 
@@ -4136,12 +4137,14 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         // normalsData checks for not being Float32Array will only pass at most once
         var normalsData = this.getVerticesData(VertexBuffer.NormalKind);
 
-        if (!normalsData) {
-            return this;
-        }
+        if (hasNormals) {
+            if (!normalsData) {
+                return this;
+            }
 
-        if (!(normalsData instanceof Float32Array)) {
-            normalsData = new Float32Array(normalsData);
+            if (!(normalsData instanceof Float32Array)) {
+                normalsData = new Float32Array(normalsData);
+            }
         }
 
         var matricesIndicesData = this.getVerticesData(VertexBuffer.MatricesIndicesKind);
@@ -4185,14 +4188,18 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             Vector3.TransformCoordinatesFromFloatsToRef(internalDataInfo._sourcePositions[index], internalDataInfo._sourcePositions[index + 1], internalDataInfo._sourcePositions[index + 2], finalMatrix, tempVector3);
             tempVector3.toArray(positionsData, index);
 
-            Vector3.TransformNormalFromFloatsToRef(internalDataInfo._sourceNormals[index], internalDataInfo._sourceNormals[index + 1], internalDataInfo._sourceNormals[index + 2], finalMatrix, tempVector3);
-            tempVector3.toArray(normalsData, index);
+            if (hasNormals) {
+                Vector3.TransformNormalFromFloatsToRef(internalDataInfo._sourceNormals[index], internalDataInfo._sourceNormals[index + 1], internalDataInfo._sourceNormals[index + 2], finalMatrix, tempVector3);
+                tempVector3.toArray(normalsData!, index);
+            }
 
             finalMatrix.reset();
         }
 
         this.updateVerticesData(VertexBuffer.PositionKind, positionsData);
-        this.updateVerticesData(VertexBuffer.NormalKind, normalsData);
+        if (hasNormals) {
+            this.updateVerticesData(VertexBuffer.NormalKind, normalsData!);
+        }
 
         return this;
     }

+ 2 - 2
src/Misc/decorators.ts

@@ -275,7 +275,7 @@ export class SerializationHelper {
             var propertyType = propertyDescriptor.type;
             var sourceProperty = (<any>entity)[property];
 
-            if (sourceProperty !== undefined && sourceProperty !== null) {
+            if (sourceProperty !== undefined && sourceProperty !== null && property !== "uniqueId") {
                 switch (propertyType) {
                     case 0:     // Value
                         serializationObject[targetPropertyName] = sourceProperty;
@@ -350,7 +350,7 @@ export class SerializationHelper {
             var sourceProperty = source[propertyDescriptor.sourceName || property];
             var propertyType = propertyDescriptor.type;
 
-            if (sourceProperty !== undefined && sourceProperty !== null) {
+            if (sourceProperty !== undefined && sourceProperty !== null && property !== "uniqueId") {
                 var dest = <any>destination;
                 switch (propertyType) {
                     case 0:     // Value

+ 2 - 1
src/Misc/index.ts

@@ -49,4 +49,5 @@ export * from "./minMaxReducer";
 export * from "./depthReducer";
 export * from "./dataStorage";
 export * from "./sceneRecorder";
-export * from "./khronosTextureContainer2";
+export * from "./khronosTextureContainer2";
+export * from "./trajectoryClassifier";

+ 885 - 0
src/Misc/trajectoryClassifier.ts

@@ -0,0 +1,885 @@
+import { DeepImmutable, Nullable } from "../types";
+import { Matrix, Vector3 } from "../Maths/math.vector";
+
+// This implementation was based on the original MIT-licensed TRACE repository
+// from https://github.com/septagon/TRACE.
+
+/**
+ * Generic implementation of Levenshtein distance.
+ */
+namespace Levenshtein {
+    /**
+     * Alphabet from which to construct sequences to be compared using Levenshtein
+     * distance.
+     */
+    export class Alphabet<T> {
+        private _characterToIdx: Map<T, number>;
+        private _insertionCosts: number[];
+        private _deletionCosts: number[];
+        private _substitutionCosts: number[][];
+
+        /**
+         * Serialize the Alphabet to JSON string.
+         * @returns JSON serialization
+         */
+        public serialize(): string {
+            let jsonObject: any = {};
+
+            let characters = new Array<T>(this._characterToIdx.size);
+            this._characterToIdx.forEach((v, k) => {
+                characters[v] = k;
+            });
+            jsonObject["characters"] = characters;
+
+            jsonObject["insertionCosts"] = this._insertionCosts;
+            jsonObject["deletionCosts"] = this._deletionCosts;
+            jsonObject["substitutionCosts"] = this._substitutionCosts;
+
+            return JSON.stringify(jsonObject);
+        }
+
+        /**
+         * Parse an Alphabet from a JSON serialization.
+         * @param json JSON string to deserialize
+         * @returns deserialized Alphabet
+         */
+        public static Deserialize<T>(json: string): Alphabet<T> {
+            let jsonObject = JSON.parse(json);
+            let alphabet = new Alphabet(jsonObject["characters"] as T[]);
+            alphabet._insertionCosts = jsonObject["insertionCosts"];
+            alphabet._deletionCosts = jsonObject["deletionCosts"];
+            alphabet._substitutionCosts = jsonObject["substitutionCosts"];
+            return alphabet;
+        }
+
+        /**
+         * Create a new Alphabet.
+         * @param characters characters of the alphabet
+         * @param charToInsertionCost function mapping characters to insertion costs
+         * @param charToDeletionCost function mapping characters to deletion costs
+         * @param charsToSubstitutionCost function mapping character pairs to substitution costs
+         */
+        public constructor(
+            characters: Array<T>,
+            charToInsertionCost: Nullable<(char: T) => number> = null,
+            charToDeletionCost: Nullable<(char: T) => number> = null,
+            charsToSubstitutionCost: Nullable<(outChar: T, inChar: T) => number> = null) {
+
+            charToInsertionCost = charToInsertionCost ?? (() => 1);
+            charToDeletionCost = charToDeletionCost ?? (() => 1);
+            charsToSubstitutionCost = charsToSubstitutionCost ?? ((a: T, b: T) => a === b ? 0 : 1);
+
+            this._characterToIdx = new Map<T, number>();
+            this._insertionCosts = new Array<number>(characters.length);
+            this._deletionCosts = new Array<number>(characters.length);
+            this._substitutionCosts = new Array<Array<number>>(characters.length);
+
+            let c: T;
+            for (let outerIdx = 0; outerIdx < characters.length; ++outerIdx) {
+                c = characters[outerIdx];
+                this._characterToIdx.set(c, outerIdx);
+                this._insertionCosts[outerIdx] = charToInsertionCost(c);
+                this._deletionCosts[outerIdx] = charToDeletionCost(c);
+
+                this._substitutionCosts[outerIdx] = new Array<number>(characters.length);
+                for (let innerIdx = outerIdx; innerIdx < characters.length; ++innerIdx) {
+                    this._substitutionCosts[outerIdx][innerIdx] = charsToSubstitutionCost(c, characters[innerIdx]);
+                }
+            }
+        }
+
+        /**
+         * Get the index (internally-assigned number) for a character.
+         * @param char character
+         * @returns index
+         */
+        public getCharacterIdx(char: T): number {
+            return this._characterToIdx.get(char)!;
+        }
+
+        /**
+         * Get the insertion cost of a character from its index.
+         * @param idx character index
+         * @returns insertion cost
+         */
+        public getInsertionCost(idx: number): number {
+            return this._insertionCosts[idx];
+        }
+
+        /**
+         * Get the deletion cost of a character from its index.
+         * @param idx character index
+         * @returns deletion cost
+         */
+        public getDeletionCost(idx: number): number {
+            return this._deletionCosts[idx];
+        }
+
+        /**
+         * Gets the cost to substitute two characters. NOTE: this cost is
+         * required to be bi-directional, meaning it cannot matter which of
+         * the provided characters is being removed and which is being inserted.
+         * @param idx1 the first character index
+         * @param idx2 the second character index
+         * @returns substitution cost
+         */
+        public getSubstitutionCost(idx1: number, idx2: number): number {
+            let min = Math.min(idx1, idx2);
+            let max = Math.max(idx1, idx2);
+
+            return this._substitutionCosts[min][max];
+        }
+    }
+
+    /**
+     * Character sequence intended to be compared against other Sequences created
+     * with the same Alphabet in order to compute Levenshtein distance.
+     */
+    export class Sequence<T> {
+        private _alphabet: Alphabet<T>;
+        private _characters: number[];
+
+        // Scratch values
+        private static readonly MAX_SEQUENCE_LENGTH = 256;
+        private static _costMatrix =
+            [...Array(Sequence.MAX_SEQUENCE_LENGTH + 1)].map((n) => new Array<number>(Sequence.MAX_SEQUENCE_LENGTH + 1));
+        private static _insertionCost: number;
+        private static _deletionCost: number;
+        private static _substitutionCost: number;
+
+        /**
+         * Serialize to JSON string. JSON representation does NOT include the Alphabet
+         * from which this Sequence was created; Alphabet must be independently
+         * serialized.
+         * @returns JSON string
+         */
+        public serialize(): string {
+            return JSON.stringify(this._characters);
+        }
+
+        /**
+         * Deserialize from JSON string and Alphabet. This should be the same Alphabet
+         * from which the Sequence was originally created, which must be serialized and
+         * deserialized independently so that it can be passed in here.
+         * @param json JSON string representation of Sequence
+         * @param alphabet Alphabet from which Sequence was originally created
+         * @returns Sequence
+         */
+        public static Deserialize<T>(json: string, alphabet: Alphabet<T>): Sequence<T> {
+            let sequence = new Sequence([], alphabet);
+            sequence._characters = JSON.parse(json);
+            return sequence;
+        }
+
+        /**
+         * Create a new Sequence.
+         * @param characters characters in the new Sequence
+         * @param alphabet Alphabet, which must include all used characters
+         */
+        public constructor(characters: T[], alphabet: Alphabet<T>) {
+            if (characters.length > Sequence.MAX_SEQUENCE_LENGTH) {
+                throw new Error("Sequences longer than " + Sequence.MAX_SEQUENCE_LENGTH + " not supported.");
+            }
+            this._alphabet = alphabet;
+            this._characters = characters.map((c) => this._alphabet.getCharacterIdx(c));
+        }
+
+        /**
+         * Get the distance between this Sequence and another.
+         * @param other sequence to compare to
+         * @returns Levenshtein distance
+         */
+        public distance(other: Sequence<T>): number {
+            return Sequence._distance<T>(this, other);
+        }
+
+        /**
+         * Compute the Levenshtein distance between two Sequences.
+         * @param a first Sequence
+         * @param b second Sequence
+         * @returns Levenshtein distance
+         */
+        private static _distance<T>(a: Sequence<T>, b: Sequence<T>): number {
+            const alphabet = a._alphabet;
+            if (alphabet !== b._alphabet) {
+                throw new Error("Cannot Levenshtein compare Sequences built from different alphabets.");
+            }
+            const aChars = a._characters;
+            const bChars = b._characters;
+            const aLength = aChars.length;
+            const bLength = bChars.length;
+
+            let costMatrix = Sequence._costMatrix;
+            costMatrix[0][0] = 0;
+            for (let idx = 0; idx < aLength; ++idx) {
+                costMatrix[idx + 1][0] = costMatrix[idx][0] + alphabet.getInsertionCost(aChars[idx]);
+            }
+            for (let idx = 0; idx < bLength; ++idx) {
+                costMatrix[0][idx + 1] = costMatrix[0][idx] + alphabet.getInsertionCost(bChars[idx]);
+            }
+
+            for (let aIdx = 0; aIdx < aLength; ++aIdx) {
+                for (let bIdx = 0; bIdx < bLength; ++bIdx) {
+                    Sequence._insertionCost = costMatrix[aIdx + 1][bIdx] + alphabet.getInsertionCost(bChars[bIdx]);
+                    Sequence._deletionCost = costMatrix[aIdx][bIdx + 1] + alphabet.getDeletionCost(aChars[aIdx]);
+                    Sequence._substitutionCost = costMatrix[aIdx][bIdx] + alphabet.getSubstitutionCost(aChars[aIdx], bChars[bIdx]);
+
+                    costMatrix[aIdx + 1][bIdx + 1] = Math.min(
+                        Sequence._insertionCost,
+                        Sequence._deletionCost,
+                        Sequence._substitutionCost);
+                }
+            }
+
+            return costMatrix[aLength][bLength];
+        }
+    }
+}
+
+/**
+ * A 3D trajectory consisting of an order list of vectors describing a
+ * path of motion through 3D space.
+ */
+export class Trajectory {
+    private _points: Vector3[];
+    private readonly _segmentLength: number;
+
+    /**
+     * Serialize to JSON.
+     * @returns serialized JSON string
+     */
+    public serialize(): string {
+        return JSON.stringify(this);
+    }
+
+    /**
+     * Deserialize from JSON.
+     * @param json serialized JSON string
+     * @returns deserialized Trajectory
+     */
+    public static Deserialize(json: string): Trajectory {
+        let jsonObject = JSON.parse(json);
+        let trajectory = new Trajectory(jsonObject["_segmentLength"]);
+        trajectory._points = jsonObject["_points"].map((pt: any) => {
+            return new Vector3(pt["_x"], pt["_y"], pt["_z"]);
+        });
+        return trajectory;
+    }
+
+    /**
+     * Create a new empty Trajectory.
+     * @param segmentLength radius of discretization for Trajectory points
+     */
+    public constructor(segmentLength: number = 0.01) {
+        this._points = [];
+        this._segmentLength = segmentLength;
+    }
+
+    /**
+     * Get the length of the Trajectory.
+     * @returns length of the Trajectory
+     */
+    public getLength(): number {
+        return this._points.length * this._segmentLength;
+    }
+
+    /**
+     * Append a new point to the Trajectory.
+     * NOTE: This implementation has many allocations.
+     * @param point point to append to the Trajectory
+     */
+    public add(point: DeepImmutable<Vector3>): void {
+        let numPoints = this._points.length;
+        if (numPoints === 0) {
+            this._points.push(point.clone());
+        } else {
+            const getT = () =>
+                this._segmentLength / Vector3.Distance(this._points[numPoints - 1], point);
+            for (let t = getT(); t <= 1.0; t = getT()) {
+                let newPoint = this._points[numPoints - 1].scale(1.0 - t);
+                point.scaleAndAddToRef(t, newPoint);
+                this._points.push(newPoint);
+                ++numPoints;
+            }
+        }
+    }
+
+    /**
+     * Create a new Trajectory with a segment length chosen to make it
+     * probable that the new Trajectory will have a specified number of
+     * segments. This operation is imprecise.
+     * @param targetResolution number of segments desired
+     * @returns new Trajectory with approximately the requested number of segments
+     */
+    public resampleAtTargetResolution(targetResolution: number): Trajectory {
+        var resampled = new Trajectory(this.getLength() / targetResolution);
+        this._points.forEach((pt) => {
+            resampled.add(pt);
+        });
+        return resampled;
+    }
+
+    /**
+     * Convert Trajectory segments into tokenized representation. This
+     * representation is an array of numbers where each nth number is the
+     * index of the token which is most similar to the nth segment of the
+     * Trajectory.
+     * @param tokens list of vectors which serve as discrete tokens
+     * @returns list of indices of most similar token per segment
+     */
+    public tokenize(tokens: DeepImmutable<Vector3[]>): number[] {
+        let tokenization: number[] = [];
+
+        let segmentDir = new Vector3();
+        for (let idx = 2; idx < this._points.length; ++idx) {
+            if (Trajectory._transformSegmentDirToRef(
+                    this._points[idx - 2],
+                    this._points[idx - 1],
+                    this._points[idx],
+                    segmentDir)) {
+
+                tokenization.push(Trajectory._tokenizeSegment(segmentDir, tokens));
+            }
+        }
+
+        return tokenization;
+    }
+
+    private static _forwardDir = new Vector3();
+    private static _inverseFromVec = new Vector3();
+    private static _upDir = new Vector3();
+    private static _fromToVec = new Vector3();
+    private static _lookMatrix = new Matrix();
+
+    /**
+     * Transform the rotation (i.e., direction) of a segment to isolate
+     * the relative transformation represented by the segment. This operation
+     * may or may not succeed due to singularities in the equations that define
+     * motion relativity in this context.
+     * @param priorVec the origin of the prior segment
+     * @param fromVec the origin of the current segment
+     * @param toVec the destination of the current segment
+     * @param result reference to output variable
+     * @returns whether or not transformation was successful
+     */
+    private static _transformSegmentDirToRef(
+        priorVec: DeepImmutable<Vector3>,
+        fromVec: DeepImmutable<Vector3>,
+        toVec: DeepImmutable<Vector3>,
+        result: Vector3): boolean {
+
+        const DOT_PRODUCT_SAMPLE_REJECTION_THRESHOLD = 0.98;
+
+        fromVec.subtractToRef(priorVec, Trajectory._forwardDir);
+        Trajectory._forwardDir.normalize();
+        fromVec.scaleToRef(-1, Trajectory._inverseFromVec);
+        Trajectory._inverseFromVec.normalize();
+
+        if (Math.abs(Vector3.Dot(Trajectory._forwardDir, Trajectory._inverseFromVec)) > DOT_PRODUCT_SAMPLE_REJECTION_THRESHOLD) {
+            return false;
+        }
+
+        Vector3.CrossToRef(Trajectory._forwardDir, Trajectory._inverseFromVec, Trajectory._upDir);
+        Trajectory._upDir.normalize();
+        Matrix.LookAtLHToRef(priorVec, fromVec, Trajectory._upDir, Trajectory._lookMatrix);
+        toVec.subtractToRef(fromVec, Trajectory._fromToVec);
+        Trajectory._fromToVec.normalize();
+        Vector3.TransformNormalToRef(Trajectory._fromToVec, Trajectory._lookMatrix, result);
+        return true;
+    }
+
+    private static _bestMatch: number;
+    private static _score: number;
+    private static _bestScore: number;
+
+    /**
+     * Determine which token vector is most similar to the
+     * segment vector.
+     * @param segment segment vector
+     * @param tokens token vector list
+     * @returns index of the most similar token to the segment
+     */
+    private static _tokenizeSegment(
+        segment: DeepImmutable<Vector3>,
+        tokens: DeepImmutable<Vector3[]>): number {
+
+        Trajectory._bestMatch = 0;
+        Trajectory._score = Vector3.Dot(segment, tokens[0]);
+        Trajectory._bestScore = Trajectory._score;
+        for (let idx = 1; idx < tokens.length; ++idx) {
+            Trajectory._score = Vector3.Dot(segment, tokens[idx]);
+            if (Trajectory._score > Trajectory._bestScore) {
+                Trajectory._bestMatch = idx;
+                Trajectory._bestScore = Trajectory._score;
+            }
+        }
+
+        return Trajectory._bestMatch;
+    }
+}
+
+/**
+ * Collection of vectors intended to be used as the basis of Trajectory
+ * tokenization for Levenshtein distance comparison. Canonically, a
+ * Vector3Alphabet will resemble a "spikeball" of vectors distributed
+ * roughly evenly over the surface of the unit sphere.
+ */
+class Vector3Alphabet {
+
+    /**
+     * Characters in the alphabet.
+     * NOTE: There is no reason for this property to exist and this class should just extend
+     * Array<Vector3>, except that doing so produces bizarre build-time errors indicating that
+     * the ES5 library itself fails its own TypeDoc validation.
+     */
+    public chars: Vector3[];
+
+    /**
+     * Helper method to create new "spikeball" Vector3Alphabets. Uses a naive
+     * optimize-from-random strategy to space points around the unit sphere
+     * surface as a simple alternative to really doing the math to tile the
+     * sphere.
+     * @param alphabetSize size of the desired alphabet
+     * @param iterations number of iterations over which to optimize the "spikeball"
+     * @param startingStepSize distance factor to move points in early optimization iterations
+     * @param endingStepSize distance factor to move points in late optimization iterations
+     * @param fixedValues alphabet "characters" that are required and cannot be moved by optimization
+     * @returns a new randomly generated and optimized Vector3Alphabet of the specified size
+     */
+    public static Generate(
+        alphabetSize: number = 64,
+        iterations: number = 256,
+        startingStepSize: number = 0.1,
+        endingStepSize: number = 0.001,
+        fixedValues: DeepImmutable<Vector3[]> = []): Vector3Alphabet {
+
+        const EPSILON = 0.001;
+        const EPSILON_SQUARED = EPSILON * EPSILON;
+
+        let alphabet = new Vector3Alphabet(alphabetSize);
+        for (let idx = 0; idx < alphabetSize; ++idx) {
+            alphabet.chars[idx] = new Vector3(
+                Math.random() - 0.5,
+                Math.random() - 0.5,
+                Math.random() - 0.5);
+            alphabet.chars[idx].normalize();
+        }
+
+        for (let idx = 0; idx < fixedValues.length; ++idx) {
+            alphabet.chars[idx].copyFrom(fixedValues[idx]);
+        }
+
+        let stepSize: number;
+        let distSq: number;
+        let force = new Vector3();
+        let scratch = new Vector3();
+        const lerp = (l: number, r: number, t: number) => (1.0 - t) * l + t * r;
+        for (let iteration = 0; iteration < iterations; ++iteration) {
+            stepSize = lerp(startingStepSize, endingStepSize, iteration / (iterations - 1));
+            for (let idx = fixedValues.length; idx < alphabet.chars.length; ++idx) {
+                force.copyFromFloats(0, 0, 0);
+                alphabet.chars.forEach((pt) => {
+                    alphabet.chars[idx].subtractToRef(pt, scratch);
+                    distSq = scratch.lengthSquared();
+                    if (distSq > EPSILON_SQUARED) {
+                        scratch.scaleAndAddToRef(1 / (scratch.lengthSquared() * distSq), force);
+                    }
+                });
+                force.scaleInPlace(stepSize);
+                alphabet.chars[idx].addInPlace(force);
+                alphabet.chars[idx].normalize();
+            }
+        }
+
+        return alphabet;
+    }
+
+    /**
+     * Serialize to JSON.
+     * @returns JSON serialization
+     */
+    public serialize(): string {
+        return JSON.stringify(this.chars);
+    }
+
+    /**
+     * Deserialize from JSON.
+     * @param json JSON serialization
+     * @returns deserialized Vector3Alphabet
+     */
+    public static Deserialize(json: string): Vector3Alphabet {
+        let jsonObject = JSON.parse(json);
+        let alphabet = new Vector3Alphabet(jsonObject.length);
+        for (let idx = 0; idx < jsonObject.length; ++idx) {
+            alphabet.chars[idx] = new Vector3(
+                jsonObject[idx]["_x"],
+                jsonObject[idx]["_y"],
+                jsonObject[idx]["_z"]);
+        }
+        return alphabet;
+    }
+
+    private constructor(size: number) {
+        this.chars = new Array(size);
+    }
+}
+
+/**
+ * Class which formalizes the manner in which a Vector3Alphabet is used to tokenize and
+ * describe a Trajectory. This class houses the functionality which determines what
+ * attributes of Trajectories are and are not considered important, such as scale.
+ */
+class TrajectoryDescriptor {
+    private static readonly FINEST_DESCRIPTOR_RESOLUTION = 32;
+
+    private _sequences: Levenshtein.Sequence<number>[];
+
+    /**
+     * Serialize to JSON.
+     * @returns JSON serialization
+     */
+    public serialize(): string {
+        return JSON.stringify(this._sequences.map((sequence) => sequence.serialize()));
+    }
+
+    /**
+     * Deserialize from JSON string and Alphabet. This should be the same Alphabet
+     * from which the descriptor was originally created, which must be serialized and
+     * deserialized independently so that it can be passed in here.
+     * @param json JSON serialization
+     * @param alphabet Alphabet from which descriptor was originally created
+     * @returns deserialized TrajectoryDescriptor
+     */
+    public static Deserialize(json: string, alphabet: Levenshtein.Alphabet<number>): TrajectoryDescriptor {
+        let descriptor = new TrajectoryDescriptor();
+        descriptor._sequences =
+            (JSON.parse(json) as string[]).map(
+                (s) => Levenshtein.Sequence.Deserialize(s, alphabet));
+        return descriptor;
+    }
+
+    /**
+     * Create a new TrajectoryDescriptor to describe a provided Trajectory according
+     * to the provided alphabets.
+     * @param trajectory Trajectory to be described
+     * @param vector3Alphabet Vector3Alphabet to be used to tokenize the Trajectory
+     * @param levenshteinAlphabet Levenshtein.Alphabet to be used as basis for comparison with other descriptors
+     * @returns TrajectoryDescriptor describing provided Trajectory
+     */
+    public static CreateFromTrajectory(
+        trajectory: Trajectory,
+        vector3Alphabet: Vector3Alphabet,
+        levenshteinAlphabet: Levenshtein.Alphabet<number>): TrajectoryDescriptor {
+
+        return TrajectoryDescriptor.CreateFromTokenizationPyramid(
+            TrajectoryDescriptor._getTokenizationPyramid(trajectory, vector3Alphabet),
+            levenshteinAlphabet);
+    }
+
+    /**
+     * Create a new TrajectoryDescriptor from a pre-existing pyramid of tokens.
+     * NOTE: This function exists to support an outdated serialization mechanism and should
+     * be deleted if it is no longer useful.
+     * @param pyramid tokenization pyramid
+     * @param levenshteinAlphabet Levenshtein.Alphabet to be uses as basis for comparison with other descriptors
+     * @returns TrajectoryDescriptor describing the Trajectory from which the pyramid was built
+     */
+    public static CreateFromTokenizationPyramid(
+        pyramid: number[][],
+        levenshteinAlphabet: Levenshtein.Alphabet<number>) : TrajectoryDescriptor {
+
+        let descriptor = new TrajectoryDescriptor();
+        descriptor._sequences = pyramid.map((tokens) => new Levenshtein.Sequence<number>(tokens, levenshteinAlphabet));
+        return descriptor;
+    }
+
+    private constructor() {
+        this._sequences = [];
+    }
+
+    /**
+     * Create the tokenization pyramid for the provided Trajectory according to the given
+     * Vector3Alphabet.
+     * @param trajectory Trajectory to be tokenized
+     * @param alphabet Vector3Alphabet containing tokens
+     * @param targetResolution finest resolution of descriptor
+     * @returns tokenization pyramid for Trajectory
+     */
+    private static _getTokenizationPyramid(
+        trajectory: Trajectory,
+        alphabet: Vector3Alphabet,
+        targetResolution: number = TrajectoryDescriptor.FINEST_DESCRIPTOR_RESOLUTION): number[][] {
+
+        let pyramid: number[][] = [];
+        for (let res = targetResolution; res > 4; res = Math.floor(res / 2)) {
+            pyramid.push(trajectory.resampleAtTargetResolution(res).tokenize(alphabet.chars));
+        }
+        return pyramid;
+    }
+
+    /**
+     * Calculate a distance metric between this TrajectoryDescriptor and another. This is
+     * essentially a similarity score and does not directly represent Euclidean distance,
+     * edit distance, or any other formal distance metric.
+     * @param other TrajectoryDescriptor from which to determine distance
+     * @returns distance, a nonnegative similarity score where larger values indicate dissimilarity
+     */
+    public distance(other: TrajectoryDescriptor): number {
+        let totalDistance = 0;
+        let weight: number;
+        for (let idx = 0; idx < this._sequences.length; ++idx) {
+            weight = Math.pow(2, idx);
+            totalDistance += (weight * this._sequences[idx].distance(other._sequences[idx]));
+        }
+        return totalDistance;
+    }
+}
+
+/**
+ * A set of TrajectoryDescriptors defined to be "the same." This is essentially a helper
+ * class to facilitate methods of Trajectory clustering.
+ */
+class TrajectoryClass {
+    private static readonly MIN_AVERAGE_DISTANCE = 1;
+
+    private _descriptors: TrajectoryDescriptor[];
+    private _centroidIdx: number;
+    private _averageDistance: number;
+
+    /**
+     * Serialize to JSON.
+     * @returns JSON serialization
+     */
+    public serialize(): string {
+        let jsonObject: any = {};
+        jsonObject.descriptors = this._descriptors.map((desc) => desc.serialize());
+        jsonObject.centroidIdx = this._centroidIdx;
+        jsonObject.averageDistance = this._averageDistance;
+        return JSON.stringify(jsonObject);
+    }
+
+    /**
+     * Deserialize from JSON string and Alphabet. This should be the same Alphabet
+     * from which the descriptors were originally created, which must be serialized and
+     * deserialized independently so that it can be passed in here.
+     * @param json JSON string representation
+     * @param alphabet Alphabet from which TrajectoryDescriptors were originally created
+     * @returns deserialized TrajectoryDescriptor
+     */
+    public static Deserialize(json: string, alphabet: Levenshtein.Alphabet<number>): TrajectoryClass {
+        let jsonObject = JSON.parse(json);
+        let described = new TrajectoryClass();
+        described._descriptors = jsonObject.descriptors.map((s: string) => TrajectoryDescriptor.Deserialize(s, alphabet));
+        described._centroidIdx = jsonObject.centroidIdx;
+        described._averageDistance = jsonObject.averageDistance;
+        return described;
+    }
+
+    /**
+     * Create a new DescribedTrajectory.
+     * @param descriptors currently-known TrajectoryDescriptors, if any
+     */
+    public constructor(descriptors: TrajectoryDescriptor[] = []) {
+        this._descriptors = descriptors;
+        this._centroidIdx = -1;
+        this._averageDistance = 0;
+
+        this._refreshDescription();
+    }
+
+    /**
+     * Add a new TrajectoryDescriptor to the list of descriptors known to describe
+     * this same DescribedTrajectory.
+     * @param descriptor descriptor to be added
+     */
+    public add(descriptor: TrajectoryDescriptor): void {
+        this._descriptors.push(descriptor);
+        this._refreshDescription();
+    }
+
+    /**
+     * Compute the cost, which is inversely related to the likelihood that the provided
+     * TrajectoryDescriptor describes a Trajectory that is considered to be the same as
+     * the class represented by this DescribedTrajectory.
+     * @param descriptor the descriptor to be costed
+     * @returns cost of the match, which is a nonnegative similarity metric where larger values indicate dissimiliarity
+     */
+    public getMatchCost(descriptor: TrajectoryDescriptor): number {
+        return descriptor.distance(this._descriptors[this._centroidIdx]) / this._averageDistance;
+    }
+
+    /**
+     * Compute the minimum distance between the queried TrajectoryDescriptor and a
+     * descriptor which is a member of this collection. This is an alternative way of
+     * conceptualizing match cost from getMatchCost(), and it serves a different function.
+     * @param descriptor the descriptor to find the minimum distance to
+     * @returns minimum descriptor distance to a member descriptor of this DescribedTrajectory
+     */
+    public getMatchMinimumDistance(descriptor: TrajectoryDescriptor): number {
+        return Math.min(...this._descriptors.map((desc) => desc.distance(descriptor)));
+    }
+
+    /**
+     * Refreshes the internal representation of this DescribedTrajectory.
+     */
+    private _refreshDescription(): void {
+
+        this._centroidIdx = -1;
+        let sum: number;
+        let distances = this._descriptors.map((a) => {
+            sum = 0;
+            this._descriptors.forEach((b) => {
+                sum += a.distance(b);
+            });
+            return sum;
+        });
+        for (let idx = 0; idx < distances.length; ++idx) {
+            if (this._centroidIdx < 0 || distances[idx] < distances[this._centroidIdx]) {
+                this._centroidIdx = idx;
+            }
+        }
+
+        this._averageDistance = 0;
+        this._descriptors.forEach((desc) => {
+            this._averageDistance += desc.distance(this._descriptors[this._centroidIdx]);
+        });
+        if (this._descriptors.length > 0) {
+            this._averageDistance = Math.max(this._averageDistance / this._descriptors.length, TrajectoryClass.MIN_AVERAGE_DISTANCE);
+        }
+    }
+}
+
+/**
+ * Class representing a set of known, named trajectories to which Trajectories can be
+ * added and using which Trajectories can be recognized.
+ */
+export class TrajectoryClassifier {
+    private _maximumAllowableMatchCost: number = 4;
+    private _vector3Alphabet: Vector3Alphabet;
+    private _levenshteinAlphabet: Levenshtein.Alphabet<number>;
+    private _nameToDescribedTrajectory: Map<string, TrajectoryClass>;
+
+    /**
+     * Serialize to JSON.
+     * @returns JSON serialization
+     */
+    public serialize(): string {
+        let jsonObject: any = {};
+        jsonObject.maximumAllowableMatchCost = this._maximumAllowableMatchCost;
+        jsonObject.vector3Alphabet = this._vector3Alphabet.serialize();
+        jsonObject.levenshteinAlphabet = this._levenshteinAlphabet.serialize();
+        jsonObject.nameToDescribedTrajectory = [];
+        this._nameToDescribedTrajectory.forEach((described, name) => {
+            jsonObject.nameToDescribedTrajectory.push(name);
+            jsonObject.nameToDescribedTrajectory.push(described.serialize());
+        });
+        return JSON.stringify(jsonObject);
+    }
+
+    /**
+     * Deserialize from JSON.
+     * @param json JSON serialization
+     * @returns deserialized TrajectorySet
+     */
+    public static Deserialize(json: string): TrajectoryClassifier {
+        let jsonObject = JSON.parse(json);
+        let classifier = new TrajectoryClassifier();
+        classifier._maximumAllowableMatchCost = jsonObject.maximumAllowableMatchCost;
+        classifier._vector3Alphabet = Vector3Alphabet.Deserialize(jsonObject.vector3Alphabet);
+        classifier._levenshteinAlphabet = Levenshtein.Alphabet.Deserialize<number>(jsonObject.levenshteinAlphabet);
+        for (let idx = 0; idx < jsonObject.nameToDescribedTrajectory.length; idx += 2) {
+            classifier._nameToDescribedTrajectory.set(
+                jsonObject.nameToDescribedTrajectory[idx],
+                TrajectoryClass.Deserialize(jsonObject.nameToDescribedTrajectory[idx + 1], classifier._levenshteinAlphabet));
+        }
+        return classifier;
+    }
+
+    /**
+     * Initialize a new empty TrajectorySet with auto-generated Alphabets.
+     * VERY naive, need to be generating these things from known
+     * sets. Better version later, probably eliminating this one.
+     * @returns auto-generated TrajectorySet
+     */
+    public static Generate(): TrajectoryClassifier {
+        let vecs = Vector3Alphabet.Generate(64, 256, 0.1, 0.001, [Vector3.Forward()]);
+
+        let alphabet = new Levenshtein.Alphabet<number>(
+            Array.from(Array(vecs.chars.length), (_, idx) => idx),
+            (idx) => idx === 0 ? 0 : 1,
+            (idx) => idx === 0 ? 0 : 1,
+            (a, b) => Math.min(1 - Vector3.Dot(vecs.chars[a], vecs.chars[b]), 1));
+
+        let trajectorySet = new TrajectoryClassifier();
+        trajectorySet._vector3Alphabet = vecs;
+        trajectorySet._levenshteinAlphabet = alphabet;
+        return trajectorySet;
+    }
+
+    private constructor() {
+        this._nameToDescribedTrajectory = new Map<string, TrajectoryClass>();
+    }
+
+    /**
+     * Add a new Trajectory to the set with a given name.
+     * @param trajectory new Trajectory to be added
+     * @param classification name to which to add the Trajectory
+     */
+    public addTrajectoryToClassification(trajectory: Trajectory, classification: string): void {
+        if (!this._nameToDescribedTrajectory.has(classification)) {
+            this._nameToDescribedTrajectory.set(classification, new TrajectoryClass());
+        }
+
+        this._nameToDescribedTrajectory.get(classification)!.add(
+            TrajectoryDescriptor.CreateFromTrajectory(
+                trajectory,
+                this._vector3Alphabet,
+                this._levenshteinAlphabet));
+    }
+
+    /**
+     * Remove a known named trajectory and all Trajectories associated with it.
+     * @param classification name to remove
+     * @returns whether anything was removed
+     */
+    public deleteClassification(classification: string): boolean {
+        return this._nameToDescribedTrajectory.delete(classification);
+    }
+
+    /**
+     * Attempt to recognize a Trajectory from among all the classifications
+     * already known to the classifier.
+     * @param trajectory Trajectory to be recognized
+     * @returns classification of Trajectory if recognized, null otherwise
+     */
+    public classifyTrajectory(trajectory: Trajectory): Nullable<string> {
+        let descriptor = TrajectoryDescriptor.CreateFromTrajectory(
+            trajectory,
+            this._vector3Alphabet,
+            this._levenshteinAlphabet);
+
+        let allowableMatches: string[] = [];
+        this._nameToDescribedTrajectory.forEach((trajectoryClass, classification) => {
+            if (trajectoryClass.getMatchCost(descriptor) < this._maximumAllowableMatchCost) {
+                allowableMatches.push(classification);
+            }
+        });
+
+        if (allowableMatches.length === 0) {
+
+            return null;
+        }
+
+        let bestIdx = 0;
+        let bestMatch = this._nameToDescribedTrajectory.get(allowableMatches[bestIdx])!.getMatchMinimumDistance(descriptor);
+        let match: number;
+        for (let idx = 0; idx < allowableMatches.length; ++idx) {
+            match = this._nameToDescribedTrajectory.get(allowableMatches[idx])!.getMatchMinimumDistance(descriptor);
+            if (match < bestMatch) {
+                bestMatch = match;
+                bestIdx = idx;
+            }
+        }
+        return allowableMatches[bestIdx];
+    }
+}

+ 1 - 1
src/Particles/particleSystem.ts

@@ -1899,7 +1899,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
         if (this._isAnimationSheetEnabled && this.particleTexture) {
             var baseSize = this.particleTexture.getBaseSize();
-            effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, baseSize.width / this.spriteCellWidth);
+            effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, this.spriteCellWidth / baseSize.width);
         }
 
         effect.setVector2("translationPivot", this.translationPivot);

+ 15 - 6
src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts

@@ -12,6 +12,8 @@ import { PassPostProcess } from "../../../PostProcesses/passPostProcess";
 import { Scene } from "../../../scene";
 import { _TypeStore } from '../../../Misc/typeStore';
 import { EngineStore } from '../../../Engines/engineStore';
+import { SSAO2Configuration } from "../../../Rendering/ssao2Configuration";
+import { PrePassRenderer } from "../../../Rendering/prePassRenderer";
 import { Constants } from "../../../Engines/constants";
 
 import "../../../PostProcesses/RenderPipeline/postProcessRenderPipelineManagerSceneComponent";
@@ -19,8 +21,6 @@ import "../../../PostProcesses/RenderPipeline/postProcessRenderPipelineManagerSc
 import "../../../Shaders/ssao2.fragment";
 import "../../../Shaders/ssaoCombine.fragment";
 
-declare type PrePassRenderer = import("../../../Rendering/prePassRenderer").PrePassRenderer;
-
 /**
  * Render pipeline to produce ssao effect
  */
@@ -119,6 +119,8 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
     */
     private _sampleSphere: number[];
 
+    private _ssao2PrePassConfiguration: SSAO2Configuration;
+
     /**
     * Blur filter offsets
     */
@@ -267,6 +269,7 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         }
 
         this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+        this._ssao2PrePassConfiguration.enabled = false;
 
         super.dispose();
     }
@@ -293,7 +296,7 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             if (this._forceGeometryBuffer) {
                 effect.setTexture("depthNormalSampler", this._scene.enableGeometryBufferRenderer()!.getGBuffer().textures[0]);
             } else {
-                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[Constants.PREPASS_DEPTHNORMAL_INDEX]);
+                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[this._prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE)]);
             }
             effect.setArray("samplerOffsets", this._samplerOffsets);
         };
@@ -311,7 +314,7 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
             if (this._forceGeometryBuffer) {
                 effect.setTexture("depthNormalSampler", this._scene.enableGeometryBufferRenderer()!.getGBuffer().textures[0]);
             } else {
-                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[Constants.PREPASS_DEPTHNORMAL_INDEX]);
+                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[this._prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE)]);
             }
             effect.setArray("samplerOffsets", this._samplerOffsets);
 
@@ -429,7 +432,7 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
                 effect.setTexture("depthSampler", this._scene.enableGeometryBufferRenderer()!.getGBuffer().textures[0]);
                 effect.setTexture("normalSampler", this._scene.enableGeometryBufferRenderer()!.getGBuffer().textures[1]);
             } else {
-                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[Constants.PREPASS_DEPTHNORMAL_INDEX]);
+                effect.setTexture("depthNormalSampler", this._prePassRenderer.prePassRT.textures[this._prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE)]);
             }
             effect.setTexture("randomSampler", this._randomTexture);
         };
@@ -512,7 +515,13 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
      * @returns true if the pre pass is needed.
      */
     public setPrePassRenderer(prePassRenderer: PrePassRenderer): boolean {
-        prePassRenderer.materialsShouldRenderGeometry = prePassRenderer.materialsShouldRenderGeometry || true;
+        let cfg = this._ssao2PrePassConfiguration;
+        if (!cfg) {
+            cfg = new SSAO2Configuration();
+        }
+
+        cfg.enabled = true;
+        this._ssao2PrePassConfiguration = prePassRenderer.addEffectConfiguration(cfg);
         return true;
     }
 }

+ 9 - 9
src/PostProcesses/subSurfaceScatteringPostProcess.ts

@@ -31,22 +31,22 @@ export class SubSurfaceScatteringPostProcess extends PostProcess {
         this.updateEffect();
 
         this.onApplyObservable.add((effect: Effect) => {
-            if (!scene.prePassRenderer) {
-                Logger.Error("PrePass needs to be enabled for subsurface scattering.");
+            if (!scene.prePassRenderer || !scene.subSurfaceConfiguration) {
+                Logger.Error("PrePass and subsurface configuration needs to be enabled for subsurface scattering.");
                 return;
             }
             var texelSize = this.texelSize;
-            effect.setFloat("metersPerUnit", scene.prePassRenderer.subSurfaceConfiguration.metersPerUnit);
+            effect.setFloat("metersPerUnit", scene.subSurfaceConfiguration.metersPerUnit);
             effect.setFloat2("texelSize", texelSize.x, texelSize.y);
-            effect.setTexture("irradianceSampler", scene.prePassRenderer.prePassRT.textures[1]);
-            effect.setTexture("depthSampler", scene.prePassRenderer.prePassRT.textures[2]);
-            effect.setTexture("albedoSampler", scene.prePassRenderer.prePassRT.textures[3]);
+            effect.setTexture("irradianceSampler", scene.prePassRenderer.prePassRT.textures[scene.prePassRenderer.getIndex(Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE)]);
+            effect.setTexture("depthSampler", scene.prePassRenderer.prePassRT.textures[scene.prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE)]);
+            effect.setTexture("albedoSampler", scene.prePassRenderer.prePassRT.textures[scene.prePassRenderer.getIndex(Constants.PREPASS_ALBEDO_TEXTURE_TYPE)]);
             effect.setFloat2("viewportSize",
                 Math.tan(scene.activeCamera!.fov / 2) * scene.getEngine().getAspectRatio(scene.activeCamera!, true),
                 Math.tan(scene.activeCamera!.fov / 2));
-            effect.setArray3("diffusionS", scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionS);
-            effect.setArray("diffusionD", scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionD);
-            effect.setArray("filterRadii", scene.prePassRenderer.subSurfaceConfiguration.ssFilterRadii);
+            effect.setArray3("diffusionS", scene.subSurfaceConfiguration.ssDiffusionS);
+            effect.setArray("diffusionD", scene.subSurfaceConfiguration.ssDiffusionD);
+            effect.setArray("filterRadii", scene.subSurfaceConfiguration.ssFilterRadii);
         });
     }
 }

+ 7 - 5
src/Rendering/depthRendererSceneComponent.ts

@@ -16,9 +16,10 @@ declare module "../scene" {
          * Creates a depth renderer a given camera which contains a depth map which can be used for post processing.
          * @param camera The camera to create the depth renderer on (default: scene's active camera)
          * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         * @param force32bitsFloat Forces 32 bits float when supported (else 16 bits float is prioritized over 32 bits float if supported)
          * @returns the created depth renderer
          */
-        enableDepthRenderer(camera?: Nullable<Camera>, storeNonLinearDepth?: boolean): DepthRenderer;
+        enableDepthRenderer(camera?: Nullable<Camera>, storeNonLinearDepth?: boolean, force32bitsFloat?: boolean): DepthRenderer;
 
         /**
          * Disables a depth renderer for a given camera
@@ -28,7 +29,7 @@ declare module "../scene" {
     }
 }
 
-Scene.prototype.enableDepthRenderer = function(camera?: Nullable<Camera>, storeNonLinearDepth = false): DepthRenderer {
+Scene.prototype.enableDepthRenderer = function(camera?: Nullable<Camera>, storeNonLinearDepth = false, force32bitsFloat: boolean = false): DepthRenderer {
     camera = camera || this.activeCamera;
     if (!camera) {
         throw "No camera available to enable depth renderer";
@@ -37,11 +38,12 @@ Scene.prototype.enableDepthRenderer = function(camera?: Nullable<Camera>, storeN
         this._depthRenderer = {};
     }
     if (!this._depthRenderer[camera.id]) {
-        var textureType = 0;
-        if (this.getEngine().getCaps().textureHalfFloatRender) {
+        const supportFullfloat = !!this.getEngine().getCaps().textureFloatRender;
+        let textureType = 0;
+        if (this.getEngine().getCaps().textureHalfFloatRender && (!force32bitsFloat || !supportFullfloat)) {
             textureType = Constants.TEXTURETYPE_HALF_FLOAT;
         }
-        else if (this.getEngine().getCaps().textureFloatRender) {
+        else if (supportFullfloat) {
             textureType = Constants.TEXTURETYPE_FLOAT;
         } else {
             textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE;

+ 1 - 0
src/Rendering/index.ts

@@ -6,6 +6,7 @@ export * from "./geometryBufferRenderer";
 export * from "./geometryBufferRendererSceneComponent";
 export * from "./prePassRenderer";
 export * from "./prePassRendererSceneComponent";
+export * from "./subSurfaceSceneComponent";
 export * from "./outlineRenderer";
 export * from "./renderingGroup";
 export * from "./renderingManager";

+ 11 - 3
src/Rendering/prePassEffectConfiguration.ts

@@ -5,9 +5,17 @@ import { PostProcess } from "../PostProcesses/postProcess";
  */
 export interface PrePassEffectConfiguration {
     /**
+     * Name of the effect
+     */
+    name: string;
+    /**
      * Post process to attach for this effect
      */
-    postProcess: PostProcess;
+    postProcess?: PostProcess;
+    /**
+     * Textures required in the MRT
+     */
+    texturesRequired: number[];
     /**
      * Is the effect enabled
      */
@@ -17,7 +25,7 @@ export interface PrePassEffectConfiguration {
      */
     dispose(): void;
     /**
-     * Disposes the effect configuration
+     * Creates the associated post process
      */
-    createPostProcess: () => PostProcess;
+    createPostProcess?: () => PostProcess;
 }

+ 153 - 27
src/Rendering/prePassRenderer.ts

@@ -5,10 +5,10 @@ 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 { SubSurfaceConfiguration } from "./subSurfaceConfiguration";
-
+import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
 /**
  * Renders a pre pass of the scene
  * This means every mesh in the scene will be rendered to a render target texture
@@ -21,6 +21,39 @@ export class PrePassRenderer {
         throw _DevTools.WarnImport("PrePassRendererSceneComponent");
     }
 
+    private _textureFormats = [
+        {
+            type: Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_HALF_FLOAT,
+        },
+        {
+            type: Constants.PREPASS_POSITION_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_HALF_FLOAT,
+        },
+        {
+            type: Constants.PREPASS_VELOCITY_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_HALF_FLOAT,
+        },
+        {
+            type: Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_UNSIGNED_INT,
+        },
+        {
+            type: Constants.PREPASS_COLOR_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_HALF_FLOAT,
+        },
+        {
+            type: Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_HALF_FLOAT,
+        },
+        {
+            type: Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
+            format: Constants.TEXTURETYPE_UNSIGNED_INT,
+        },
+];
+
+    private _textureIndices: number[] = [];
+
     private _scene: Scene;
     private _engine: Engine;
     private _isDirty: boolean = false;
@@ -28,18 +61,13 @@ export class PrePassRenderer {
     /**
      * Number of textures in the multi render target texture where the scene is directly rendered
      */
-    public readonly mrtCount: number = 4;
+    public mrtCount: number = 0;
 
     /**
      * The render target where the scene is directly rendered
      */
     public prePassRT: MultiRenderTarget;
-    private _mrtTypes = [
-        Constants.TEXTURETYPE_HALF_FLOAT, // Original color
-        Constants.TEXTURETYPE_HALF_FLOAT, // Irradiance
-        Constants.TEXTURETYPE_HALF_FLOAT, // Depth (world units)
-        Constants.TEXTURETYPE_UNSIGNED_INT // Albedo
-    ];
+
     private _multiRenderAttachments: number[];
     private _defaultAttachments: number[];
     private _clearAttachments: number[];
@@ -54,9 +82,9 @@ export class PrePassRenderer {
     public imageProcessingPostProcess: ImageProcessingPostProcess;
 
     /**
-     * Configuration for sub surface scattering post process
+     * Configuration for prepass effects
      */
-    public subSurfaceConfiguration: SubSurfaceConfiguration;
+    private _effectConfigurations: PrePassEffectConfiguration[] = [];
 
     /**
      * Should materials render their geometry on the MRT
@@ -68,6 +96,9 @@ export class PrePassRenderer {
      */
     public materialsShouldRenderIrradiance: boolean = false;
 
+    private _mrtFormats: number[] = [];
+    private _mrtLayout: number[];
+
     private _enabled: boolean = false;
 
     /**
@@ -102,7 +133,7 @@ export class PrePassRenderer {
 
         PrePassRenderer._SceneComponentInitialization(this._scene);
 
-        this.subSurfaceConfiguration = new SubSurfaceConfiguration(this._scene);
+        this._resetLayout();
     }
 
     private _initializeAttachments() {
@@ -124,11 +155,9 @@ export class PrePassRenderer {
 
     private _createCompositionEffect() {
         this.prePassRT = new MultiRenderTarget("sceneprePassRT", { width: this._engine.getRenderWidth(), height: this._engine.getRenderHeight() }, this.mrtCount, this._scene,
-            { generateMipMaps: false, generateDepthTexture: true, defaultType: Constants.TEXTURETYPE_UNSIGNED_INT, types: this._mrtTypes });
+            { generateMipMaps: false, generateDepthTexture: true, defaultType: Constants.TEXTURETYPE_UNSIGNED_INT, types: this._mrtFormats });
         this.prePassRT.samples = 1;
 
-        this._initializeAttachments();
-
         this.imageProcessingPostProcess = new ImageProcessingPostProcess("sceneCompositionPass", 1, null, undefined, this._engine);
         this.imageProcessingPostProcess.autoClear = false;
     }
@@ -230,17 +259,77 @@ 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
+     * already present.
+     * @param cfg the effect configuration
+     * @return the effect configuration now used by the prepass
+     */
+    public addEffectConfiguration(cfg: PrePassEffectConfiguration) : PrePassEffectConfiguration {
+        // Do not add twice
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].name === cfg.name) {
+                return this._effectConfigurations[i];
+            }
+        }
+
+        this._effectConfigurations.push(cfg);
+        return cfg;
+    }
+
+    /**
+     * Returns the index of a texture in the multi render target texture array.
+     * @param type Texture type
+     * @return The index
+     */
+    public getIndex(type: number) : number {
+        if (!this._checkTextureType(type)) {
+            return -1;
+        }
+
+        return this._textureIndices[type];
+    }
+
     private _enable() {
-        this._resetPostProcessChain();
+        const previousMrtCount = this.mrtCount;
 
-        if (this.subSurfaceConfiguration.enabled) {
-            if (!this.subSurfaceConfiguration.postProcess) {
-                this.subSurfaceConfiguration.createPostProcess();
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].enabled) {
+                this._enableTextures(this._effectConfigurations[i].texturesRequired);
             }
+        }
 
-            this._postProcesses.push(this.subSurfaceConfiguration.postProcess);
+        if (this.prePassRT && this.mrtCount !== previousMrtCount) {
+            this.prePassRT.updateCount(this.mrtCount, { types: this._mrtFormats });
         }
 
+        this._resetPostProcessChain();
+
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].enabled) {
+                if (!this._effectConfigurations[i].postProcess && this._effectConfigurations[i].createPostProcess) {
+                    this._effectConfigurations[i].createPostProcess!();
+                }
+
+                if (this._effectConfigurations[i].postProcess) {
+                    this._postProcesses.push(this._effectConfigurations[i].postProcess!);
+                }
+            }
+        }
+
+        this._initializeAttachments();
+
         if (!this.imageProcessingPostProcess) {
             this._createCompositionEffect();
         }
@@ -252,9 +341,22 @@ export class PrePassRenderer {
 
     private _disable() {
         this._setState(false);
-        this.subSurfaceConfiguration.enabled = false;
-        this.materialsShouldRenderGeometry = false;
-        this.materialsShouldRenderIrradiance = false;
+        this._resetLayout();
+
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            this._effectConfigurations[i].enabled = false;
+        }
+    }
+
+    private _resetLayout() {
+        for (let i = 0 ; i < this._textureFormats.length; i++) {
+            this._textureIndices[this._textureFormats[i].type] = -1;
+        }
+
+        this._textureIndices[Constants.PREPASS_COLOR_TEXTURE_TYPE] = 0;
+        this._mrtLayout = [Constants.PREPASS_COLOR_TEXTURE_TYPE];
+        this._mrtFormats = [Constants.TEXTURETYPE_HALF_FLOAT];
+        this.mrtCount = 1;
     }
 
     private _resetPostProcessChain() {
@@ -263,8 +365,10 @@ export class PrePassRenderer {
             this.imageProcessingPostProcess.restoreDefaultInputTexture();
         }
 
-        if (this.subSurfaceConfiguration.postProcess) {
-            this.subSurfaceConfiguration.postProcess.restoreDefaultInputTexture();
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            if (this._effectConfigurations[i].postProcess) {
+                this._effectConfigurations[i].postProcess!.restoreDefaultInputTexture();
+            }
         }
     }
 
@@ -279,11 +383,30 @@ export class PrePassRenderer {
         this._isDirty = true;
     }
 
+    /**
+     * Enables a texture on the MultiRenderTarget for prepass
+     */
+    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;
+                this._mrtLayout.push(type);
+
+                this._mrtFormats.push(this._textureFormats[type].format);
+                this.mrtCount++;
+            }
+        }
+    }
+
     private _update() {
         this._disable();
         let enablePrePass = false;
 
-        // Subsurface scattering
         for (let i = 0; i < this._scene.materials.length; i++) {
             if (this._scene.materials[i].setPrePassRenderer(this)) {
                 enablePrePass = true;
@@ -312,8 +435,11 @@ export class PrePassRenderer {
      * Disposes the prepass renderer.
      */
     public dispose() {
+        for (let i = 0; i < this._effectConfigurations.length; i++) {
+            this._effectConfigurations[i].dispose();
+        }
+
         this.imageProcessingPostProcess.dispose();
-        this.subSurfaceConfiguration.dispose();
         this.prePassRT.dispose();
     }
 

+ 2 - 57
src/Rendering/prePassRendererSceneComponent.ts

@@ -1,25 +1,9 @@
 import { Nullable } from "../types";
 import { Scene } from "../scene";
-import { ISceneSerializableComponent, SceneComponentConstants } from "../sceneComponent";
+import { ISceneComponent, SceneComponentConstants } from "../sceneComponent";
 import { PrePassRenderer } from "./prePassRenderer";
-import { AbstractScene } from "../abstractScene";
-import { Color3 } from "../Maths/math.color";
 import { Logger } from "../Misc/logger";
 
-// Adds the parser to the scene parsers.
-AbstractScene.AddParser(SceneComponentConstants.NAME_PREPASSRENDERER, (parsedData: any, scene: Scene) => {
-    // Diffusion profiles
-    if (parsedData.ssDiffusionProfileColors !== undefined && parsedData.ssDiffusionProfileColors !== null) {
-        scene.enablePrePassRenderer();
-        if (scene.prePassRenderer) {
-            for (var index = 0, cache = parsedData.ssDiffusionProfileColors.length; index < cache; index++) {
-                var color = parsedData.ssDiffusionProfileColors[index];
-                scene.prePassRenderer.subSurfaceConfiguration.addDiffusionProfile(new Color3(color.r, color.g, color.b));
-            }
-        }
-    }
-});
-
 declare module "../abstractScene" {
     export interface AbstractScene {
         /** @hidden (Backing field) */
@@ -86,7 +70,7 @@ Scene.prototype.disablePrePassRenderer = function(): void {
  * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful
  * in several rendering techniques.
  */
-export class PrePassRendererSceneComponent implements ISceneSerializableComponent {
+export class PrePassRendererSceneComponent implements ISceneComponent {
     /**
      * The component name helpful to identify the component in the list of scene components.
      */
@@ -133,45 +117,6 @@ export class PrePassRendererSceneComponent implements ISceneSerializableComponen
     }
 
     /**
-     * Serializes the component data to the specified json object
-     * @param serializationObject The object to serialize to
-     */
-    public serialize(serializationObject: any): void {
-        if (!this.scene.prePassRenderer) {
-            return;
-        }
-
-        const ssDiffusionProfileColors = this.scene.prePassRenderer.subSurfaceConfiguration.ssDiffusionProfileColors;
-        serializationObject.ssDiffusionProfileColors = [];
-
-        for (let i = 0; i < ssDiffusionProfileColors.length; i++) {
-            serializationObject.ssDiffusionProfileColors.push({ r: ssDiffusionProfileColors[i].r,
-                                                                g: ssDiffusionProfileColors[i].g,
-                                                                b: ssDiffusionProfileColors[i].b });
-        }
-    }
-
-    /**
-     * Adds all the elements from the container to the scene
-     * @param container the container holding the elements
-     */
-    public addFromContainer(container: AbstractScene): void {
-        // Nothing to do
-    }
-
-    /**
-     * Removes all the elements in the container from the scene
-     * @param container contains the elements to remove
-     * @param dispose if the removed element should be disposed (default: false)
-     */
-    public removeFromContainer(container: AbstractScene, dispose?: boolean): void {
-        // Make sure nothing will be serialized
-        if (this.scene.prePassRenderer) {
-            this.scene.prePassRenderer.subSurfaceConfiguration.clearAllDiffusionProfiles();
-        }
-    }
-
-    /**
      * Rebuilds the elements related to this component in case of
      * context lost for instance.
      */

+ 41 - 0
src/Rendering/ssao2Configuration.ts

@@ -0,0 +1,41 @@
+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 subsurface scattering
+ */
+export class SSAO2Configuration implements PrePassEffectConfiguration {
+    /**
+     * Is subsurface enabled
+     */
+    public enabled = false;
+
+    /**
+     * Name of the configuration
+     */
+    public name = "ssao2";
+
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    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
+    }
+}

+ 26 - 0
src/Rendering/subSurfaceConfiguration.ts

@@ -2,12 +2,21 @@ import { Logger } from "../Misc/logger";
 import { Scene } from "../scene";
 import { Color3 } from "../Maths/math.color";
 import { SubSurfaceScatteringPostProcess } from "../PostProcesses/subSurfaceScatteringPostProcess";
+import { SceneComponentConstants } from "../sceneComponent";
 import { PrePassEffectConfiguration } from "./prePassEffectConfiguration";
+import { _DevTools } from '../Misc/devTools';
+import { Constants } from "../Engines/constants";
+
 /**
  * Contains all parameters needed for the prepass to perform
  * screen space subsurface scattering
  */
 export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
+    /** @hidden */
+    public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
+        throw _DevTools.WarnImport("PrePassRendererSceneComponent");
+    }
+
     private _ssDiffusionS: number[] = [];
     private _ssFilterRadii: number[] = [];
     private _ssDiffusionD: number[] = [];
@@ -44,6 +53,11 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
     public enabled = false;
 
     /**
+     * Name of the configuration
+     */
+    public name = SceneComponentConstants.NAME_SUBSURFACE;
+
+    /**
      * Diffusion profile colors for subsurface scattering
      * You can add one diffusion color using `addDiffusionProfile` on `scene.prePassRenderer`
      * See ...
@@ -57,6 +71,16 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
      */
     public metersPerUnit: number = 1;
 
+    /**
+     * Textures that should be present in the MRT for this effect to work
+     */
+    public readonly texturesRequired: number[] = [
+        Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE,
+        Constants.PREPASS_ALBEDO_TEXTURE_TYPE,
+        Constants.PREPASS_COLOR_TEXTURE_TYPE,
+        Constants.PREPASS_IRRADIANCE_TEXTURE_TYPE,
+    ];
+
     private _scene: Scene;
 
     /**
@@ -67,6 +91,8 @@ export class SubSurfaceConfiguration implements PrePassEffectConfiguration {
         // Adding default diffusion profile
         this.addDiffusionProfile(new Color3(1, 1, 1));
         this._scene = scene;
+
+        SubSurfaceConfiguration._SceneComponentInitialization(this._scene);
     }
 
     /**

+ 181 - 0
src/Rendering/subSurfaceSceneComponent.ts

@@ -0,0 +1,181 @@
+import { Nullable } from "../types";
+import { Scene } from "../scene";
+import { ISceneSerializableComponent, SceneComponentConstants } from "../sceneComponent";
+import { SubSurfaceConfiguration } from "./subSurfaceConfiguration";
+import { AbstractScene } from "../abstractScene";
+import { Color3 } from "../Maths/math.color";
+
+// Adds the parser to the scene parsers.
+AbstractScene.AddParser(SceneComponentConstants.NAME_SUBSURFACE, (parsedData: any, scene: Scene) => {
+    // Diffusion profiles
+    if (parsedData.ssDiffusionProfileColors !== undefined && parsedData.ssDiffusionProfileColors !== null) {
+        scene.enableSubSurfaceForPrePass();
+        if (scene.subSurfaceConfiguration) {
+            for (var index = 0, cache = parsedData.ssDiffusionProfileColors.length; index < cache; index++) {
+                var color = parsedData.ssDiffusionProfileColors[index];
+                scene.subSurfaceConfiguration.addDiffusionProfile(new Color3(color.r, color.g, color.b));
+            }
+        }
+    }
+});
+
+declare module "../abstractScene" {
+    export interface AbstractScene {
+        /** @hidden (Backing field) */
+        _subSurfaceConfiguration: Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Gets or Sets the current prepass renderer associated to the scene.
+         */
+        subSurfaceConfiguration: Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Enables the subsurface effect for prepass
+         * @returns the SubSurfaceConfiguration
+         */
+        enableSubSurfaceForPrePass(): Nullable<SubSurfaceConfiguration>;
+
+        /**
+         * Disables the subsurface effect for prepass
+         */
+        disableSubSurfaceForPrePass(): void;
+    }
+}
+
+Object.defineProperty(Scene.prototype, "subSurfaceConfiguration", {
+    get: function(this: Scene) {
+        return this._subSurfaceConfiguration;
+    },
+    set: function(this: Scene, value: Nullable<SubSurfaceConfiguration>) {
+        if (value) {
+            if (this.enablePrePassRenderer()) {
+                    this._subSurfaceConfiguration = value;
+            }
+        }
+    },
+    enumerable: true,
+    configurable: true
+});
+
+Scene.prototype.enableSubSurfaceForPrePass = function(): Nullable<SubSurfaceConfiguration> {
+    if (this._subSurfaceConfiguration) {
+        return this._subSurfaceConfiguration;
+    }
+
+    const prePassRenderer = this.enablePrePassRenderer();
+    if (prePassRenderer) {
+        this._subSurfaceConfiguration = new SubSurfaceConfiguration(this);
+        prePassRenderer.addEffectConfiguration(this._subSurfaceConfiguration);
+        return this._subSurfaceConfiguration;
+    }
+
+    return null;
+
+};
+
+Scene.prototype.disableSubSurfaceForPrePass = function(): void {
+    if (!this._subSurfaceConfiguration) {
+        return;
+    }
+
+    this._subSurfaceConfiguration.dispose();
+    this._subSurfaceConfiguration = null;
+};
+
+/**
+ * Defines the Geometry Buffer scene component responsible to manage a G-Buffer useful
+ * in several rendering techniques.
+ */
+export class SubSurfaceSceneComponent implements ISceneSerializableComponent {
+    /**
+     * The component name helpful to identify the component in the list of scene components.
+     */
+    public readonly name = SceneComponentConstants.NAME_PREPASSRENDERER;
+
+    /**
+     * The scene the component belongs to.
+     */
+    public scene: Scene;
+
+    /**
+     * Creates a new instance of the component for the given scene
+     * @param scene Defines the scene to register the component in
+     */
+    constructor(scene: Scene) {
+        this.scene = scene;
+    }
+
+    /**
+     * Registers the component in a given scene
+     */
+    public register(): void {
+    }
+
+    /**
+     * Serializes the component data to the specified json object
+     * @param serializationObject The object to serialize to
+     */
+    public serialize(serializationObject: any): void {
+        if (!this.scene.subSurfaceConfiguration) {
+            return;
+        }
+
+        const ssDiffusionProfileColors = this.scene.subSurfaceConfiguration.ssDiffusionProfileColors;
+        serializationObject.ssDiffusionProfileColors = [];
+
+        for (let i = 0; i < ssDiffusionProfileColors.length; i++) {
+            serializationObject.ssDiffusionProfileColors.push({ r: ssDiffusionProfileColors[i].r,
+                                                                g: ssDiffusionProfileColors[i].g,
+                                                                b: ssDiffusionProfileColors[i].b });
+        }
+    }
+
+    /**
+     * Adds all the elements from the container to the scene
+     * @param container the container holding the elements
+     */
+    public addFromContainer(container: AbstractScene): void {
+        // Nothing to do
+    }
+
+    /**
+     * Removes all the elements in the container from the scene
+     * @param container contains the elements to remove
+     * @param dispose if the removed element should be disposed (default: false)
+     */
+    public removeFromContainer(container: AbstractScene, dispose?: boolean): void {
+        // Make sure nothing will be serialized
+        if (!this.scene.prePassRenderer) {
+            return;
+        }
+
+        if (this.scene.subSurfaceConfiguration) {
+            this.scene.subSurfaceConfiguration.clearAllDiffusionProfiles();
+        }
+    }
+
+    /**
+     * Rebuilds the elements related to this component in case of
+     * context lost for instance.
+     */
+    public rebuild(): void {
+        // Nothing to do for this component
+    }
+
+    /**
+     * Disposes the component and the associated ressources
+     */
+    public dispose(): void {
+        // Nothing to do for this component
+    }
+
+}
+
+SubSurfaceConfiguration._SceneComponentInitialization = (scene: Scene) => {
+    // Register the G Buffer component to the scene.
+    let component = scene._getComponent(SceneComponentConstants.NAME_SUBSURFACE) as SubSurfaceSceneComponent;
+    if (!component) {
+        component = new SubSurfaceSceneComponent(scene);
+        scene._addComponent(component);
+    }
+};

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

@@ -481,10 +481,19 @@ color.rgb = max(color.rgb, 0.);
 
 #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 #ifdef PREPASS
-    gl_FragData[0] = color; // Lit without irradiance
-    gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0); // Irradiance
-    gl_FragData[2] = vec4(vViewPos.z, (view * vec4(normalW, 0.0)).rgb); // Linear depth + normal
-    gl_FragData[3] = vec4(0.0, 0.0, 0.0, 1.0); // albedo, for pre and post scatter
+    gl_FragData[0] = color; // We can't split irradiance on std material
+
+    #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
+    #endif
+
+    #ifdef PREPASS_DEPTHNORMAL
+    	gl_FragData[PREPASS_DEPTHNORMAL_INDEX] = vec4(vViewPos.z, (view * vec4(normalW, 0.0)).rgb); // Linear depth + normal
+    #endif
+
+    #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
 #endif
 	gl_FragColor = color;
 

+ 2 - 2
src/Shaders/particles.vertex.fx

@@ -135,8 +135,8 @@ void main(void) {
 	vColor = color;
 
 	#ifdef ANIMATESHEET
-		float rowOffset = floor(cellIndex / particlesInfos.z);
-		float columnOffset = cellIndex - rowOffset * particlesInfos.z;
+		float rowOffset = floor(cellIndex * particlesInfos.z);
+		float columnOffset = cellIndex - rowOffset / particlesInfos.z;
 
 		vec2 uvScale = particlesInfos.xy;
 		vec2 uvOffset = vec2(offset.x , 1.0 - offset.y);

+ 22 - 15
src/Shaders/pbr.fragment.fx

@@ -502,26 +502,33 @@ void main(void) {
     #define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 
 #ifdef PREPASS
-    vec3 irradiance = finalDiffuse;
-    #ifndef UNLIT
-        #ifdef REFLECTION
-            irradiance += finalIrradiance;
+    #ifdef PREPASS_IRRADIANCE
+        vec3 irradiance = finalDiffuse;
+        #ifndef UNLIT
+            #ifdef REFLECTION
+                irradiance += finalIrradiance;
+            #endif
+        #endif
+
+        vec3 sqAlbedo = sqrt(surfaceAlbedo); // for pre and post scatter
+        gl_FragData[0] = vec4(finalColor.rgb - irradiance, finalColor.a); // Split irradiance from final color
+        irradiance /= sqAlbedo;
+        
+        #ifndef SS_SCATTERING
+            float scatteringDiffusionProfile = 255.;
         #endif
+        gl_FragData[PREPASS_IRRADIANCE_INDEX] = vec4(tagLightingForSSS(irradiance), scatteringDiffusionProfile / 255.); // Irradiance + SS diffusion profile
+    #else
+        gl_FragData[0] = vec4(finalColor.rgb, finalColor.a);
     #endif
 
-    vec3 sqAlbedo = sqrt(surfaceAlbedo); // for pre and post scatter
+    #ifdef PREPASS_DEPTHNORMAL
+        gl_FragData[PREPASS_DEPTHNORMAL_INDEX] = vec4(vViewPos.z, (view * vec4(normalW, 0.0)).rgb); // Linear depth + normal
+    #endif
 
-    // Irradiance is diffuse * surfaceAlbedo
-    #ifdef SS_SCATTERING
-    gl_FragData[0] = vec4(finalColor.rgb - irradiance, finalColor.a); // Lit without irradiance
-    irradiance /= sqAlbedo;
-    gl_FragData[1] = vec4(tagLightingForSSS(irradiance), scatteringDiffusionProfile / 255.); // Irradiance + SS diffusion profile
-    #else
-    gl_FragData[0] = vec4(finalColor.rgb, finalColor.a); // Lit without irradiance
-    gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0); // Irradiance
+    #ifdef PREPASS_ALBEDO
+        gl_FragData[PREPASS_ALBEDO_INDEX] = vec4(sqAlbedo, 1.0); // albedo, for pre and post scatter
     #endif
-    gl_FragData[2] = vec4(vViewPos.z, (view * vec4(normalW, 0.0)).rgb); // Linear depth + normal
-    gl_FragData[3] = vec4(sqAlbedo, 1.0); // albedo, for pre and post scatter
 #endif
 
     gl_FragColor = finalColor;

+ 9 - 2
src/XR/webXRCamera.ts

@@ -5,7 +5,7 @@ import { FreeCamera } from "../Cameras/freeCamera";
 import { TargetCamera } from "../Cameras/targetCamera";
 import { WebXRSessionManager } from "./webXRSessionManager";
 import { Viewport } from "../Maths/math.viewport";
-import { Observable } from '../Misc/observable';
+import { Observable } from "../Misc/observable";
 
 /**
  * WebXR Camera which holds the views for the xrSession
@@ -49,6 +49,8 @@ export class WebXRCamera extends FreeCamera {
         this.cameraRigMode = Camera.RIG_MODE_CUSTOM;
         this.updateUpVectorFromRotation = true;
         this._updateNumberOfRigCameras(1);
+        // freeze projection matrix, which will be copied later
+        this.freezeProjectionMatrix();
 
         this._xrSessionManager.onXRSessionInit.add(() => {
             this._referencedPosition.copyFromFloats(0, 0, 0);
@@ -167,7 +169,7 @@ export class WebXRCamera extends FreeCamera {
             this._updateNumberOfRigCameras(pose.views.length);
         }
 
-        pose.views.forEach((view: any, i: number) => {
+        pose.views.forEach((view: XRView, i: number) => {
             const currentRig = <TargetCamera>this.rigCameras[i];
             // update right and left, where applicable
             if (!currentRig.isLeftCamera && !currentRig.isRightCamera) {
@@ -196,6 +198,11 @@ export class WebXRCamera extends FreeCamera {
                 currentRig._projectionMatrix.toggleProjectionMatrixHandInPlace();
             }
 
+            // first camera?
+            if (i === 0) {
+                this._projectionMatrix.copyFrom(currentRig._projectionMatrix);
+            }
+
             // Update viewport
             if (this._xrSessionManager.session.renderState.baseLayer) {
                 var viewport = this._xrSessionManager.session.renderState.baseLayer.getViewport(view);

+ 1 - 0
src/sceneComponent.ts

@@ -28,6 +28,7 @@ export class SceneComponentConstants {
     public static readonly NAME_DEPTHRENDERER = "DepthRenderer";
     public static readonly NAME_POSTPROCESSRENDERPIPELINEMANAGER = "PostProcessRenderPipelineManager";
     public static readonly NAME_SPRITE = "Sprite";
+    public static readonly NAME_SUBSURFACE = "SubSurface";
     public static readonly NAME_OUTLINERENDERER = "Outline";
     public static readonly NAME_PROCEDURALTEXTURE = "ProceduralTexture";
     public static readonly NAME_SHADOWGENERATOR = "ShadowGenerator";