瀏覽代碼

Merge branch 'master' into LineMeshBoundingBias

Julien Barrois 6 年之前
父節點
當前提交
7221a608e1
共有 48 個文件被更改,包括 11518 次插入10023 次删除
  1. 3160 3100
      Playground/babylon.d.txt
  2. 2 1
      Tools/Gulp/config.json
  3. 1 1
      Viewer/package.json
  4. 6397 6339
      dist/preview release/babylon.d.ts
  5. 1 1
      dist/preview release/babylon.js
  6. 216 113
      dist/preview release/babylon.max.js
  7. 216 113
      dist/preview release/babylon.no-module.max.js
  8. 1 1
      dist/preview release/babylon.worker.js
  9. 218 115
      dist/preview release/es6.js
  10. 1 1
      dist/preview release/glTF2Interface/package.json
  11. 2 0
      dist/preview release/gui/babylon.gui.d.ts
  12. 1 1
      dist/preview release/gui/babylon.gui.js
  13. 1 1
      dist/preview release/gui/babylon.gui.min.js
  14. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  15. 4 0
      dist/preview release/gui/babylon.gui.module.d.ts
  16. 2 2
      dist/preview release/gui/package.json
  17. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  18. 5 5
      dist/preview release/inspector/package.json
  19. 2 2
      dist/preview release/loaders/package.json
  20. 2 2
      dist/preview release/materialsLibrary/package.json
  21. 2 2
      dist/preview release/postProcessesLibrary/package.json
  22. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  23. 3 3
      dist/preview release/serializers/package.json
  24. 459 0
      dist/preview release/viewer/babylon.viewer.d.ts
  25. 2 2
      dist/preview release/viewer/babylon.viewer.js
  26. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  27. 492 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  28. 10 4
      dist/preview release/what's new.md
  29. 1 1
      inspector/src/tools/FullscreenTool.ts
  30. 1 1
      package.json
  31. 49 0
      src/Cameras/XR/babylon.webXRCamera.ts
  32. 9 1
      src/Cameras/babylon.camera.ts
  33. 1 1
      src/Culling/babylon.boundingBox.ts
  34. 12 4
      src/Engine/babylon.engine.ts
  35. 6 6
      src/Materials/babylon.material.ts
  36. 2 2
      src/Materials/babylon.multiMaterial.ts
  37. 1 1
      src/Materials/babylon.pushMaterial.ts
  38. 5 5
      src/Mesh/babylon.mesh.ts
  39. 19 20
      src/Particles/babylon.gpuParticleSystem.ts
  40. 149 149
      src/Particles/babylon.particleSystem.ts
  41. 2 2
      src/PostProcess/babylon.motionBlurPostProcess.ts
  42. 20 0
      src/Tools/babylon.tools.ts
  43. 0 4
      src/babylon.mixins.ts
  44. 30 5
      src/babylon.scene.ts
  45. 1 1
      src/babylon.sceneComponent.ts
  46. 二進制
      tests/validation/ReferenceImages/cameraRig.png
  47. 1 1
      tests/validation/config.json
  48. 3 3
      tests/validation/validation.js

文件差異過大導致無法顯示
+ 3160 - 3100
Playground/babylon.d.txt


+ 2 - 1
Tools/Gulp/config.json

@@ -1297,7 +1297,8 @@
                 "../../src/Cameras/VR/babylon.vrDeviceOrientationFreeCamera.js",
                 "../../src/Cameras/VR/babylon.vrDeviceOrientationArcRotateCamera.js",
                 "../../src/Cameras/VR/babylon.vrDeviceOrientationGamepadCamera.js",
-                "../../src/Cameras/VR/babylon.vrExperienceHelper.js"
+                "../../src/Cameras/VR/babylon.vrExperienceHelper.js",
+                "../../src/Cameras/XR/babylon.webXRCamera.js"
             ],
             "dependUpon": [
                 "core",

+ 1 - 1
Viewer/package.json

@@ -42,4 +42,4 @@
     "dependencies": {
         "pepjs": "^0.4.3"
     }
-}
+}

文件差異過大導致無法顯示
+ 6397 - 6339
dist/preview release/babylon.d.ts


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.js


+ 216 - 113
dist/preview release/babylon.max.js

@@ -12272,6 +12272,10 @@ var BABYLON;
              */
             this.onBeginFrameObservable = new BABYLON.Observable();
             /**
+             * If set, will be used to request the next animation frame for the render loop
+             */
+            this.customAnimationFrameRequester = null;
+            /**
              * Observable raised when the engine ends the current frame
              */
             this.onEndFrameObservable = new BABYLON.Observable();
@@ -13434,11 +13438,16 @@ var BABYLON;
             }
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = BABYLON.Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                }
+                else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                }
+                else {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             }
             else {
                 this._renderingQueueLaunched = false;
@@ -19208,7 +19217,7 @@ var BABYLON;
             this.minimum.copyFrom(min);
             this.maximum.copyFrom(max);
             var distance = BABYLON.Vector3.Distance(min, max);
-            BABYLON.Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
             this._update(worldMatrix || _identityMatrix);
         };
@@ -19219,8 +19228,8 @@ var BABYLON;
          */
         BoundingSphere.prototype.scale = function (factor) {
             var newRadius = this.radius * factor;
-            var tmpVectors = BABYLON.Tmp.Vector3;
-            var tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
+            var tmpVectors = BoundingSphere.TmpVector3;
+            var tempRadiusVector = tmpVectors[0].setAll(newRadius);
             var min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
             var max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
             this.reConstruct(min, max);
@@ -19230,7 +19239,7 @@ var BABYLON;
         /** @hidden */
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            var tempVector = BABYLON.Tmp.Vector3[0];
+            var tempVector = BoundingSphere.TmpVector3[0];
             BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         };
@@ -19253,11 +19262,8 @@ var BABYLON;
          * @returns true if the point is inside the bounding sphere
          */
         BoundingSphere.prototype.intersectsPoint = function (point) {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (this.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
             return true;
@@ -19270,15 +19276,14 @@ var BABYLON;
          * @returns true if the speres intersect
          */
         BoundingSphere.Intersects = function (sphere0, sphere1) {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            var radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
             return true;
         };
+        BoundingSphere.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingSphere;
     }());
     BABYLON.BoundingSphere = BoundingSphere;
@@ -19366,8 +19371,8 @@ var BABYLON;
             vectors[6].copyFromFloats(minX, maxY, maxZ);
             vectors[7].copyFromFloats(maxX, minY, maxZ);
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(min, this.extendSize).scaleInPlace(0.5);
             this._update(worldMatrix || this._worldMatrix || BABYLON.Matrix.Identity());
         };
         /**
@@ -19376,7 +19381,7 @@ var BABYLON;
          * @returns the current bounding box
          */
         BoundingBox.prototype.scale = function (factor) {
-            var tmpVectors = BABYLON.Tmp.Vector3;
+            var tmpVectors = BoundingBox.TmpVector3;
             var diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             var len = diff.length();
             diff.normalizeFromLength(len);
@@ -19557,6 +19562,7 @@ var BABYLON;
             }
             return true;
         };
+        BoundingBox.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingBox;
     }());
     BABYLON.BoundingBox = BoundingBox;
@@ -19866,6 +19872,8 @@ var BABYLON;
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
             _this._isWorldMatrixFrozen = false;
+            /** @hidden */
+            _this._indexInSceneTransformNodesArray = -1;
             /**
             * An event triggered after the world matrix is updated
             */
@@ -19937,8 +19945,8 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector.
-                if (quaternion && this.rotation.length()) {
-                    this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+                if (quaternion) {
+                    this.rotation.setAll(0.0);
                 }
             },
             enumerable: true,
@@ -20070,7 +20078,7 @@ var BABYLON;
         */
         TransformNode.prototype.setPivotMatrix = function (matrix, postMultiplyPivotMatrix) {
             if (postMultiplyPivotMatrix === void 0) { postMultiplyPivotMatrix = true; }
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             if (this._postMultiplyPivotMatrix) {
@@ -20154,10 +20162,9 @@ var BABYLON;
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             }
             else {
                 this.position.x = absolutePositionX;
@@ -20182,8 +20189,8 @@ var BABYLON;
          */
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
+            var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20320,52 +20327,33 @@ var BABYLON;
             if (!node && !this.parent) {
                 return this;
             }
+            var quatRotation = BABYLON.Tmp.Quaternion[0];
+            var position = BABYLON.Tmp.Vector3[0];
+            var scale = BABYLON.Tmp.Vector3[1];
             if (!node) {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             }
             else {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 var diffMatrix = BABYLON.Tmp.Matrix[0];
                 var invParentMatrix = BABYLON.Tmp.Matrix[1];
                 this.computeWorldMatrix(true);
                 node.computeWorldMatrix(true);
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
             }
+            else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
+            }
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
             this.parent = node;
             return this;
         };
@@ -20429,8 +20417,8 @@ var BABYLON;
         TransformNode.prototype.rotate = function (axis, amount, space) {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion;
             if (!space || space === BABYLON.Space.LOCAL) {
@@ -20439,8 +20427,8 @@ var BABYLON;
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = BABYLON.Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -20462,17 +20450,25 @@ var BABYLON;
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-            point.subtractToRef(this.position, BABYLON.Tmp.Vector3[0]);
-            BABYLON.Matrix.TranslationToRef(BABYLON.Tmp.Vector3[0].x, BABYLON.Tmp.Vector3[0].y, BABYLON.Tmp.Vector3[0].z, BABYLON.Tmp.Matrix[0]);
-            BABYLON.Tmp.Matrix[0].invertToRef(BABYLON.Tmp.Matrix[2]);
-            BABYLON.Matrix.RotationAxisToRef(axis, amount, BABYLON.Tmp.Matrix[1]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[1], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
-            this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                this.rotation.setAll(0);
+            }
+            var tmpVector = BABYLON.Tmp.Vector3[0];
+            var finalScale = BABYLON.Tmp.Vector3[1];
+            var finalTranslation = BABYLON.Tmp.Vector3[2];
+            var finalRotation = BABYLON.Tmp.Quaternion[0];
+            var translationMatrix = BABYLON.Tmp.Matrix[0]; // T
+            var translationMatrixInv = BABYLON.Tmp.Matrix[1]; // T'
+            var rotationMatrix = BABYLON.Tmp.Matrix[2]; // R
+            var finalMatrix = BABYLON.Tmp.Matrix[3]; // T' x R x T
+            point.subtractToRef(this.position, tmpVector);
+            BABYLON.Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            BABYLON.Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix); // T' x R x T
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -23469,6 +23465,10 @@ var BABYLON;
              */
             _this.customRenderTargets = new Array();
             /**
+             * When set, the camera will render to this render target instead of the default canvas
+             */
+            _this.customDefaultRenderTarget = null;
+            /**
              * Observable triggered when the camera view matrix has changed.
              */
             _this.onViewMatrixChangedObservable = new BABYLON.Observable();
@@ -24379,6 +24379,10 @@ var BABYLON;
          */
         Camera.RIG_MODE_WEBVR = 21;
         /**
+         * Custom rig mode allowing rig cameras to be populated manually with any number of cameras
+         */
+        Camera.RIG_MODE_CUSTOM = 22;
+        /**
          * Defines if by default attaching controls should prevent the default javascript event to continue.
          */
         Camera.ForceAttachControlToAlwaysPreventDefault = false;
@@ -25204,6 +25208,9 @@ var BABYLON;
             this.geometries = new Array();
             /**
             * All of the tranform nodes added to this scene
+            * In the context a the Scene, it is not supposed to be modified manually.
+            * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+            * Note also that the order of the TransformNode wihin the array is not significant and might change.
             * @see http://doc.babylonjs.com/how_to/transformnode
             */
             this.transformNodes = new Array();
@@ -25404,6 +25411,11 @@ var BABYLON;
              * in order to block unwanted artifacts like system double clicks
              */
             _this.preventDefaultOnPointerDown = true;
+            /**
+             * This is used to call preventDefault() on pointer up
+             * in order to block unwanted artifacts like system double clicks
+             */
+            _this.preventDefaultOnPointerUp = true;
             // Metadata
             /**
              * Gets or sets user defined metadata
@@ -26918,6 +26930,7 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
+                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -26938,6 +26951,7 @@ var BABYLON;
                             if (Date.now() - _this._previousStartingPointerTime > Scene.DoubleClickDelay ||
                                 btn !== _this._previousButtonPressed) {
                                 clickInfo.singleClick = true;
+                                eventRaised = true;
                                 cb(clickInfo, _this._currentPickResult);
                             }
                         }
@@ -27003,8 +27017,10 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, _this._currentPickResult);
+                if (!eventRaised) {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27060,6 +27076,10 @@ var BABYLON;
                 _this._pickedUpMesh = null;
                 _this._meshPickProceed = false;
                 _this._updatePointerPosition(evt);
+                if (_this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
                 _this._initClickEvent(_this.onPrePointerObservable, _this.onPointerObservable, evt, function (clickInfo, pickResult) {
                     // PreObservable support
                     if (_this.onPrePointerObservable.hasObservers()) {
@@ -27908,6 +27928,7 @@ var BABYLON;
          * @param newTransformNode defines the transform node to add
          */
         Scene.prototype.addTransformNode = function (newTransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
         };
@@ -27917,10 +27938,15 @@ var BABYLON;
          * @returns the index where the transform node was in the transform node list
          */
         Scene.prototype.removeTransformNode = function (toRemove) {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    var lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);
             return index;
@@ -28899,7 +28925,7 @@ var BABYLON;
                     continue;
                 }
                 mesh._preActivate();
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
@@ -29028,7 +29054,18 @@ var BABYLON;
                     step.action(this.activeCamera);
                 }
                 this._intermediateRendering = false;
-                engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                if (this.activeCamera.customDefaultRenderTarget) {
+                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                    if (internalTexture) {
+                        engine.bindFramebuffer(internalTexture);
+                    }
+                    else {
+                        BABYLON.Tools.Error("Camera contains invalid customDefaultRenderTarget");
+                    }
+                }
+                else {
+                    engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                }
             }
             this.onAfterRenderTargetsRenderObservable.notifyObservers(this);
             // Prepare Frame
@@ -33011,12 +33048,12 @@ var BABYLON;
             this.computeWorldMatrix();
             var mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var _i = 0, _a = this.subMeshes; _i < _a.length; _i++) {
                         var subMesh = _a[_i];
                         var effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -33693,7 +33730,7 @@ var BABYLON;
                 return this;
             }
             this._effectiveMaterial = material;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -33710,7 +33747,7 @@ var BABYLON;
                 step.action(this, subMesh, batch);
             }
             var effect;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             }
             else {
@@ -33736,7 +33773,7 @@ var BABYLON;
                 this._bind(subMesh, effect, fillMode);
             }
             var world = this.getWorldMatrix();
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
             else {
@@ -36378,9 +36415,9 @@ var BABYLON;
              */
             this.doNotSerialize = false;
             /**
-             * Specifies if the effect should be stored on sub meshes
+             * @hidden
              */
-            this.storeEffectOnSubMeshes = false;
+            this._storeEffectOnSubMeshes = false;
             /**
             * An event triggered when the material is disposed
             */
@@ -37066,7 +37103,7 @@ var BABYLON;
                 if (localOptions.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
-                if (_this.storeEffectOnSubMeshes) {
+                if (_this._storeEffectOnSubMeshes) {
                     if (_this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(_this);
@@ -37226,7 +37263,7 @@ var BABYLON;
                     mesh.material = null;
                     if (mesh.geometry) {
                         var geometry = (mesh.geometry);
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
                                 var subMesh = _a[_i];
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
@@ -37244,7 +37281,7 @@ var BABYLON;
             this._uniformBuffer.dispose();
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
                 this._effect = null;
@@ -43224,7 +43261,7 @@ var BABYLON;
              * This is mostly used when shader parallel compilation is supported (true by default)
              */
             _this.allowShaderHotSwapping = true;
-            _this.storeEffectOnSubMeshes = true;
+            _this._storeEffectOnSubMeshes = true;
             return _this;
         }
         PushMaterial.prototype.getEffect = function () {
@@ -61843,10 +61880,10 @@ var BABYLON;
                 if (!this.isReady()) {
                     return;
                 }
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
             this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene.getAnimationRatio());
             // Determine the number of particles we need to create
@@ -67566,10 +67603,10 @@ var BABYLON;
                     }
                     this._preWarmDone = true;
                 }
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return 0;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
             // Get everything ready to render
             this._initialize();
@@ -68345,13 +68382,22 @@ var BABYLON;
             var index = 0;
             var idx = 0;
             var tmpNormal = BABYLON.Tmp.Vector3[0];
-            var rotMatrix = BABYLON.Tmp.Matrix[0];
-            var invertedRotMatrix = BABYLON.Tmp.Matrix[1];
+            var quaternion = BABYLON.Tmp.Quaternion[0];
+            var invertedRotMatrix = BABYLON.Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 var particle = this.particles[p];
                 var shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    var rotation = particle.rotation;
+                    BABYLON.Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;
                     BABYLON.Vector3.TransformNormalFromFloatsToRef(this._normals32[idx], this._normals32[idx + 1], this._normals32[idx + 2], invertedRotMatrix, tmpNormal);
@@ -80200,7 +80246,7 @@ var BABYLON;
             var _this = _super.call(this, name, scene, true) || this;
             scene.multiMaterials.push(_this);
             _this.subMaterials = new Array();
-            _this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            _this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
             return _this;
         }
         Object.defineProperty(MultiMaterial.prototype, "subMaterials", {
@@ -80282,7 +80328,7 @@ var BABYLON;
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }
@@ -91784,7 +91830,7 @@ var BABYLON;
      * The Motion Blur Post Process which blurs an image based on the objects velocity in scene.
      * Velocity can be affected by each object's rotation, position and scale depending on the transformation speed.
      * As an example, all you have to do is to create the post-process:
-     *  var mb = new BABYLON.MotionBlurProcess(
+     *  var mb = new BABYLON.MotionBlurPostProcess(
      *      'mb', // The name of the effect.
      *      scene, // The scene containing the objects to blur according to their velocity.
      *      1.0, // The required width/height ratio to downsize to before computing the render pass.
@@ -91792,8 +91838,8 @@ var BABYLON;
      * );
      * Then, all objects moving, rotating and/or scaling will be blurred depending on the transformation speed.
      */
-    var MotionBlurProcess = /** @class */ (function (_super) {
-        __extends(MotionBlurProcess, _super);
+    var MotionBlurPostProcess = /** @class */ (function (_super) {
+        __extends(MotionBlurPostProcess, _super);
         /**
          * Creates a new instance MotionBlurPostProcess
          * @param name The name of the effect.
@@ -91806,7 +91852,7 @@ var BABYLON;
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function MotionBlurProcess(name, scene, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
+        function MotionBlurPostProcess(name, scene, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, name, "motionBlur", ["motionStrength", "motionScale", "screenSize"], ["velocitySampler"], options, camera, samplingMode, engine, reusable, "#define SAMPLES 64.0", textureType, undefined, null, blockCompilation) || this;
@@ -91835,7 +91881,7 @@ var BABYLON;
             };
             return _this;
         }
-        Object.defineProperty(MotionBlurProcess.prototype, "motionBlurSamples", {
+        Object.defineProperty(MotionBlurPostProcess.prototype, "motionBlurSamples", {
             /**
              * Gets the number of iterations are used for motion blur quality. Default value is equal to 32
              */
@@ -91856,16 +91902,16 @@ var BABYLON;
          * Disposes the post process.
          * @param camera The camera to dispose the post process on.
          */
-        MotionBlurProcess.prototype.dispose = function (camera) {
+        MotionBlurPostProcess.prototype.dispose = function (camera) {
             if (this._geometryBufferRenderer) {
                 // Clear previous transformation matrices dictionary used to compute objects velocities
                 this._geometryBufferRenderer._previousTransformationMatrices = {};
             }
             _super.prototype.dispose.call(this, camera);
         };
-        return MotionBlurProcess;
+        return MotionBlurPostProcess;
     }(BABYLON.PostProcess));
-    BABYLON.MotionBlurProcess = MotionBlurProcess;
+    BABYLON.MotionBlurPostProcess = MotionBlurPostProcess;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=babylon.motionBlurPostProcess.js.map
@@ -108183,6 +108229,63 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.vrExperienceHelper.js.map
 
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * WebXR Camera which holds the views for the xrSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    var WebXRCamera = /** @class */ (function (_super) {
+        __extends(WebXRCamera, _super);
+        /**
+         * Creates a new webXRCamera, this should only be set at the camera after it has been updated by the xrSessionManager
+         * @param name the name of the camera
+         * @param scene the scene to add the camera to
+         */
+        function WebXRCamera(name, scene) {
+            var _this = _super.call(this, name, BABYLON.Vector3.Zero(), scene) || this;
+            // Initial camera configuration
+            _this.minZ = 0;
+            _this.rotationQuaternion = new BABYLON.Quaternion();
+            _this.cameraRigMode = BABYLON.Camera.RIG_MODE_CUSTOM;
+            _this._updateNumberOfRigCameras(1);
+            return _this;
+        }
+        WebXRCamera.prototype._updateNumberOfRigCameras = function (viewCount) {
+            if (viewCount === void 0) { viewCount = 1; }
+            while (this.rigCameras.length < viewCount) {
+                var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
+                newCamera.minZ = 0;
+                newCamera.parent = this;
+                this.rigCameras.push(newCamera);
+            }
+            while (this.rigCameras.length > viewCount) {
+                var removedCamera = this.rigCameras.pop();
+                if (removedCamera) {
+                    removedCamera.dispose();
+                }
+            }
+        };
+        /** @hidden */
+        WebXRCamera.prototype._updateForDualEyeDebugging = function (pupilDistance) {
+            if (pupilDistance === void 0) { pupilDistance = 0.01; }
+            // Create initial camera rigs
+            this._updateNumberOfRigCameras(2);
+            this.rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
+            this.rigCameras[0].position.x = -pupilDistance / 2;
+            this.rigCameras[0].customDefaultRenderTarget = null;
+            this.rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
+            this.rigCameras[1].position.x = pupilDistance / 2;
+            this.rigCameras[1].customDefaultRenderTarget = null;
+        };
+        return WebXRCamera;
+    }(BABYLON.FreeCamera));
+    BABYLON.WebXRCamera = WebXRCamera;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.webXRCamera.js.map
+
 // Mainly based on these 2 articles :
 // Creating an universal virtual touch joystick working for all Touch models thanks to Hand.JS : http://blogs.msdn.com/b/davrous/archive/2013/02/22/creating-an-universal-virtual-touch-joystick-working-for-all-touch-models-thanks-to-hand-js.aspx
 // & on Seb Lee-Delisle original work: http://seb.ly/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/

+ 216 - 113
dist/preview release/babylon.no-module.max.js

@@ -12239,6 +12239,10 @@ var BABYLON;
              */
             this.onBeginFrameObservable = new BABYLON.Observable();
             /**
+             * If set, will be used to request the next animation frame for the render loop
+             */
+            this.customAnimationFrameRequester = null;
+            /**
              * Observable raised when the engine ends the current frame
              */
             this.onEndFrameObservable = new BABYLON.Observable();
@@ -13401,11 +13405,16 @@ var BABYLON;
             }
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = BABYLON.Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                }
+                else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                }
+                else {
+                    this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = BABYLON.Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             }
             else {
                 this._renderingQueueLaunched = false;
@@ -19175,7 +19184,7 @@ var BABYLON;
             this.minimum.copyFrom(min);
             this.maximum.copyFrom(max);
             var distance = BABYLON.Vector3.Distance(min, max);
-            BABYLON.Vector3.LerpToRef(min, max, 0.5, this.center);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
             this.radius = distance * 0.5;
             this._update(worldMatrix || _identityMatrix);
         };
@@ -19186,8 +19195,8 @@ var BABYLON;
          */
         BoundingSphere.prototype.scale = function (factor) {
             var newRadius = this.radius * factor;
-            var tmpVectors = BABYLON.Tmp.Vector3;
-            var tempRadiusVector = tmpVectors[0].copyFromFloats(newRadius, newRadius, newRadius);
+            var tmpVectors = BoundingSphere.TmpVector3;
+            var tempRadiusVector = tmpVectors[0].setAll(newRadius);
             var min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
             var max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
             this.reConstruct(min, max);
@@ -19197,7 +19206,7 @@ var BABYLON;
         /** @hidden */
         BoundingSphere.prototype._update = function (world) {
             BABYLON.Vector3.TransformCoordinatesToRef(this.center, world, this.centerWorld);
-            var tempVector = BABYLON.Tmp.Vector3[0];
+            var tempVector = BoundingSphere.TmpVector3[0];
             BABYLON.Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, world, tempVector);
             this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
         };
@@ -19220,11 +19229,8 @@ var BABYLON;
          * @returns true if the point is inside the bounding sphere
          */
         BoundingSphere.prototype.intersectsPoint = function (point) {
-            var x = this.centerWorld.x - point.x;
-            var y = this.centerWorld.y - point.y;
-            var z = this.centerWorld.z - point.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (this.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(this.centerWorld, point);
+            if (this.radiusWorld * this.radiusWorld < squareDistance) {
                 return false;
             }
             return true;
@@ -19237,15 +19243,14 @@ var BABYLON;
          * @returns true if the speres intersect
          */
         BoundingSphere.Intersects = function (sphere0, sphere1) {
-            var x = sphere0.centerWorld.x - sphere1.centerWorld.x;
-            var y = sphere0.centerWorld.y - sphere1.centerWorld.y;
-            var z = sphere0.centerWorld.z - sphere1.centerWorld.z;
-            var distance = Math.sqrt((x * x) + (y * y) + (z * z));
-            if (sphere0.radiusWorld + sphere1.radiusWorld < distance) {
+            var squareDistance = BABYLON.Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
+            var radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
+            if (radiusSum * radiusSum < squareDistance) {
                 return false;
             }
             return true;
         };
+        BoundingSphere.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingSphere;
     }());
     BABYLON.BoundingSphere = BoundingSphere;
@@ -19333,8 +19338,8 @@ var BABYLON;
             vectors[6].copyFromFloats(minX, maxY, maxZ);
             vectors[7].copyFromFloats(maxX, minY, maxZ);
             // OBB
-            this.maximum.addToRef(min, this.center).scaleInPlace(0.5);
-            this.maximum.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.addToRef(min, this.center).scaleInPlace(0.5);
+            max.subtractToRef(min, this.extendSize).scaleInPlace(0.5);
             this._update(worldMatrix || this._worldMatrix || BABYLON.Matrix.Identity());
         };
         /**
@@ -19343,7 +19348,7 @@ var BABYLON;
          * @returns the current bounding box
          */
         BoundingBox.prototype.scale = function (factor) {
-            var tmpVectors = BABYLON.Tmp.Vector3;
+            var tmpVectors = BoundingBox.TmpVector3;
             var diff = this.maximum.subtractToRef(this.minimum, tmpVectors[0]);
             var len = diff.length();
             diff.normalizeFromLength(len);
@@ -19524,6 +19529,7 @@ var BABYLON;
             }
             return true;
         };
+        BoundingBox.TmpVector3 = BABYLON.Tools.BuildArray(3, BABYLON.Vector3.Zero);
         return BoundingBox;
     }());
     BABYLON.BoundingBox = BoundingBox;
@@ -19833,6 +19839,8 @@ var BABYLON;
             _this._pivotMatrix = BABYLON.Matrix.Identity();
             _this._postMultiplyPivotMatrix = false;
             _this._isWorldMatrixFrozen = false;
+            /** @hidden */
+            _this._indexInSceneTransformNodesArray = -1;
             /**
             * An event triggered after the world matrix is updated
             */
@@ -19904,8 +19912,8 @@ var BABYLON;
             set: function (quaternion) {
                 this._rotationQuaternion = quaternion;
                 //reset the rotation vector.
-                if (quaternion && this.rotation.length()) {
-                    this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+                if (quaternion) {
+                    this.rotation.setAll(0.0);
                 }
             },
             enumerable: true,
@@ -20037,7 +20045,7 @@ var BABYLON;
         */
         TransformNode.prototype.setPivotMatrix = function (matrix, postMultiplyPivotMatrix) {
             if (postMultiplyPivotMatrix === void 0) { postMultiplyPivotMatrix = true; }
-            this._pivotMatrix = matrix.clone();
+            this._pivotMatrix.copyFrom(matrix);
             this._cache.pivotMatrixUpdated = true;
             this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
             if (this._postMultiplyPivotMatrix) {
@@ -20121,10 +20129,9 @@ var BABYLON;
                 absolutePositionZ = absolutePosition.z;
             }
             if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new BABYLON.Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = BABYLON.Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+                var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
+                BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(absolutePositionX, absolutePositionY, absolutePositionZ, invertParentWorldMatrix, this.position);
             }
             else {
                 this.position.x = absolutePositionX;
@@ -20149,8 +20156,8 @@ var BABYLON;
          */
         TransformNode.prototype.getPositionExpressedInLocalSpace = function () {
             this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
+            var invLocalWorldMatrix = BABYLON.Tmp.Matrix[0];
+            this._localWorld.invertToRef(invLocalWorldMatrix);
             return BABYLON.Vector3.TransformNormal(this.position, invLocalWorldMatrix);
         };
         /**
@@ -20287,52 +20294,33 @@ var BABYLON;
             if (!node && !this.parent) {
                 return this;
             }
+            var quatRotation = BABYLON.Tmp.Quaternion[0];
+            var position = BABYLON.Tmp.Vector3[0];
+            var scale = BABYLON.Tmp.Vector3[1];
             if (!node) {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 if (this.parent && this.parent.computeWorldMatrix) {
                     this.parent.computeWorldMatrix(true);
                 }
                 this.computeWorldMatrix(true);
-                this.getWorldMatrix().decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
+                this.getWorldMatrix().decompose(scale, quatRotation, position);
             }
             else {
-                var rotation = BABYLON.Tmp.Quaternion[0];
-                var position = BABYLON.Tmp.Vector3[0];
-                var scale = BABYLON.Tmp.Vector3[1];
                 var diffMatrix = BABYLON.Tmp.Matrix[0];
                 var invParentMatrix = BABYLON.Tmp.Matrix[1];
                 this.computeWorldMatrix(true);
                 node.computeWorldMatrix(true);
                 node.getWorldMatrix().invertToRef(invParentMatrix);
                 this.getWorldMatrix().multiplyToRef(invParentMatrix, diffMatrix);
-                diffMatrix.decompose(scale, rotation, position);
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                }
-                else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-                this.scaling.x = scale.x;
-                this.scaling.y = scale.y;
-                this.scaling.z = scale.z;
+                diffMatrix.decompose(scale, quatRotation, position);
+            }
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.copyFrom(quatRotation);
             }
+            else {
+                quatRotation.toEulerAnglesToRef(this.rotation);
+            }
+            this.scaling.copyFrom(scale);
+            this.position.copyFrom(position);
             this.parent = node;
             return this;
         };
@@ -20396,8 +20384,8 @@ var BABYLON;
         TransformNode.prototype.rotate = function (axis, amount, space) {
             axis.normalize();
             if (!this.rotationQuaternion) {
-                this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation = BABYLON.Vector3.Zero();
+                this.rotationQuaternion = this.rotation.toQuaternion();
+                this.rotation.setAll(0);
             }
             var rotationQuaternion;
             if (!space || space === BABYLON.Space.LOCAL) {
@@ -20406,8 +20394,8 @@ var BABYLON;
             }
             else {
                 if (this.parent) {
-                    var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                    invertParentWorldMatrix.invert();
+                    var invertParentWorldMatrix = BABYLON.Tmp.Matrix[0];
+                    this.parent.getWorldMatrix().invertToRef(invertParentWorldMatrix);
                     axis = BABYLON.Vector3.TransformNormal(axis, invertParentWorldMatrix);
                 }
                 rotationQuaternion = BABYLON.Quaternion.RotationAxisToRef(axis, amount, TransformNode._rotationAxisCache);
@@ -20429,17 +20417,25 @@ var BABYLON;
             axis.normalize();
             if (!this.rotationQuaternion) {
                 this.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
-                this.rotation.copyFromFloats(0, 0, 0);
-            }
-            point.subtractToRef(this.position, BABYLON.Tmp.Vector3[0]);
-            BABYLON.Matrix.TranslationToRef(BABYLON.Tmp.Vector3[0].x, BABYLON.Tmp.Vector3[0].y, BABYLON.Tmp.Vector3[0].z, BABYLON.Tmp.Matrix[0]);
-            BABYLON.Tmp.Matrix[0].invertToRef(BABYLON.Tmp.Matrix[2]);
-            BABYLON.Matrix.RotationAxisToRef(axis, amount, BABYLON.Tmp.Matrix[1]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[1], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].multiplyToRef(BABYLON.Tmp.Matrix[0], BABYLON.Tmp.Matrix[2]);
-            BABYLON.Tmp.Matrix[2].decompose(BABYLON.Tmp.Vector3[0], BABYLON.Tmp.Quaternion[0], BABYLON.Tmp.Vector3[1]);
-            this.position.addInPlace(BABYLON.Tmp.Vector3[1]);
-            BABYLON.Tmp.Quaternion[0].multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                this.rotation.setAll(0);
+            }
+            var tmpVector = BABYLON.Tmp.Vector3[0];
+            var finalScale = BABYLON.Tmp.Vector3[1];
+            var finalTranslation = BABYLON.Tmp.Vector3[2];
+            var finalRotation = BABYLON.Tmp.Quaternion[0];
+            var translationMatrix = BABYLON.Tmp.Matrix[0]; // T
+            var translationMatrixInv = BABYLON.Tmp.Matrix[1]; // T'
+            var rotationMatrix = BABYLON.Tmp.Matrix[2]; // R
+            var finalMatrix = BABYLON.Tmp.Matrix[3]; // T' x R x T
+            point.subtractToRef(this.position, tmpVector);
+            BABYLON.Matrix.TranslationToRef(tmpVector.x, tmpVector.y, tmpVector.z, translationMatrix); // T
+            BABYLON.Matrix.TranslationToRef(-tmpVector.x, -tmpVector.y, -tmpVector.z, translationMatrixInv); // T'
+            BABYLON.Matrix.RotationAxisToRef(axis, amount, rotationMatrix); // R
+            translationMatrixInv.multiplyToRef(rotationMatrix, finalMatrix); // T' x R
+            finalMatrix.multiplyToRef(translationMatrix, finalMatrix); // T' x R x T
+            finalMatrix.decompose(finalScale, finalRotation, finalTranslation);
+            this.position.addInPlace(finalTranslation);
+            finalRotation.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
             return this;
         };
         /**
@@ -23436,6 +23432,10 @@ var BABYLON;
              */
             _this.customRenderTargets = new Array();
             /**
+             * When set, the camera will render to this render target instead of the default canvas
+             */
+            _this.customDefaultRenderTarget = null;
+            /**
              * Observable triggered when the camera view matrix has changed.
              */
             _this.onViewMatrixChangedObservable = new BABYLON.Observable();
@@ -24346,6 +24346,10 @@ var BABYLON;
          */
         Camera.RIG_MODE_WEBVR = 21;
         /**
+         * Custom rig mode allowing rig cameras to be populated manually with any number of cameras
+         */
+        Camera.RIG_MODE_CUSTOM = 22;
+        /**
          * Defines if by default attaching controls should prevent the default javascript event to continue.
          */
         Camera.ForceAttachControlToAlwaysPreventDefault = false;
@@ -25171,6 +25175,9 @@ var BABYLON;
             this.geometries = new Array();
             /**
             * All of the tranform nodes added to this scene
+            * In the context a the Scene, it is not supposed to be modified manually.
+            * Any addition or removal should be done using the addTransformNode and removeTransformNode Scene methods.
+            * Note also that the order of the TransformNode wihin the array is not significant and might change.
             * @see http://doc.babylonjs.com/how_to/transformnode
             */
             this.transformNodes = new Array();
@@ -25371,6 +25378,11 @@ var BABYLON;
              * in order to block unwanted artifacts like system double clicks
              */
             _this.preventDefaultOnPointerDown = true;
+            /**
+             * This is used to call preventDefault() on pointer up
+             * in order to block unwanted artifacts like system double clicks
+             */
+            _this.preventDefaultOnPointerUp = true;
             // Metadata
             /**
              * Gets or sets user defined metadata
@@ -26885,6 +26897,7 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
+                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -26905,6 +26918,7 @@ var BABYLON;
                             if (Date.now() - _this._previousStartingPointerTime > Scene.DoubleClickDelay ||
                                 btn !== _this._previousButtonPressed) {
                                 clickInfo.singleClick = true;
+                                eventRaised = true;
                                 cb(clickInfo, _this._currentPickResult);
                             }
                         }
@@ -26970,8 +26984,10 @@ var BABYLON;
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, _this._currentPickResult);
+                if (!eventRaised) {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, _this._currentPickResult);
+                }
             };
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
@@ -27027,6 +27043,10 @@ var BABYLON;
                 _this._pickedUpMesh = null;
                 _this._meshPickProceed = false;
                 _this._updatePointerPosition(evt);
+                if (_this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
                 _this._initClickEvent(_this.onPrePointerObservable, _this.onPointerObservable, evt, function (clickInfo, pickResult) {
                     // PreObservable support
                     if (_this.onPrePointerObservable.hasObservers()) {
@@ -27875,6 +27895,7 @@ var BABYLON;
          * @param newTransformNode defines the transform node to add
          */
         Scene.prototype.addTransformNode = function (newTransformNode) {
+            newTransformNode._indexInSceneTransformNodesArray = this.transformNodes.length;
             this.transformNodes.push(newTransformNode);
             this.onNewTransformNodeAddedObservable.notifyObservers(newTransformNode);
         };
@@ -27884,10 +27905,15 @@ var BABYLON;
          * @returns the index where the transform node was in the transform node list
          */
         Scene.prototype.removeTransformNode = function (toRemove) {
-            var index = this.transformNodes.indexOf(toRemove);
+            var index = toRemove._indexInSceneTransformNodesArray;
             if (index !== -1) {
-                // Remove from the scene if found
-                this.transformNodes.splice(index, 1);
+                if (index !== this.transformNodes.length - 1) {
+                    var lastNode = this.transformNodes[this.transformNodes.length - 1];
+                    this.transformNodes[index] = lastNode;
+                    lastNode._indexInSceneTransformNodesArray = index;
+                }
+                toRemove._indexInSceneTransformNodesArray = -1;
+                this.transformNodes.pop();
             }
             this.onTransformNodeRemovedObservable.notifyObservers(toRemove);
             return index;
@@ -28866,7 +28892,7 @@ var BABYLON;
                     continue;
                 }
                 mesh._preActivate();
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
                     mesh._activate(this._renderId);
@@ -28995,7 +29021,18 @@ var BABYLON;
                     step.action(this.activeCamera);
                 }
                 this._intermediateRendering = false;
-                engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                if (this.activeCamera.customDefaultRenderTarget) {
+                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                    if (internalTexture) {
+                        engine.bindFramebuffer(internalTexture);
+                    }
+                    else {
+                        BABYLON.Tools.Error("Camera contains invalid customDefaultRenderTarget");
+                    }
+                }
+                else {
+                    engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                }
             }
             this.onAfterRenderTargetsRenderObservable.notifyObservers(this);
             // Prepare Frame
@@ -32978,12 +33015,12 @@ var BABYLON;
             this.computeWorldMatrix();
             var mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var _i = 0, _a = this.subMeshes; _i < _a.length; _i++) {
                         var subMesh = _a[_i];
                         var effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -33660,7 +33697,7 @@ var BABYLON;
                 return this;
             }
             this._effectiveMaterial = material;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -33677,7 +33714,7 @@ var BABYLON;
                 step.action(this, subMesh, batch);
             }
             var effect;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             }
             else {
@@ -33703,7 +33740,7 @@ var BABYLON;
                 this._bind(subMesh, effect, fillMode);
             }
             var world = this.getWorldMatrix();
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             }
             else {
@@ -36345,9 +36382,9 @@ var BABYLON;
              */
             this.doNotSerialize = false;
             /**
-             * Specifies if the effect should be stored on sub meshes
+             * @hidden
              */
-            this.storeEffectOnSubMeshes = false;
+            this._storeEffectOnSubMeshes = false;
             /**
             * An event triggered when the material is disposed
             */
@@ -37033,7 +37070,7 @@ var BABYLON;
                 if (localOptions.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
-                if (_this.storeEffectOnSubMeshes) {
+                if (_this._storeEffectOnSubMeshes) {
                     if (_this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(_this);
@@ -37193,7 +37230,7 @@ var BABYLON;
                     mesh.material = null;
                     if (mesh.geometry) {
                         var geometry = (mesh.geometry);
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var _i = 0, _a = mesh.subMeshes; _i < _a.length; _i++) {
                                 var subMesh = _a[_i];
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
@@ -37211,7 +37248,7 @@ var BABYLON;
             this._uniformBuffer.dispose();
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
                 this._effect = null;
@@ -43191,7 +43228,7 @@ var BABYLON;
              * This is mostly used when shader parallel compilation is supported (true by default)
              */
             _this.allowShaderHotSwapping = true;
-            _this.storeEffectOnSubMeshes = true;
+            _this._storeEffectOnSubMeshes = true;
             return _this;
         }
         PushMaterial.prototype.getEffect = function () {
@@ -61810,10 +61847,10 @@ var BABYLON;
                 if (!this.isReady()) {
                     return;
                 }
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
             this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene.getAnimationRatio());
             // Determine the number of particles we need to create
@@ -67533,10 +67570,10 @@ var BABYLON;
                     }
                     this._preWarmDone = true;
                 }
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return 0;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
             // Get everything ready to render
             this._initialize();
@@ -68312,13 +68349,22 @@ var BABYLON;
             var index = 0;
             var idx = 0;
             var tmpNormal = BABYLON.Tmp.Vector3[0];
-            var rotMatrix = BABYLON.Tmp.Matrix[0];
-            var invertedRotMatrix = BABYLON.Tmp.Matrix[1];
+            var quaternion = BABYLON.Tmp.Quaternion[0];
+            var invertedRotMatrix = BABYLON.Tmp.Matrix[0];
             for (var p = 0; p < this.particles.length; p++) {
                 var particle = this.particles[p];
                 var shape = particle._model._shape;
-                particle.getRotationMatrix(rotMatrix);
-                rotMatrix.invertToRef(invertedRotMatrix);
+                // computing the inverse of the rotation matrix from the quaternion
+                // is equivalent to computing the matrix of the inverse quaternion, i.e of the conjugate quaternion
+                if (particle.rotationQuaternion) {
+                    particle.rotationQuaternion.conjugateToRef(quaternion);
+                }
+                else {
+                    var rotation = particle.rotation;
+                    BABYLON.Quaternion.RotationYawPitchRollToRef(rotation.y, rotation.x, rotation.z, quaternion);
+                    quaternion.conjugateInPlace();
+                }
+                quaternion.toRotationMatrix(invertedRotMatrix);
                 for (var pt = 0; pt < shape.length; pt++) {
                     idx = index + pt * 3;
                     BABYLON.Vector3.TransformNormalFromFloatsToRef(this._normals32[idx], this._normals32[idx + 1], this._normals32[idx + 2], invertedRotMatrix, tmpNormal);
@@ -80167,7 +80213,7 @@ var BABYLON;
             var _this = _super.call(this, name, scene, true) || this;
             scene.multiMaterials.push(_this);
             _this.subMaterials = new Array();
-            _this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            _this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
             return _this;
         }
         Object.defineProperty(MultiMaterial.prototype, "subMaterials", {
@@ -80249,7 +80295,7 @@ var BABYLON;
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }
@@ -91751,7 +91797,7 @@ var BABYLON;
      * The Motion Blur Post Process which blurs an image based on the objects velocity in scene.
      * Velocity can be affected by each object's rotation, position and scale depending on the transformation speed.
      * As an example, all you have to do is to create the post-process:
-     *  var mb = new BABYLON.MotionBlurProcess(
+     *  var mb = new BABYLON.MotionBlurPostProcess(
      *      'mb', // The name of the effect.
      *      scene, // The scene containing the objects to blur according to their velocity.
      *      1.0, // The required width/height ratio to downsize to before computing the render pass.
@@ -91759,8 +91805,8 @@ var BABYLON;
      * );
      * Then, all objects moving, rotating and/or scaling will be blurred depending on the transformation speed.
      */
-    var MotionBlurProcess = /** @class */ (function (_super) {
-        __extends(MotionBlurProcess, _super);
+    var MotionBlurPostProcess = /** @class */ (function (_super) {
+        __extends(MotionBlurPostProcess, _super);
         /**
          * Creates a new instance MotionBlurPostProcess
          * @param name The name of the effect.
@@ -91773,7 +91819,7 @@ var BABYLON;
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        function MotionBlurProcess(name, scene, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
+        function MotionBlurPostProcess(name, scene, options, camera, samplingMode, engine, reusable, textureType, blockCompilation) {
             if (textureType === void 0) { textureType = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (blockCompilation === void 0) { blockCompilation = false; }
             var _this = _super.call(this, name, "motionBlur", ["motionStrength", "motionScale", "screenSize"], ["velocitySampler"], options, camera, samplingMode, engine, reusable, "#define SAMPLES 64.0", textureType, undefined, null, blockCompilation) || this;
@@ -91802,7 +91848,7 @@ var BABYLON;
             };
             return _this;
         }
-        Object.defineProperty(MotionBlurProcess.prototype, "motionBlurSamples", {
+        Object.defineProperty(MotionBlurPostProcess.prototype, "motionBlurSamples", {
             /**
              * Gets the number of iterations are used for motion blur quality. Default value is equal to 32
              */
@@ -91823,16 +91869,16 @@ var BABYLON;
          * Disposes the post process.
          * @param camera The camera to dispose the post process on.
          */
-        MotionBlurProcess.prototype.dispose = function (camera) {
+        MotionBlurPostProcess.prototype.dispose = function (camera) {
             if (this._geometryBufferRenderer) {
                 // Clear previous transformation matrices dictionary used to compute objects velocities
                 this._geometryBufferRenderer._previousTransformationMatrices = {};
             }
             _super.prototype.dispose.call(this, camera);
         };
-        return MotionBlurProcess;
+        return MotionBlurPostProcess;
     }(BABYLON.PostProcess));
-    BABYLON.MotionBlurProcess = MotionBlurProcess;
+    BABYLON.MotionBlurPostProcess = MotionBlurPostProcess;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=babylon.motionBlurPostProcess.js.map
@@ -108150,6 +108196,63 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.vrExperienceHelper.js.map
 
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * WebXR Camera which holds the views for the xrSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    var WebXRCamera = /** @class */ (function (_super) {
+        __extends(WebXRCamera, _super);
+        /**
+         * Creates a new webXRCamera, this should only be set at the camera after it has been updated by the xrSessionManager
+         * @param name the name of the camera
+         * @param scene the scene to add the camera to
+         */
+        function WebXRCamera(name, scene) {
+            var _this = _super.call(this, name, BABYLON.Vector3.Zero(), scene) || this;
+            // Initial camera configuration
+            _this.minZ = 0;
+            _this.rotationQuaternion = new BABYLON.Quaternion();
+            _this.cameraRigMode = BABYLON.Camera.RIG_MODE_CUSTOM;
+            _this._updateNumberOfRigCameras(1);
+            return _this;
+        }
+        WebXRCamera.prototype._updateNumberOfRigCameras = function (viewCount) {
+            if (viewCount === void 0) { viewCount = 1; }
+            while (this.rigCameras.length < viewCount) {
+                var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
+                newCamera.minZ = 0;
+                newCamera.parent = this;
+                this.rigCameras.push(newCamera);
+            }
+            while (this.rigCameras.length > viewCount) {
+                var removedCamera = this.rigCameras.pop();
+                if (removedCamera) {
+                    removedCamera.dispose();
+                }
+            }
+        };
+        /** @hidden */
+        WebXRCamera.prototype._updateForDualEyeDebugging = function (pupilDistance) {
+            if (pupilDistance === void 0) { pupilDistance = 0.01; }
+            // Create initial camera rigs
+            this._updateNumberOfRigCameras(2);
+            this.rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
+            this.rigCameras[0].position.x = -pupilDistance / 2;
+            this.rigCameras[0].customDefaultRenderTarget = null;
+            this.rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
+            this.rigCameras[1].position.x = pupilDistance / 2;
+            this.rigCameras[1].customDefaultRenderTarget = null;
+        };
+        return WebXRCamera;
+    }(BABYLON.FreeCamera));
+    BABYLON.WebXRCamera = WebXRCamera;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.webXRCamera.js.map
+
 // Mainly based on these 2 articles :
 // Creating an universal virtual touch joystick working for all Touch models thanks to Hand.JS : http://blogs.msdn.com/b/davrous/archive/2013/02/22/creating-an-universal-virtual-touch-joystick-working-for-all-touch-models-thanks-to-hand-js.aspx
 // & on Seb Lee-Delisle original work: http://seb.ly/2011/04/multi-touch-game-controller-in-javascripthtml5-for-ipad/

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/babylon.worker.js


文件差異過大導致無法顯示
+ 218 - 115
dist/preview release/es6.js


+ 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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -849,6 +849,8 @@ declare module BABYLON.GUI {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


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

@@ -952,6 +952,8 @@ declare module 'babylonjs-gui/2D/controls/control' {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */
@@ -3676,6 +3678,8 @@ declare module BABYLON.GUI {
             isPointerBlocker: boolean;
             /** Gets or sets a boolean indicating if the control can be focusable */
             isFocusInvisible: boolean;
+            /** Gets or sets a boolean indicating if the children are clipped to the current control bounds */
+            clipChildren: boolean;
             /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
             shadowOffsetX: number;
             /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */

+ 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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "3.3.0"
+        "babylonjs": "4.0.0-alpha.0"
     },
     "engines": {
         "node": "*"

文件差異過大導致無法顯示
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,10 +28,10 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "3.3.0",
-        "babylonjs-gui": "3.3.0",
-        "babylonjs-loaders": "3.3.0",
-        "babylonjs-serializers": "3.3.0"
+        "babylonjs": "4.0.0-alpha.0",
+        "babylonjs-gui": "4.0.0-alpha.0",
+        "babylonjs-loaders": "4.0.0-alpha.0",
+        "babylonjs-serializers": "4.0.0-alpha.0"
     },
     "engines": {
         "node": "*"

+ 2 - 2
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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.3.0"
+        "babylonjs-gltf2interface": "4.0.0-alpha.0"
     },
     "peerDependencies": {
         "babylonjs": ">=3.3.0-rc.4"

+ 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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "3.3.0"
+        "babylonjs": "4.0.0-alpha.0"
     },
     "engines": {
         "node": "*"

+ 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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "3.3.0"
+        "babylonjs": "4.0.0-alpha.0"
     },
     "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": "3.3.0",
+    "version": "4.0.0-alpha.0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "3.3.0"
+        "babylonjs": "4.0.0-alpha.0"
     },
     "engines": {
         "node": "*"

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

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

+ 459 - 0
dist/preview release/viewer/babylon.viewer.d.ts

@@ -1728,6 +1728,465 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    export interface ICameraConfiguration {
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        rotation?: {
+            x: number;
+            y: number;
+            z: number;
+            w: number;
+        };
+        fov?: number;
+        fovMode?: number;
+        minZ?: number;
+        maxZ?: number;
+        inertia?: number;
+        exposure?: number;
+        pinchPrecision?: number;
+        behaviors?: {
+            [name: string]: boolean | number | ICameraBehaviorConfiguration;
+        };
+        disableCameraControl?: boolean;
+        disableCtrlForPanning?: boolean;
+        disableAutoFocus?: boolean;
+        [propName: string]: any;
+    }
+    export interface ICameraBehaviorConfiguration {
+        type: number;
+        [propName: string]: any;
+    }
+}
+declare module BabylonViewer {
+    /**
+        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
+        */
+    export interface IColorGradingConfiguration {
+            /**
+                * Transform data string, encoded as determined by transformDataFormat.
+                */
+            transformData: string;
+            /**
+                * The encoding format of TransformData (currently only raw-base16 is supported).
+                */
+            transformDataFormat: string;
+            /**
+                * The weight of the transform
+                */
+            transformWeight: number;
+            /**
+                * Color curve colorFilterHueGlobal value
+                */
+            colorFilterHueGlobal: number;
+            /**
+                * Color curve colorFilterHueShadows value
+                */
+            colorFilterHueShadows: number;
+            /**
+                * Color curve colorFilterHueMidtones value
+                */
+            colorFilterHueMidtones: number;
+            /**
+                * Color curve colorFilterHueHighlights value
+                */
+            colorFilterHueHighlights: number;
+            /**
+                * Color curve colorFilterDensityGlobal value
+                */
+            colorFilterDensityGlobal: number;
+            /**
+                * Color curve colorFilterDensityShadows value
+                */
+            colorFilterDensityShadows: number;
+            /**
+                * Color curve colorFilterDensityMidtones value
+                */
+            colorFilterDensityMidtones: number;
+            /**
+                * Color curve colorFilterDensityHighlights value
+                */
+            colorFilterDensityHighlights: number;
+            /**
+                * Color curve saturationGlobal value
+                */
+            saturationGlobal: number;
+            /**
+                * Color curve saturationShadows value
+                */
+            saturationShadows: number;
+            /**
+                * Color curve saturationMidtones value
+                */
+            saturationMidtones: number;
+            /**
+                * Color curve saturationHighlights value
+                */
+            saturationHighlights: number;
+            /**
+                * Color curve exposureGlobal value
+                */
+            exposureGlobal: number;
+            /**
+                * Color curve exposureShadows value
+                */
+            exposureShadows: number;
+            /**
+                * Color curve exposureMidtones value
+                */
+            exposureMidtones: number;
+            /**
+                * Color curve exposureHighlights value
+                */
+            exposureHighlights: number;
+    }
+}
+declare module BabylonViewer {
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: BABYLON.DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
+}
+declare module BabylonViewer {
+    export interface IGroundConfiguration {
+        size?: number;
+        receiveShadows?: boolean;
+        shadowLevel?: number;
+        shadowOnly?: boolean;
+        mirror?: boolean | {
+            sizeRatio?: number;
+            blurKernel?: number;
+            amount?: number;
+            fresnelWeight?: number;
+            fallOffDistance?: number;
+            textureType?: number;
+        };
+        texture?: string;
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        opacity?: number;
+        material?: {
+            [propName: string]: any;
+        };
+    }
+}
+declare module BabylonViewer {
+    export interface IImageProcessingConfiguration {
+        colorGradingEnabled?: boolean;
+        colorCurvesEnabled?: boolean;
+        colorCurves?: {
+            globalHue?: number;
+            globalDensity?: number;
+            globalSaturation?: number;
+            globalExposure?: number;
+            highlightsHue?: number;
+            highlightsDensity?: number;
+            highlightsSaturation?: number;
+            highlightsExposure?: number;
+            midtonesHue?: number;
+            midtonesDensity?: number;
+            midtonesSaturation?: number;
+            midtonesExposure?: number;
+            shadowsHue?: number;
+            shadowsDensity?: number;
+            shadowsSaturation?: number;
+            shadowsExposure?: number;
+        };
+        colorGradingWithGreenDepth?: boolean;
+        colorGradingBGR?: boolean;
+        exposure?: number;
+        toneMappingEnabled?: boolean;
+        contrast?: number;
+        vignetteEnabled?: boolean;
+        vignetteStretch?: number;
+        vignetteCentreX?: number;
+        vignetteCentreY?: number;
+        vignetteWeight?: number;
+        vignetteColor?: {
+            r: number;
+            g: number;
+            b: number;
+            a?: number;
+        };
+        vignetteCameraFov?: number;
+        vignetteBlendMode?: number;
+        vignetteM?: boolean;
+        applyByPostProcess?: boolean;
+        isEnabled?: boolean;
+    }
+}
+declare module BabylonViewer {
+    export interface ILightConfiguration {
+        type: number;
+        name?: string;
+        disabled?: boolean;
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        target?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        direction?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        diffuse?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        specular?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        intensity?: number;
+        intensityMode?: number;
+        radius?: number;
+        shadownEnabled?: boolean;
+        shadowConfig?: {
+            useBlurExponentialShadowMap?: boolean;
+            useBlurCloseExponentialShadowMap?: boolean;
+            useKernelBlur?: boolean;
+            blurKernel?: number;
+            blurScale?: number;
+            minZ?: number;
+            maxZ?: number;
+            frustumSize?: number;
+            angleScale?: number;
+            frustumEdgeFalloff?: number;
+            [propName: string]: any;
+        };
+        spotAngle?: number;
+        shadowFieldOfView?: number;
+        shadowBufferSize?: number;
+        shadowFrustumSize?: number;
+        shadowMinZ?: number;
+        shadowMaxZ?: number;
+        [propName: string]: any;
+        behaviors?: {
+            [name: string]: number | {
+                type: number;
+                [propName: string]: any;
+            };
+        };
+    }
+}
+declare module BabylonViewer {
+    export interface IObserversConfiguration {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
+}
+declare module BabylonViewer {
+    export interface ISceneConfiguration {
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | BABYLON.IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
+    }
+}
+declare module BabylonViewer {
+    export interface ISceneOptimizerConfiguration {
+        targetFrameRate?: number;
+        trackerDuration?: number;
+        autoGeneratePriorities?: boolean;
+        improvementMode?: boolean;
+        degradation?: string;
+        types?: {
+            texture?: ISceneOptimizerParameters;
+            hardwareScaling?: ISceneOptimizerParameters;
+            shadow?: ISceneOptimizerParameters;
+            postProcess?: ISceneOptimizerParameters;
+            lensFlare?: ISceneOptimizerParameters;
+            particles?: ISceneOptimizerParameters;
+            renderTarget?: ISceneOptimizerParameters;
+            mergeMeshes?: ISceneOptimizerParameters;
+        };
+        custom?: string;
+    }
+    export interface ISceneOptimizerParameters {
+        priority?: number;
+        maximumSize?: number;
+        step?: number;
+    }
+}
+declare module BabylonViewer {
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
+}
+declare module BabylonViewer {
+    /**
+        * A single template configuration object
+        */
+    export interface ITemplateConfiguration {
+            /**
+                * can be either the id of the template's html element or a URL.
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            location?: string;
+            /**
+                * If no location is provided you can provide here the raw html of this template.
+                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            html?: string;
+            id?: string;
+            /**
+                * Parameters that will be delivered to the template and will render it accordingly.
+                */
+            params?: {
+                    [key: string]: string | number | boolean | object;
+            };
+            /**
+                * Events to attach to this template.
+                * event name is the key. the value can either be a boolean (attach to the parent element)
+                * or a map of html id elements.
+                *
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
+                */
+            events?: {
+                    pointerdown?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerup?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointermove?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerover?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerout?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerenter?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerleave?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointercancel?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    click?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    dragstart?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    drop?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    [key: string]: boolean | {
+                            [id: string]: boolean;
+                    } | undefined;
+            };
+    }
+}
+declare module BabylonViewer {
+    export interface IVRConfiguration {
+        disabled?: boolean;
+        objectScaleFactor?: number;
+        disableInteractions?: boolean;
+        disableTeleportation?: boolean;
+        overrideFloorMeshName?: string;
+        vrOptions?: BABYLON.VRExperienceHelperOptions;
+        modelHeightCorrection?: number | boolean;
+        rotateUsingControllers?: boolean;
+        cameraPosition?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+    }
+}
+declare module BabylonViewer {
     /**
         * Spherical polynomial coefficients (counter part to spherical harmonic coefficients used in shader irradiance calculation)
         * @ignoreChildren

文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


文件差異過大導致無法顯示
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 492 - 1
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1663,7 +1663,21 @@ declare module 'babylonjs-viewer/loader/plugins' {
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces' {
-    
+    export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/groundConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/lightConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/modelAnimationConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/modelConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/observersConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/sceneConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/templateConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/vrConfiguration';
+    export * from 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration';
 }
 
 declare module 'babylonjs-viewer/configuration/interfaces/environmentMapConfiguration' {
@@ -1857,6 +1871,483 @@ declare module 'babylonjs-viewer/loader/plugins/extendedMaterialLoaderPlugin' {
     }
 }
 
+declare module 'babylonjs-viewer/configuration/interfaces/cameraConfiguration' {
+    export interface ICameraConfiguration {
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        rotation?: {
+            x: number;
+            y: number;
+            z: number;
+            w: number;
+        };
+        fov?: number;
+        fovMode?: number;
+        minZ?: number;
+        maxZ?: number;
+        inertia?: number;
+        exposure?: number;
+        pinchPrecision?: number;
+        behaviors?: {
+            [name: string]: boolean | number | ICameraBehaviorConfiguration;
+        };
+        disableCameraControl?: boolean;
+        disableCtrlForPanning?: boolean;
+        disableAutoFocus?: boolean;
+        [propName: string]: any;
+    }
+    export interface ICameraBehaviorConfiguration {
+        type: number;
+        [propName: string]: any;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration' {
+    /**
+        * The Color Grading Configuration groups the different settings used to define the color grading used in the viewer.
+        */
+    export interface IColorGradingConfiguration {
+            /**
+                * Transform data string, encoded as determined by transformDataFormat.
+                */
+            transformData: string;
+            /**
+                * The encoding format of TransformData (currently only raw-base16 is supported).
+                */
+            transformDataFormat: string;
+            /**
+                * The weight of the transform
+                */
+            transformWeight: number;
+            /**
+                * Color curve colorFilterHueGlobal value
+                */
+            colorFilterHueGlobal: number;
+            /**
+                * Color curve colorFilterHueShadows value
+                */
+            colorFilterHueShadows: number;
+            /**
+                * Color curve colorFilterHueMidtones value
+                */
+            colorFilterHueMidtones: number;
+            /**
+                * Color curve colorFilterHueHighlights value
+                */
+            colorFilterHueHighlights: number;
+            /**
+                * Color curve colorFilterDensityGlobal value
+                */
+            colorFilterDensityGlobal: number;
+            /**
+                * Color curve colorFilterDensityShadows value
+                */
+            colorFilterDensityShadows: number;
+            /**
+                * Color curve colorFilterDensityMidtones value
+                */
+            colorFilterDensityMidtones: number;
+            /**
+                * Color curve colorFilterDensityHighlights value
+                */
+            colorFilterDensityHighlights: number;
+            /**
+                * Color curve saturationGlobal value
+                */
+            saturationGlobal: number;
+            /**
+                * Color curve saturationShadows value
+                */
+            saturationShadows: number;
+            /**
+                * Color curve saturationMidtones value
+                */
+            saturationMidtones: number;
+            /**
+                * Color curve saturationHighlights value
+                */
+            saturationHighlights: number;
+            /**
+                * Color curve exposureGlobal value
+                */
+            exposureGlobal: number;
+            /**
+                * Color curve exposureShadows value
+                */
+            exposureShadows: number;
+            /**
+                * Color curve exposureMidtones value
+                */
+            exposureMidtones: number;
+            /**
+                * Color curve exposureHighlights value
+                */
+            exposureHighlights: number;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/defaultRenderingPipelineConfiguration' {
+    import { DepthOfFieldEffectBlurLevel } from 'babylonjs';
+    export interface IDefaultRenderingPipelineConfiguration {
+        sharpenEnabled?: boolean;
+        bloomEnabled?: boolean;
+        bloomThreshold?: number;
+        depthOfFieldEnabled?: boolean;
+        depthOfFieldBlurLevel?: DepthOfFieldEffectBlurLevel;
+        fxaaEnabled?: boolean;
+        imageProcessingEnabled?: boolean;
+        defaultPipelineTextureType?: number;
+        bloomScale?: number;
+        chromaticAberrationEnabled?: boolean;
+        grainEnabled?: boolean;
+        bloomKernel?: number;
+        hardwareScaleLevel?: number;
+        bloomWeight?: number;
+        hdr?: boolean;
+        samples?: number;
+        glowLayerEnabled?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/groundConfiguration' {
+    export interface IGroundConfiguration {
+        size?: number;
+        receiveShadows?: boolean;
+        shadowLevel?: number;
+        shadowOnly?: boolean;
+        mirror?: boolean | {
+            sizeRatio?: number;
+            blurKernel?: number;
+            amount?: number;
+            fresnelWeight?: number;
+            fallOffDistance?: number;
+            textureType?: number;
+        };
+        texture?: string;
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        opacity?: number;
+        material?: {
+            [propName: string]: any;
+        };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration' {
+    export interface IImageProcessingConfiguration {
+        colorGradingEnabled?: boolean;
+        colorCurvesEnabled?: boolean;
+        colorCurves?: {
+            globalHue?: number;
+            globalDensity?: number;
+            globalSaturation?: number;
+            globalExposure?: number;
+            highlightsHue?: number;
+            highlightsDensity?: number;
+            highlightsSaturation?: number;
+            highlightsExposure?: number;
+            midtonesHue?: number;
+            midtonesDensity?: number;
+            midtonesSaturation?: number;
+            midtonesExposure?: number;
+            shadowsHue?: number;
+            shadowsDensity?: number;
+            shadowsSaturation?: number;
+            shadowsExposure?: number;
+        };
+        colorGradingWithGreenDepth?: boolean;
+        colorGradingBGR?: boolean;
+        exposure?: number;
+        toneMappingEnabled?: boolean;
+        contrast?: number;
+        vignetteEnabled?: boolean;
+        vignetteStretch?: number;
+        vignetteCentreX?: number;
+        vignetteCentreY?: number;
+        vignetteWeight?: number;
+        vignetteColor?: {
+            r: number;
+            g: number;
+            b: number;
+            a?: number;
+        };
+        vignetteCameraFov?: number;
+        vignetteBlendMode?: number;
+        vignetteM?: boolean;
+        applyByPostProcess?: boolean;
+        isEnabled?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/lightConfiguration' {
+    export interface ILightConfiguration {
+        type: number;
+        name?: string;
+        disabled?: boolean;
+        position?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        target?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        direction?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+        diffuse?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        specular?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        intensity?: number;
+        intensityMode?: number;
+        radius?: number;
+        shadownEnabled?: boolean;
+        shadowConfig?: {
+            useBlurExponentialShadowMap?: boolean;
+            useBlurCloseExponentialShadowMap?: boolean;
+            useKernelBlur?: boolean;
+            blurKernel?: number;
+            blurScale?: number;
+            minZ?: number;
+            maxZ?: number;
+            frustumSize?: number;
+            angleScale?: number;
+            frustumEdgeFalloff?: number;
+            [propName: string]: any;
+        };
+        spotAngle?: number;
+        shadowFieldOfView?: number;
+        shadowBufferSize?: number;
+        shadowFrustumSize?: number;
+        shadowMinZ?: number;
+        shadowMaxZ?: number;
+        [propName: string]: any;
+        behaviors?: {
+            [name: string]: number | {
+                type: number;
+                [propName: string]: any;
+            };
+        };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/observersConfiguration' {
+    export interface IObserversConfiguration {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/sceneConfiguration' {
+    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
+    import { IColorGradingConfiguration } from "babylonjs-viewer/configuration/interfaces/colorGradingConfiguration";
+    import { IGlowLayerOptions } from "babylonjs";
+    export interface ISceneConfiguration {
+            debug?: boolean;
+            clearColor?: {
+                    r: number;
+                    g: number;
+                    b: number;
+                    a: number;
+            };
+            /** Deprecated, use environmentMap.mainColor instead. */
+            mainColor?: {
+                    r?: number;
+                    g?: number;
+                    b?: number;
+            };
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            environmentTexture?: string;
+            colorGrading?: IColorGradingConfiguration;
+            environmentRotationY?: number;
+            /**
+                * Deprecated, please use default rendering pipeline
+                */
+            glow?: boolean | IGlowLayerOptions;
+            disableHdr?: boolean;
+            renderInBackground?: boolean;
+            disableCameraControl?: boolean;
+            animationPropertiesOverride?: {
+                    [propName: string]: any;
+            };
+            defaultMaterial?: {
+                    materialType: "standard" | "pbr";
+                    [propName: string]: any;
+            };
+            flags?: {
+                    shadowsEnabled?: boolean;
+                    particlesEnabled?: boolean;
+                    collisionsEnabled?: boolean;
+                    lightsEnabled?: boolean;
+                    texturesEnabled?: boolean;
+                    lensFlaresEnabled?: boolean;
+                    proceduralTexturesEnabled?: boolean;
+                    renderTargetsEnabled?: boolean;
+                    spritesEnabled?: boolean;
+                    skeletonsEnabled?: boolean;
+                    audioEnabled?: boolean;
+            };
+            assetsRootURL?: string;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/sceneOptimizerConfiguration' {
+    export interface ISceneOptimizerConfiguration {
+        targetFrameRate?: number;
+        trackerDuration?: number;
+        autoGeneratePriorities?: boolean;
+        improvementMode?: boolean;
+        degradation?: string;
+        types?: {
+            texture?: ISceneOptimizerParameters;
+            hardwareScaling?: ISceneOptimizerParameters;
+            shadow?: ISceneOptimizerParameters;
+            postProcess?: ISceneOptimizerParameters;
+            lensFlare?: ISceneOptimizerParameters;
+            particles?: ISceneOptimizerParameters;
+            renderTarget?: ISceneOptimizerParameters;
+            mergeMeshes?: ISceneOptimizerParameters;
+        };
+        custom?: string;
+    }
+    export interface ISceneOptimizerParameters {
+        priority?: number;
+        maximumSize?: number;
+        step?: number;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/skyboxConfiguration' {
+    import { IImageProcessingConfiguration } from "babylonjs-viewer/configuration/interfaces/imageProcessingConfiguration";
+    export interface ISkyboxConfiguration {
+        cubeTexture?: {
+            noMipMap?: boolean;
+            gammaSpace?: boolean;
+            url?: string | Array<string>;
+        };
+        color?: {
+            r: number;
+            g: number;
+            b: number;
+        };
+        pbr?: boolean;
+        scale?: number;
+        blur?: number;
+        material?: {
+            imageProcessingConfiguration?: IImageProcessingConfiguration;
+            [propName: string]: any;
+        };
+        infiniteDistance?: boolean;
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/templateConfiguration' {
+    /**
+        * A single template configuration object
+        */
+    export interface ITemplateConfiguration {
+            /**
+                * can be either the id of the template's html element or a URL.
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            location?: string;
+            /**
+                * If no location is provided you can provide here the raw html of this template.
+                * See http://doc.babylonjs.com/extensions/the_templating_system#location-vs-html
+                */
+            html?: string;
+            id?: string;
+            /**
+                * Parameters that will be delivered to the template and will render it accordingly.
+                */
+            params?: {
+                    [key: string]: string | number | boolean | object;
+            };
+            /**
+                * Events to attach to this template.
+                * event name is the key. the value can either be a boolean (attach to the parent element)
+                * or a map of html id elements.
+                *
+                * See - http://doc.babylonjs.com/extensions/the_templating_system#event-binding
+                */
+            events?: {
+                    pointerdown?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerup?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointermove?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerover?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerout?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerenter?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointerleave?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    pointercancel?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    click?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    dragstart?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    drop?: boolean | {
+                            [id: string]: boolean;
+                    };
+                    [key: string]: boolean | {
+                            [id: string]: boolean;
+                    } | undefined;
+            };
+    }
+}
+
+declare module 'babylonjs-viewer/configuration/interfaces/vrConfiguration' {
+    import { VRExperienceHelperOptions } from "babylonjs";
+    export interface IVRConfiguration {
+        disabled?: boolean;
+        objectScaleFactor?: number;
+        disableInteractions?: boolean;
+        disableTeleportation?: boolean;
+        overrideFloorMeshName?: string;
+        vrOptions?: VRExperienceHelperOptions;
+        modelHeightCorrection?: number | boolean;
+        rotateUsingControllers?: boolean;
+        cameraPosition?: {
+            x: number;
+            y: number;
+            z: number;
+        };
+    }
+}
+
 declare module 'babylonjs-viewer/labs/environmentSerializer' {
     import { Vector3 } from "babylonjs";
     import { TextureCube } from 'babylonjs-viewer/labs/texture';

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

@@ -5,6 +5,10 @@
 - Added support for [parallel shader compilation](https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/) ([Deltakosh](https://github.com/deltakosh))
 - Added FlyCamera for free navigation in 3D space, with a limited set of settings ([Phuein](https://github.com/phuein))
 - Added Object Based Motion Blur post-process ([julien-moreau](https://github.com/julien-moreau))
+- WebXR ([TrevorDev](https://github.com/TrevorDev))
+  - Add customAnimationFrameRequester to allow sessions to hook into engine's render loop ([TrevorDev](https://github.com/TrevorDev))
+  - camera customDefaultRenderTarget to allow cameras to render to a custom render target (eg. xr framebuffer) instead of the canvas ([TrevorDev](https://github.com/TrevorDev))
+  - webXR camera which can be updated by a webXRSession ([TrevorDev](https://github.com/TrevorDev))
 
 ## Updates
 
@@ -16,9 +20,9 @@
 - Added utility function `Tools.BuildArray` for array initialisation ([barroij](https://github.com/barroij))
 - Introduced a new `IOfflineSupport` interface to hide IndexedDB ([Deltakosh](https://github.com/deltakosh))
 - `PBRMaterial` and `StandardMaterial` now use hot swapping feature for shaders. This means they can keep using a previous shader while a new one is being compiled ([Deltakosh](https://github.com/deltakosh))
-- Performance oriented changes ([barroij](https://github.com/barroij))
-  - prevent avoidable matrix inversion or square root computation.
-  - enable a removal in O(1) from the `transformNodes`array of the Scene.
+- Performance oriented updates ([barroij](https://github.com/barroij))
+  - Prevent avoidable matrix inversion or square root computation
+  - Enable a removal in O(1) from the `transformNodes`array of the Scene
 
 ### glTF Loader
 
@@ -31,7 +35,9 @@
 ## Bug fixes
 
 ### Core Engine
-
+- Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with pointer up being fire twice ([Deltakosh](https://github.com/deltakosh))
+- Fixed a bug with particle systems being update once per camera instead of once per frame ([Deltakosh](https://github.com/deltakosh)) 
 
 
 ### Viewer

+ 1 - 1
inspector/src/tools/FullscreenTool.ts

@@ -14,7 +14,7 @@ export class FullscreenTool extends AbstractTool {
 
         function requestFullScreen(element: HTMLElement) {
             // Supports most browsers and their versions.
-            var requestMethod = element.requestFullscreen || element.webkitRequestFullScreen;
+            var requestMethod = element.requestFullscreen || (<any>element).webkitRequestFullScreen;
             requestMethod.call(element);
         }
 

+ 1 - 1
package.json

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

+ 49 - 0
src/Cameras/XR/babylon.webXRCamera.ts

@@ -0,0 +1,49 @@
+module BABYLON {
+    /**
+     * WebXR Camera which holds the views for the xrSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    export class WebXRCamera extends FreeCamera {
+        /**
+         * Creates a new webXRCamera, this should only be set at the camera after it has been updated by the xrSessionManager
+         * @param name the name of the camera
+         * @param scene the scene to add the camera to
+         */
+        constructor(name: string, scene: BABYLON.Scene) {
+            super(name, BABYLON.Vector3.Zero(), scene);
+
+            // Initial camera configuration
+            this.minZ = 0;
+            this.rotationQuaternion = new BABYLON.Quaternion();
+            this.cameraRigMode = BABYLON.Camera.RIG_MODE_CUSTOM;
+            this._updateNumberOfRigCameras(1);
+        }
+
+        private _updateNumberOfRigCameras(viewCount = 1) {
+            while (this.rigCameras.length < viewCount) {
+                var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
+                newCamera.minZ = 0;
+                newCamera.parent = this;
+                this.rigCameras.push(newCamera);
+            }
+            while (this.rigCameras.length > viewCount) {
+                var removedCamera = this.rigCameras.pop();
+                if (removedCamera) {
+                    removedCamera.dispose();
+                }
+            }
+        }
+
+        /** @hidden */
+        public _updateForDualEyeDebugging(pupilDistance = 0.01) {
+            // Create initial camera rigs
+            this._updateNumberOfRigCameras(2);
+            this.rigCameras[0].viewport = new BABYLON.Viewport(0, 0, 0.5, 1.0);
+            this.rigCameras[0].position.x = -pupilDistance / 2;
+            this.rigCameras[0].customDefaultRenderTarget = null;
+            this.rigCameras[1].viewport = new BABYLON.Viewport(0.5, 0, 0.5, 1.0);
+            this.rigCameras[1].position.x = pupilDistance / 2;
+            this.rigCameras[1].customDefaultRenderTarget = null;
+        }
+    }
+}

+ 9 - 1
src/Cameras/babylon.camera.ts

@@ -56,6 +56,10 @@ module BABYLON {
          * Defines that both eyes of the camera should be renderered in a VR mode (webVR).
          */
         public static readonly RIG_MODE_WEBVR = 21;
+        /**
+         * Custom rig mode allowing rig cameras to be populated manually with any number of cameras
+         */
+        public static readonly RIG_MODE_CUSTOM = 22;
 
         /**
          * Defines if by default attaching controls should prevent the default javascript event to continue.
@@ -200,6 +204,10 @@ module BABYLON {
          * else in the scene.
          */
         public customRenderTargets = new Array<RenderTargetTexture>();
+        /**
+         * When set, the camera will render to this render target instead of the default canvas
+         */
+        public customDefaultRenderTarget: Nullable<RenderTargetTexture> = null;
 
         /**
          * Observable triggered when the camera view matrix has changed.
@@ -415,7 +423,7 @@ module BABYLON {
         /** @hidden */
         public _isSynchronizedViewMatrix(): boolean {
             if (!super._isSynchronized()) {
-                return false;
+                return false;
             }
 
             return this._cache.position.equals(this.position)

+ 1 - 1
src/Culling/babylon.boundingBox.ts

@@ -100,7 +100,7 @@ module BABYLON {
 
             // OBB
             max.addToRef(min, this.center).scaleInPlace(0.5);
-            max.subtractToRef(max, this.extendSize).scaleInPlace(0.5);
+            max.subtractToRef(min, this.extendSize).scaleInPlace(0.5);
 
             this._update(worldMatrix || _identityMatrix, extraWorldExtent || 0);
         }

+ 12 - 4
src/Engine/babylon.engine.ts

@@ -625,6 +625,11 @@ module BABYLON {
         public onBeginFrameObservable = new Observable<Engine>();
 
         /**
+         * If set, will be used to request the next animation frame for the render loop
+         */
+        public customAnimationFrameRequester: Nullable<ICustomAnimationFrameRequester> = null;
+
+        /**
          * Observable raised when the engine ends the current frame
          */
         public onEndFrameObservable = new Observable<Engine>();
@@ -1894,11 +1899,14 @@ module BABYLON {
 
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
-                var requester = null;
-                if (this._vrDisplay && this._vrDisplay.isPresenting) {
-                    requester = this._vrDisplay;
+                if (this.customAnimationFrameRequester) {
+                    this.customAnimationFrameRequester.requestID = Tools.QueueNewFrame(this.customAnimationFrameRequester.renderFunction || this._bindedRenderFunction, this.customAnimationFrameRequester);
+                    this._frameHandler = this.customAnimationFrameRequester.requestID;
+                } else if (this._vrDisplay && this._vrDisplay.isPresenting) {
+                    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, this._vrDisplay);
+                } else {
+                    this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
                 }
-                this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction, requester);
             } else {
                 this._renderingQueueLaunched = false;
             }

+ 6 - 6
src/Materials/babylon.material.ts

@@ -467,7 +467,7 @@ module BABYLON {
          * Gets a boolean indicating that current material needs to register RTT
          */
         public get hasRenderTargetTextures(): boolean {
-          return false;
+            return false;
         }
 
         /**
@@ -476,9 +476,9 @@ module BABYLON {
         public doNotSerialize = false;
 
         /**
-         * Specifies if the effect should be stored on sub meshes
+         * @hidden
          */
-        public storeEffectOnSubMeshes = false;
+        public _storeEffectOnSubMeshes = false;
 
         /**
          * Stores the animations for the material
@@ -1100,7 +1100,7 @@ module BABYLON {
                     scene.clipPlane = new Plane(0, 0, 0, 1);
                 }
 
-                if (this.storeEffectOnSubMeshes) {
+                if (this._storeEffectOnSubMeshes) {
                     if (this.isReadyForSubMesh(mesh, subMesh)) {
                         if (onCompiled) {
                             onCompiled(this);
@@ -1282,7 +1282,7 @@ module BABYLON {
                     if ((<Mesh>mesh).geometry) {
                         var geometry = <Geometry>((<Mesh>mesh).geometry);
 
-                        if (this.storeEffectOnSubMeshes) {
+                        if (this._storeEffectOnSubMeshes) {
                             for (var subMesh of mesh.subMeshes) {
                                 geometry._releaseVertexArrayObject(subMesh._materialEffect);
                                 if (forceDisposeEffect && subMesh._materialEffect) {
@@ -1300,7 +1300,7 @@ module BABYLON {
 
             // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
             if (forceDisposeEffect && this._effect) {
-                if (!this.storeEffectOnSubMeshes) {
+                if (!this._storeEffectOnSubMeshes) {
                     this._scene.getEngine()._releaseEffect(this._effect);
                 }
 

+ 2 - 2
src/Materials/babylon.multiMaterial.ts

@@ -35,7 +35,7 @@ module BABYLON {
 
             this.subMaterials = new Array<Material>();
 
-            this.storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
+            this._storeEffectOnSubMeshes = true; // multimaterial is considered like a push material
         }
 
         private _hookArray(array: Nullable<Material>[]): void {
@@ -105,7 +105,7 @@ module BABYLON {
             for (var index = 0; index < this.subMaterials.length; index++) {
                 var subMaterial = this.subMaterials[index];
                 if (subMaterial) {
-                    if (subMaterial.storeEffectOnSubMeshes) {
+                    if (subMaterial._storeEffectOnSubMeshes) {
                         if (!subMaterial.isReadyForSubMesh(mesh, subMesh, useInstances)) {
                             return false;
                         }

+ 1 - 1
src/Materials/babylon.pushMaterial.ts

@@ -18,7 +18,7 @@ module BABYLON {
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
-            this.storeEffectOnSubMeshes = true;
+            this._storeEffectOnSubMeshes = true;
         }
 
         public getEffect(): Effect {

+ 5 - 5
src/Mesh/babylon.mesh.ts

@@ -759,11 +759,11 @@ module BABYLON {
 
             let mat = this.material || scene.defaultMaterial;
             if (mat) {
-                if (mat.storeEffectOnSubMeshes) {
+                if (mat._storeEffectOnSubMeshes) {
                     for (var subMesh of this.subMeshes) {
                         let effectiveMaterial = subMesh.getMaterial();
                         if (effectiveMaterial) {
-                            if (effectiveMaterial.storeEffectOnSubMeshes) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
                                 if (!effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                                     return false;
                                 }
@@ -1539,7 +1539,7 @@ module BABYLON {
 
             this._effectiveMaterial = material;
 
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 if (!this._effectiveMaterial.isReadyForSubMesh(this, subMesh, hardwareInstancedRendering)) {
                     return this;
                 }
@@ -1557,7 +1557,7 @@ module BABYLON {
             }
 
             var effect: Nullable<Effect>;
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 effect = subMesh.effect;
             } else {
                 effect = this._effectiveMaterial.getEffect();
@@ -1590,7 +1590,7 @@ module BABYLON {
 
             var world = this.getWorldMatrix();
 
-            if (this._effectiveMaterial.storeEffectOnSubMeshes) {
+            if (this._effectiveMaterial._storeEffectOnSubMeshes) {
                 this._effectiveMaterial.bindForSubMesh(world, this, subMesh);
             } else {
                 this._effectiveMaterial.bind(world, this);

+ 19 - 20
src/Particles/babylon.gpuParticleSystem.ts

@@ -591,9 +591,9 @@ module BABYLON {
          * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
          */
         constructor(name: string, options: Partial<{
-                        capacity: number,
-                        randomTextureSize: number
-                    }>, scene: Scene, isAnimationSheetEnabled: boolean = false) {
+            capacity: number,
+            randomTextureSize: number
+        }>, scene: Scene, isAnimationSheetEnabled: boolean = false) {
             super(name);
             this._scene = scene || Engine.LastCreatedScene;
             // Setup the default processing configuration to the scene.
@@ -626,8 +626,8 @@ module BABYLON {
             this._updateEffectOptions = {
                 attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle", "cellIndex", "cellStartOffset", "noiseCoordinates1", "noiseCoordinates2"],
                 uniformsNames: ["currentCount", "timeDelta", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange", "gravity", "emitPower",
-                                "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor",
-                                "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
+                    "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor",
+                    "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
                 uniformBuffersNames: [],
                 samplers: ["randomSampler", "randomSampler2", "sizeGradientSampler", "angularSpeedGradientSampler", "velocityGradientSampler", "limitVelocityGradientSampler", "noiseSampler", "dragGradientSampler"],
                 defines: "",
@@ -673,7 +673,7 @@ module BABYLON {
         }
 
         private _createUpdateVAO(source: Buffer): WebGLVertexArrayObject {
-            let updateVertexBuffers: {[key: string]: VertexBuffer} = {};
+            let updateVertexBuffers: { [key: string]: VertexBuffer } = {};
             updateVertexBuffers["position"] = source.createVertexBuffer("position", 0, 3);
             updateVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1);
             updateVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1);
@@ -725,7 +725,7 @@ module BABYLON {
         }
 
         private _createRenderVAO(source: Buffer, spriteSource: Buffer): WebGLVertexArrayObject {
-            let renderVertexBuffers: {[key: string]: VertexBuffer} = {};
+            let renderVertexBuffers: { [key: string]: VertexBuffer } = {};
             renderVertexBuffers["position"] = source.createVertexBuffer("position", 0, 3, this._attributesStrideSize, true);
             renderVertexBuffers["age"] = source.createVertexBuffer("age", 3, 1, this._attributesStrideSize, true);
             renderVertexBuffers["life"] = source.createVertexBuffer("life", 4, 1, this._attributesStrideSize, true);
@@ -877,10 +877,10 @@ module BABYLON {
             }
 
             // Sprite data
-            var spriteData = new Float32Array([0.5, 0.5,  1, 1,
-                                              -0.5, 0.5,  0, 1,
-                                             -0.5, -0.5,  0, 0,
-                                             0.5, -0.5,  1, 0]);
+            var spriteData = new Float32Array([0.5, 0.5, 1, 1,
+                -0.5, 0.5, 0, 1,
+                -0.5, -0.5, 0, 0,
+                0.5, -0.5, 1, 0]);
 
             // Buffers
             this._buffer0 = new Buffer(engine, data, false, this._attributesStrideSize);
@@ -1042,9 +1042,9 @@ module BABYLON {
             }
 
             this._renderEffect = new Effect("gpuRenderParticles",
-                                            ["position", "age", "life", "size", "color", "offset", "uv", "direction", "initialDirection", "angle", "cellIndex"],
-                                            uniforms,
-                                            samplers, this._scene.getEngine(), defines);
+                ["position", "age", "life", "size", "color", "offset", "uv", "direction", "initialDirection", "angle", "cellIndex"],
+                uniforms,
+                samplers, this._scene.getEngine(), defines);
         }
 
         /**
@@ -1161,11 +1161,11 @@ module BABYLON {
                     this._preWarmDone = true;
                 }
 
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return 0;
                 }
 
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
 
             // Get everything ready to render
@@ -1294,8 +1294,7 @@ module BABYLON {
                 }
 
                 // Draw order
-                switch (this.blendMode)
-                {
+                switch (this.blendMode) {
                     case ParticleSystem.BLENDMODE_ADD:
                         this._engine.setAlphaMode(Engine.ALPHA_ADD);
                         break;
@@ -1447,7 +1446,7 @@ module BABYLON {
          * @returns the cloned particle system
          */
         public clone(name: string, newEmitter: any): GPUParticleSystem {
-            var result = new GPUParticleSystem(name, {capacity: this._capacity, randomTextureSize: this._randomTextureSize}, this._scene);
+            var result = new GPUParticleSystem(name, { capacity: this._capacity, randomTextureSize: this._randomTextureSize }, this._scene);
 
             Tools.DeepCopy(this, result);
 
@@ -1486,7 +1485,7 @@ module BABYLON {
          */
         public static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string, doNotStart = false): GPUParticleSystem {
             var name = parsedParticleSystem.name;
-            var particleSystem = new GPUParticleSystem(name, {capacity: parsedParticleSystem.capacity, randomTextureSize: parsedParticleSystem.randomTextureSize}, scene);
+            var particleSystem = new GPUParticleSystem(name, { capacity: parsedParticleSystem.capacity, randomTextureSize: parsedParticleSystem.randomTextureSize }, scene);
 
             if (parsedParticleSystem.activeParticleCount) {
                 particleSystem.activeParticleCount = parsedParticleSystem.activeParticleCount;

+ 149 - 149
src/Particles/babylon.particleSystem.ts

@@ -206,181 +206,181 @@ module BABYLON {
                 for (var index = 0; index < particles.length; index++) {
                     var particle = particles[index];
 
-                        let scaledUpdateSpeed = this._scaledUpdateSpeed;
-                        let previousAge = particle.age;
-                        particle.age += scaledUpdateSpeed;
+                    let scaledUpdateSpeed = this._scaledUpdateSpeed;
+                    let previousAge = particle.age;
+                    particle.age += scaledUpdateSpeed;
 
-                        // Evaluate step to death
-                        if (particle.age > particle.lifeTime) {
-                            let diff = particle.age - previousAge;
-                            let oldDiff = particle.lifeTime - previousAge;
+                    // Evaluate step to death
+                    if (particle.age > particle.lifeTime) {
+                        let diff = particle.age - previousAge;
+                        let oldDiff = particle.lifeTime - previousAge;
 
-                            scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
+                        scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
 
-                            particle.age = particle.lifeTime;
-                        }
+                        particle.age = particle.lifeTime;
+                    }
 
-                        let ratio = particle.age / particle.lifeTime;
-
-                        // Color
-                        if (this._colorGradients && this._colorGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentColorGradient) {
-                                    particle._currentColor1.copyFrom(particle._currentColor2);
-                                    (<ColorGradient>nextGradient).getColorToRef(particle._currentColor2);
-                                    particle._currentColorGradient = (<ColorGradient>currentGradient);
-                                }
-                                Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
-                            });
-                        }
-                        else {
-                            particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
-                            particle.color.addInPlace(this._scaledColorStep);
+                    let ratio = particle.age / particle.lifeTime;
 
-                            if (particle.color.a < 0) {
-                                particle.color.a = 0;
+                    // Color
+                    if (this._colorGradients && this._colorGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentColorGradient) {
+                                particle._currentColor1.copyFrom(particle._currentColor2);
+                                (<ColorGradient>nextGradient).getColorToRef(particle._currentColor2);
+                                particle._currentColorGradient = (<ColorGradient>currentGradient);
                             }
-                        }
+                            Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
+                        });
+                    }
+                    else {
+                        particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
+                        particle.color.addInPlace(this._scaledColorStep);
 
-                        // Angular speed
-                        if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentAngularSpeedGradient) {
-                                    particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
-                                    particle._currentAngularSpeed2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentAngularSpeedGradient = (<FactorGradient>currentGradient);
-                                }
-                                particle.angularSpeed = Scalar.Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
-                            });
-                        }
-                        particle.angle += particle.angularSpeed * scaledUpdateSpeed;
-
-                        // Direction
-                        let directionScale = scaledUpdateSpeed;
-
-                        /// Velocity
-                        if (this._velocityGradients && this._velocityGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentVelocityGradient) {
-                                    particle._currentVelocity1 = particle._currentVelocity2;
-                                    particle._currentVelocity2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentVelocityGradient = (<FactorGradient>currentGradient);
-                                }
-                                directionScale *= Scalar.Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
-                            });
+                        if (particle.color.a < 0) {
+                            particle.color.a = 0;
                         }
+                    }
 
-                        particle.direction.scaleToRef(directionScale, this._scaledDirection);
-
-                        /// Limit velocity
-                        if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentLimitVelocityGradient) {
-                                    particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
-                                    particle._currentLimitVelocity2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentLimitVelocityGradient = (<FactorGradient>currentGradient);
-                                }
+                    // Angular speed
+                    if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentAngularSpeedGradient) {
+                                particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
+                                particle._currentAngularSpeed2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentAngularSpeedGradient = (<FactorGradient>currentGradient);
+                            }
+                            particle.angularSpeed = Scalar.Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
+                        });
+                    }
+                    particle.angle += particle.angularSpeed * scaledUpdateSpeed;
+
+                    // Direction
+                    let directionScale = scaledUpdateSpeed;
+
+                    /// Velocity
+                    if (this._velocityGradients && this._velocityGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentVelocityGradient) {
+                                particle._currentVelocity1 = particle._currentVelocity2;
+                                particle._currentVelocity2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentVelocityGradient = (<FactorGradient>currentGradient);
+                            }
+                            directionScale *= Scalar.Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
+                        });
+                    }
 
-                                let limitVelocity = Scalar.Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
-                                let currentVelocity = particle.direction.length();
+                    particle.direction.scaleToRef(directionScale, this._scaledDirection);
 
-                                if (currentVelocity > limitVelocity) {
-                                    particle.direction.scaleInPlace(this.limitVelocityDamping);
-                                }
-                            });
-                        }
+                    /// Limit velocity
+                    if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentLimitVelocityGradient) {
+                                particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
+                                particle._currentLimitVelocity2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentLimitVelocityGradient = (<FactorGradient>currentGradient);
+                            }
 
-                        /// Drag
-                        if (this._dragGradients && this._dragGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentDragGradient) {
-                                    particle._currentDrag1 = particle._currentDrag2;
-                                    particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentDragGradient = (<FactorGradient>currentGradient);
-                                }
+                            let limitVelocity = Scalar.Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
+                            let currentVelocity = particle.direction.length();
 
-                                let drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
+                            if (currentVelocity > limitVelocity) {
+                                particle.direction.scaleInPlace(this.limitVelocityDamping);
+                            }
+                        });
+                    }
 
-                                this._scaledDirection.scaleInPlace(1.0 - drag);
-                            });
-                        }
+                    /// Drag
+                    if (this._dragGradients && this._dragGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentDragGradient) {
+                                particle._currentDrag1 = particle._currentDrag2;
+                                particle._currentDrag2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentDragGradient = (<FactorGradient>currentGradient);
+                            }
 
-                        particle.position.addInPlace(this._scaledDirection);
+                            let drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
 
-                        // Noise
-                        if (noiseTextureData && noiseTextureSize) {
-                            let fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
-                            let fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
-                            let fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                            this._scaledDirection.scaleInPlace(1.0 - drag);
+                        });
+                    }
 
-                            let force = Tmp.Vector3[0];
-                            let scaledForce = Tmp.Vector3[1];
+                    particle.position.addInPlace(this._scaledDirection);
 
-                            force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
+                    // Noise
+                    if (noiseTextureData && noiseTextureSize) {
+                        let fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                        let fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
+                        let fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
 
-                            force.scaleToRef(scaledUpdateSpeed, scaledForce);
-                            particle.direction.addInPlace(scaledForce);
-                        }
+                        let force = Tmp.Vector3[0];
+                        let scaledForce = Tmp.Vector3[1];
 
-                        // Gravity
-                        this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
-                        particle.direction.addInPlace(this._scaledGravity);
-
-                        // Size
-                        if (this._sizeGradients && this._sizeGradients.length > 0) {
-                            Tools.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
-                                if (currentGradient !== particle._currentSizeGradient) {
-                                    particle._currentSize1 = particle._currentSize2;
-                                    particle._currentSize2 = (<FactorGradient>nextGradient).getFactor();
-                                    particle._currentSizeGradient = (<FactorGradient>currentGradient);
-                                }
-                                particle.size = Scalar.Lerp(particle._currentSize1, particle._currentSize2, scale);
-                            });
-                        }
+                        force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
 
-                        // Remap data
-                        if (this._useRampGradients) {
-                            if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
-                                Tools.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
-                                    let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
-                                    let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+                        force.scaleToRef(scaledUpdateSpeed, scaledForce);
+                        particle.direction.addInPlace(scaledForce);
+                    }
 
-                                    particle.remapData.x = min;
-                                    particle.remapData.y = max - min;
-                                });
+                    // Gravity
+                    this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
+                    particle.direction.addInPlace(this._scaledGravity);
+
+                    // Size
+                    if (this._sizeGradients && this._sizeGradients.length > 0) {
+                        Tools.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
+                            if (currentGradient !== particle._currentSizeGradient) {
+                                particle._currentSize1 = particle._currentSize2;
+                                particle._currentSize2 = (<FactorGradient>nextGradient).getFactor();
+                                particle._currentSizeGradient = (<FactorGradient>currentGradient);
                             }
+                            particle.size = Scalar.Lerp(particle._currentSize1, particle._currentSize2, scale);
+                        });
+                    }
 
-                            if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
-                                Tools.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
-                                    let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
-                                    let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+                    // Remap data
+                    if (this._useRampGradients) {
+                        if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
+                            Tools.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
+                                let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
+                                let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
 
-                                    particle.remapData.z = min;
-                                    particle.remapData.w = max - min;
-                                });
-                            }
+                                particle.remapData.x = min;
+                                particle.remapData.y = max - min;
+                            });
                         }
 
-                        if (this._isAnimationSheetEnabled) {
-                            particle.updateCellIndex();
+                        if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
+                            Tools.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
+                                let min = Scalar.Lerp((<FactorGradient>currentGradient).factor1, (<FactorGradient>nextGradient).factor1, scale);
+                                let max = Scalar.Lerp((<FactorGradient>currentGradient).factor2!, (<FactorGradient>nextGradient).factor2!, scale);
+
+                                particle.remapData.z = min;
+                                particle.remapData.w = max - min;
+                            });
                         }
+                    }
 
-                        // Update the position of the attached sub-emitters to match their attached particle
-                        particle._inheritParticleInfoToSubEmitters();
-
-                        if (particle.age >= particle.lifeTime) { // Recycle by swapping with last particle
-                            this._emitFromParticle(particle);
-                            if (particle._attachedSubEmitters) {
-                                particle._attachedSubEmitters.forEach((subEmitter) => {
-                                    subEmitter.particleSystem.disposeOnStop = true;
-                                    subEmitter.particleSystem.stop();
-                                });
-                                particle._attachedSubEmitters = null;
-                            }
-                            this.recycleParticle(particle);
-                            index--;
-                            continue;
+                    if (this._isAnimationSheetEnabled) {
+                        particle.updateCellIndex();
+                    }
+
+                    // Update the position of the attached sub-emitters to match their attached particle
+                    particle._inheritParticleInfoToSubEmitters();
+
+                    if (particle.age >= particle.lifeTime) { // Recycle by swapping with last particle
+                        this._emitFromParticle(particle);
+                        if (particle._attachedSubEmitters) {
+                            particle._attachedSubEmitters.forEach((subEmitter) => {
+                                subEmitter.particleSystem.disposeOnStop = true;
+                                subEmitter.particleSystem.stop();
+                            });
+                            particle._attachedSubEmitters = null;
                         }
+                        this.recycleParticle(particle);
+                        index--;
+                        continue;
+                    }
                 }
             };
         }
@@ -1138,14 +1138,14 @@ module BABYLON {
                     }
                     else if (offsetX === 1) {
                         offsetX = 1 - this._epsilon;
-                         }
+                    }
 
                     if (offsetY === 0) {
                         offsetY = this._epsilon;
                     }
                     else if (offsetY === 1) {
                         offsetY = 1 - this._epsilon;
-                         }
+                    }
                 }
 
                 this._vertexData[offset++] = offsetX;
@@ -1565,10 +1565,10 @@ module BABYLON {
                     return;
                 }
 
-                if (this._currentRenderId === this._scene.getRenderId()) {
+                if (this._currentRenderId === this._scene.getFrameId()) {
                     return;
                 }
-                this._currentRenderId = this._scene.getRenderId();
+                this._currentRenderId = this._scene.getFrameId();
             }
 
             this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene.getAnimationRatio());

+ 2 - 2
src/PostProcess/babylon.motionBlurPostProcess.ts

@@ -3,7 +3,7 @@ module BABYLON {
      * The Motion Blur Post Process which blurs an image based on the objects velocity in scene.
      * Velocity can be affected by each object's rotation, position and scale depending on the transformation speed.
      * As an example, all you have to do is to create the post-process:
-     *  var mb = new BABYLON.MotionBlurProcess(
+     *  var mb = new BABYLON.MotionBlurPostProcess(
      *      'mb', // The name of the effect.
      *      scene, // The scene containing the objects to blur according to their velocity.
      *      1.0, // The required width/height ratio to downsize to before computing the render pass.
@@ -11,7 +11,7 @@ module BABYLON {
      * );
      * Then, all objects moving, rotating and/or scaling will be blurred depending on the transformation speed.
      */
-    export class MotionBlurProcess extends PostProcess {
+    export class MotionBlurPostProcess extends PostProcess {
         /**
          * Defines how much the image is blurred by the movement. Default value is equal to 1
          */

+ 20 - 0
src/Tools/babylon.tools.ts

@@ -1,5 +1,25 @@
 module BABYLON {
     /**
+     * Interface for any object that can request an animation frame
+     */
+    export interface ICustomAnimationFrameRequester {
+        /**
+         * This function will be called when the render loop is ready. If this is not populated, the engine's renderloop function will be called
+         */
+        renderFunction?: Function;
+        /**
+         * Called to request the next frame to render to
+         * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
+         */
+        requestAnimationFrame: Function;
+        /**
+         * You can pass this value to cancelAnimationFrame() to cancel the refresh callback request
+         * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame#Return_value
+         */
+        requestID?: number;
+    }
+
+    /**
      * Interface containing an array of animations
      */
     export interface IAnimatable {

+ 0 - 4
src/babylon.mixins.ts

@@ -155,10 +155,6 @@ interface HTMLVideoElement {
     mozSrcObject: any;
 }
 
-interface Element {
-    webkitRequestFullScreen: () => void;
-}
-
 interface Screen {
     readonly orientation: string;
     readonly mozOrientation: string;

+ 30 - 5
src/babylon.scene.ts

@@ -253,6 +253,12 @@ module BABYLON {
          */
         public preventDefaultOnPointerDown = true;
 
+        /**
+         * This is used to call preventDefault() on pointer up
+         * in order to block unwanted artifacts like system double clicks
+         */
+        public preventDefaultOnPointerUp = true;
+
         // Metadata
         /**
          * Gets or sets user defined metadata
@@ -1868,6 +1874,7 @@ module BABYLON {
                         checkPicking = act.hasPickTriggers;
                     }
                 }
+                let eventRaised = false;
                 if (checkPicking) {
                     let btn = evt.button;
                     clickInfo.hasSwiped = this._isPointerSwiping();
@@ -1892,7 +1899,7 @@ module BABYLON {
                             if (Date.now() - this._previousStartingPointerTime > Scene.DoubleClickDelay ||
                                 btn !== this._previousButtonPressed) {
                                 clickInfo.singleClick = true;
-
+                                eventRaised = true;
                                 cb(clickInfo, this._currentPickResult);
                             }
                         }
@@ -1961,8 +1968,11 @@ module BABYLON {
                         }
                     }
                 }
-                clickInfo.ignore = true;
-                cb(clickInfo, this._currentPickResult);
+
+                if (!eventRaised) {
+                    clickInfo.ignore = true;
+                    cb(clickInfo, this._currentPickResult);
+                }
             };
 
             this._onPointerMove = (evt: PointerEvent) => {
@@ -2037,6 +2047,12 @@ module BABYLON {
                 this._meshPickProceed = false;
 
                 this._updatePointerPosition(evt);
+
+                if (this.preventDefaultOnPointerUp && canvas) {
+                    evt.preventDefault();
+                    canvas.focus();
+                }
+
                 this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
                     // PreObservable support
                     if (this.onPrePointerObservable.hasObservers()) {
@@ -4166,7 +4182,7 @@ module BABYLON {
 
                 mesh._preActivate();
 
-                if (mesh.isVisible && mesh.visibility > 0 && (mesh.alwaysSelectAsActiveMesh || ((mesh.layerMask & this.activeCamera.layerMask) !== 0 && mesh.isInFrustum(this._frustumPlanes)))) {
+                if (mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) !== 0) && (mesh.alwaysSelectAsActiveMesh || mesh.isInFrustum(this._frustumPlanes))) {
                     this._activeMeshes.push(mesh);
                     this.activeCamera._activeMeshes.push(mesh);
 
@@ -4328,7 +4344,16 @@ module BABYLON {
 
                 this._intermediateRendering = false;
 
-                engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                if (this.activeCamera.customDefaultRenderTarget) {
+                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                    if (internalTexture) {
+                        engine.bindFramebuffer(internalTexture);
+                    }else {
+                        Tools.Error("Camera contains invalid customDefaultRenderTarget");
+                    }
+                }else {
+                    engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
+                }
             }
 
             this.onAfterRenderTargetsRenderObservable.notifyObservers(this);

+ 1 - 1
src/babylon.sceneComponent.ts

@@ -138,7 +138,7 @@ module BABYLON {
     /**
      * Strong typing of a Active Mesh related stage step action
      */
-    export type ActiveMeshStageAction =  (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
+    export type ActiveMeshStageAction = (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
 
     /**
      * Strong typing of a Camera related stage step action

二進制
tests/validation/ReferenceImages/cameraRig.png


+ 1 - 1
tests/validation/config.json

@@ -14,7 +14,7 @@
     },
     {
       "title": "Camera rig",
-      "playgroundId": "#ATL1CS#6",
+      "playgroundId": "#ATL1CS#9",
       "referenceImage": "cameraRig.png"
     },
     {

+ 3 - 3
tests/validation/validation.js

@@ -7,7 +7,7 @@ var config;
 var justOnce;
 
 var threshold = 25;
-var errorCountThreshold = 400;
+var errorRatio = 2.5;
 
 // Overload the random to make it deterministic
 var seed = 100000,
@@ -52,7 +52,7 @@ function compare(renderData, referenceCanvas) {
         console.log("Pixel difference: " + differencesCount + " pixels.");
     }
 
-    return differencesCount > errorCountThreshold;
+    return (differencesCount * 100) / (width * height) > errorRatio;
 }
 
 function getRenderData(canvas, engine) {
@@ -235,7 +235,7 @@ function runTest(index, done) {
         var snippetUrl = "//babylonjs-api2.azurewebsites.net/snippets";
         var pgRoot = "/Playground"
 
-        var retryTime = 30 * 1000;
+        var retryTime = 500;
         var maxRetry = 2;
         var retry = 0;