David Catuhe 6 years ago
parent
commit
9969cfdf81

File diff suppressed because it is too large
+ 3904 - 3825
Playground/babylon.d.txt


File diff suppressed because it is too large
+ 3866 - 3787
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.js


+ 144 - 2
dist/preview release/babylon.max.js

@@ -5353,6 +5353,47 @@ var BABYLON;
             return this.normalizeFromLength(this.length());
         };
         /**
+         * Reorders the x y z properties of the vector in place
+         * @param order new ordering of the properties (eg. for vector 1,2,3 with "ZYX" will produce 3,2,1)
+         * @returns the current updated vector
+         */
+        Vector3.prototype.reorderInPlace = function (order) {
+            var _this = this;
+            order = order.toLowerCase();
+            if (order === "xyz") {
+                return this;
+            }
+            MathTmp.Vector3[0].copyFrom(this);
+            ["x", "y", "z"].forEach(function (val, i) {
+                _this[val] = MathTmp.Vector3[0][order[i]];
+            });
+            return this;
+        };
+        /**
+         * Rotates the vector around 0,0,0 by a quaternion
+         * @param quaternion the rotation quaternion
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionToRef = function (quaternion, result) {
+            quaternion.toRotationMatrix(MathTmp.Matrix[0]);
+            Vector3.TransformCoordinatesToRef(this, MathTmp.Matrix[0], result);
+            return result;
+        };
+        /**
+         * Rotates a vector around a given point
+         * @param quaternion the rotation quaternion
+         * @param point the point to rotate around
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionAroundPointToRef = function (quaternion, point, result) {
+            this.subtractToRef(point, MathTmp.Vector3[0]);
+            MathTmp.Vector3[0].rotateByQuaternionToRef(quaternion, MathTmp.Vector3[0]);
+            point.addToRef(MathTmp.Vector3[0], result);
+            return result;
+        };
+        /**
          * Normalize the current Vector3 with the given input length.
          * Please note that this is an in place operation.
          * @param len the length of the vector
@@ -7236,6 +7277,16 @@ var BABYLON;
             return new Quaternion(-q.x, -q.y, -q.z, q.w);
         };
         /**
+         * Inverse a given quaternion
+         * @param q defines the source quaternion
+         * @param result the quaternion the result will be stored in
+         * @returns the result quaternion
+         */
+        Quaternion.InverseToRef = function (q, result) {
+            result.set(-q.x, -q.y, -q.z, q.w);
+            return result;
+        };
+        /**
          * Creates an identity quaternion
          * @returns the identity quaternion
          */
@@ -7288,6 +7339,50 @@ var BABYLON;
             return new Quaternion(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         };
         /**
+         * Create a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerAngles = function (x, y, z) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(y, x, z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerAnglesToRef = function (x, y, z, result) {
+            Quaternion.RotationYawPitchRollToRef(y, x, z, result);
+            return result;
+        };
+        /**
+         * Create a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerVector = function (vec) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerVectorToRef = function (vec, result) {
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, result);
+            return result;
+        };
+        /**
          * Creates a new quaternion from the given Euler float angles (y, x, z)
          * @param yaw defines the rotation around Y axis
          * @param pitch defines the rotation around X axis
@@ -34582,7 +34677,12 @@ var BABYLON;
                 serializationObject.rotation = this.rotation.asArray();
             }
             serializationObject.scaling = this.scaling.asArray();
-            serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            if (this._postMultiplyPivotMatrix) {
+                serializationObject.pivotMatrix = this.getPivotMatrix().asArray();
+            }
+            else {
+                serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            }
             serializationObject.isEnabled = this.isEnabled(false);
             serializationObject.isVisible = this.isVisible;
             serializationObject.infiniteDistance = this.infiniteDistance;
@@ -98781,7 +98881,14 @@ var BABYLON;
                 mesh.computeWorldMatrix(true);
                 //get original center with no rotation
                 var c = center.clone();
-                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                var oldPivot = mesh.getPivotMatrix();
+                if (oldPivot) {
+                    // create a copy the pivot Matrix as it is modified in place
+                    oldPivot = oldPivot.clone();
+                }
+                else {
+                    oldPivot = BABYLON.Matrix.Identity();
+                }
                 //calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
                 var p = BABYLON.Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
                 mesh.setPreTransformMatrix(p);
@@ -108439,6 +108546,7 @@ var BABYLON;
                 var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
                 newCamera.minZ = 0;
                 newCamera.parent = this;
+                newCamera.rotationQuaternion = new BABYLON.Quaternion();
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -108734,6 +108842,7 @@ var BABYLON;
             this.camera = new BABYLON.WebXRCamera("", scene);
             this._sessionManager = new BABYLON.WebXRSessionManager(scene);
             this.container = new BABYLON.AbstractMesh("", scene);
+            this.camera.parent = this.container;
         }
         WebXRExperienceHelper.prototype._setState = function (val) {
             this.state = val;
@@ -108803,6 +108912,27 @@ var BABYLON;
             return this._sessionManager.environmentPointHitTestAsync(ray);
         };
         /**
+         * Updates the global position of the camera by moving the camera's container
+         * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
+         * @param position The desired global position of the camera
+         */
+        WebXRExperienceHelper.prototype.setPositionOfCameraUsingContainer = function (position) {
+            this.camera.globalPosition.subtractToRef(position, WebXRExperienceHelper._TmpVector);
+            this.container.position.subtractInPlace(WebXRExperienceHelper._TmpVector);
+        };
+        /**
+         * Rotates the xr camera by rotating the camera's container around the camera's position
+         * This should be used instead of modifying the camera's rotation as it will be overwritten by an xrSessions's update frame
+         * @param rotation the desired quaternion rotation to apply to the camera
+         */
+        WebXRExperienceHelper.prototype.rotateCameraByQuaternionUsingContainer = function (rotation) {
+            if (!this.container.rotationQuaternion) {
+                this.container.rotationQuaternion = BABYLON.Quaternion.FromEulerVector(this.container.rotation);
+            }
+            this.container.rotationQuaternion.multiplyInPlace(rotation);
+            this.container.position.rotateByQuaternionAroundPointToRef(rotation, this.camera.globalPosition, this.container.position);
+        };
+        /**
          * Checks if the creation options are supported by the xr session
          * @param options creation options
          * @returns true if supported
@@ -108822,6 +108952,7 @@ var BABYLON;
             this.onStateChangedObservable.clear();
             this._sessionManager.dispose();
         };
+        WebXRExperienceHelper._TmpVector = new BABYLON.Vector3();
         return WebXRExperienceHelper;
     }());
     BABYLON.WebXRExperienceHelper = WebXRExperienceHelper;
@@ -108910,6 +109041,14 @@ var BABYLON;
             this.scene = scene;
             this._buttons = [];
             this._activeButton = null;
+            /**
+             * Fired every time the active button is changed.
+             *
+             * When xr is entered via a button that launches xr that button will be the callback parameter
+             *
+             * When exiting xr the callback parameter will be null)
+             */
+            this.activeButtonChangedObservable = new BABYLON.Observable();
             this._overlay = document.createElement("div");
             this._overlay.style.cssText = "z-index:11;position: absolute; right: 20px;bottom: 50px;";
             if (options.customButtons) {
@@ -108987,6 +109126,7 @@ var BABYLON;
                         }); };
                     }
                 });
+                return ui;
             });
         };
         WebXREnterExitUI.prototype._updateButtons = function (activeButton) {
@@ -108995,6 +109135,7 @@ var BABYLON;
             this._buttons.forEach(function (b) {
                 b.update(_this._activeButton);
             });
+            this.activeButtonChangedObservable.notifyObservers(this._activeButton);
         };
         /**
          * Disposes of the object
@@ -109004,6 +109145,7 @@ var BABYLON;
             if (renderCanvas && renderCanvas.parentNode && renderCanvas.parentNode.contains(this._overlay)) {
                 renderCanvas.parentNode.removeChild(this._overlay);
             }
+            this.activeButtonChangedObservable.clear();
         };
         return WebXREnterExitUI;
     }());

+ 144 - 2
dist/preview release/babylon.no-module.max.js

@@ -5320,6 +5320,47 @@ var BABYLON;
             return this.normalizeFromLength(this.length());
         };
         /**
+         * Reorders the x y z properties of the vector in place
+         * @param order new ordering of the properties (eg. for vector 1,2,3 with "ZYX" will produce 3,2,1)
+         * @returns the current updated vector
+         */
+        Vector3.prototype.reorderInPlace = function (order) {
+            var _this = this;
+            order = order.toLowerCase();
+            if (order === "xyz") {
+                return this;
+            }
+            MathTmp.Vector3[0].copyFrom(this);
+            ["x", "y", "z"].forEach(function (val, i) {
+                _this[val] = MathTmp.Vector3[0][order[i]];
+            });
+            return this;
+        };
+        /**
+         * Rotates the vector around 0,0,0 by a quaternion
+         * @param quaternion the rotation quaternion
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionToRef = function (quaternion, result) {
+            quaternion.toRotationMatrix(MathTmp.Matrix[0]);
+            Vector3.TransformCoordinatesToRef(this, MathTmp.Matrix[0], result);
+            return result;
+        };
+        /**
+         * Rotates a vector around a given point
+         * @param quaternion the rotation quaternion
+         * @param point the point to rotate around
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionAroundPointToRef = function (quaternion, point, result) {
+            this.subtractToRef(point, MathTmp.Vector3[0]);
+            MathTmp.Vector3[0].rotateByQuaternionToRef(quaternion, MathTmp.Vector3[0]);
+            point.addToRef(MathTmp.Vector3[0], result);
+            return result;
+        };
+        /**
          * Normalize the current Vector3 with the given input length.
          * Please note that this is an in place operation.
          * @param len the length of the vector
@@ -7203,6 +7244,16 @@ var BABYLON;
             return new Quaternion(-q.x, -q.y, -q.z, q.w);
         };
         /**
+         * Inverse a given quaternion
+         * @param q defines the source quaternion
+         * @param result the quaternion the result will be stored in
+         * @returns the result quaternion
+         */
+        Quaternion.InverseToRef = function (q, result) {
+            result.set(-q.x, -q.y, -q.z, q.w);
+            return result;
+        };
+        /**
          * Creates an identity quaternion
          * @returns the identity quaternion
          */
@@ -7255,6 +7306,50 @@ var BABYLON;
             return new Quaternion(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         };
         /**
+         * Create a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerAngles = function (x, y, z) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(y, x, z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerAnglesToRef = function (x, y, z, result) {
+            Quaternion.RotationYawPitchRollToRef(y, x, z, result);
+            return result;
+        };
+        /**
+         * Create a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerVector = function (vec) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerVectorToRef = function (vec, result) {
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, result);
+            return result;
+        };
+        /**
          * Creates a new quaternion from the given Euler float angles (y, x, z)
          * @param yaw defines the rotation around Y axis
          * @param pitch defines the rotation around X axis
@@ -34549,7 +34644,12 @@ var BABYLON;
                 serializationObject.rotation = this.rotation.asArray();
             }
             serializationObject.scaling = this.scaling.asArray();
-            serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            if (this._postMultiplyPivotMatrix) {
+                serializationObject.pivotMatrix = this.getPivotMatrix().asArray();
+            }
+            else {
+                serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            }
             serializationObject.isEnabled = this.isEnabled(false);
             serializationObject.isVisible = this.isVisible;
             serializationObject.infiniteDistance = this.infiniteDistance;
@@ -98748,7 +98848,14 @@ var BABYLON;
                 mesh.computeWorldMatrix(true);
                 //get original center with no rotation
                 var c = center.clone();
-                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                var oldPivot = mesh.getPivotMatrix();
+                if (oldPivot) {
+                    // create a copy the pivot Matrix as it is modified in place
+                    oldPivot = oldPivot.clone();
+                }
+                else {
+                    oldPivot = BABYLON.Matrix.Identity();
+                }
                 //calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
                 var p = BABYLON.Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
                 mesh.setPreTransformMatrix(p);
@@ -108406,6 +108513,7 @@ var BABYLON;
                 var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
                 newCamera.minZ = 0;
                 newCamera.parent = this;
+                newCamera.rotationQuaternion = new BABYLON.Quaternion();
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -108701,6 +108809,7 @@ var BABYLON;
             this.camera = new BABYLON.WebXRCamera("", scene);
             this._sessionManager = new BABYLON.WebXRSessionManager(scene);
             this.container = new BABYLON.AbstractMesh("", scene);
+            this.camera.parent = this.container;
         }
         WebXRExperienceHelper.prototype._setState = function (val) {
             this.state = val;
@@ -108770,6 +108879,27 @@ var BABYLON;
             return this._sessionManager.environmentPointHitTestAsync(ray);
         };
         /**
+         * Updates the global position of the camera by moving the camera's container
+         * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
+         * @param position The desired global position of the camera
+         */
+        WebXRExperienceHelper.prototype.setPositionOfCameraUsingContainer = function (position) {
+            this.camera.globalPosition.subtractToRef(position, WebXRExperienceHelper._TmpVector);
+            this.container.position.subtractInPlace(WebXRExperienceHelper._TmpVector);
+        };
+        /**
+         * Rotates the xr camera by rotating the camera's container around the camera's position
+         * This should be used instead of modifying the camera's rotation as it will be overwritten by an xrSessions's update frame
+         * @param rotation the desired quaternion rotation to apply to the camera
+         */
+        WebXRExperienceHelper.prototype.rotateCameraByQuaternionUsingContainer = function (rotation) {
+            if (!this.container.rotationQuaternion) {
+                this.container.rotationQuaternion = BABYLON.Quaternion.FromEulerVector(this.container.rotation);
+            }
+            this.container.rotationQuaternion.multiplyInPlace(rotation);
+            this.container.position.rotateByQuaternionAroundPointToRef(rotation, this.camera.globalPosition, this.container.position);
+        };
+        /**
          * Checks if the creation options are supported by the xr session
          * @param options creation options
          * @returns true if supported
@@ -108789,6 +108919,7 @@ var BABYLON;
             this.onStateChangedObservable.clear();
             this._sessionManager.dispose();
         };
+        WebXRExperienceHelper._TmpVector = new BABYLON.Vector3();
         return WebXRExperienceHelper;
     }());
     BABYLON.WebXRExperienceHelper = WebXRExperienceHelper;
@@ -108877,6 +109008,14 @@ var BABYLON;
             this.scene = scene;
             this._buttons = [];
             this._activeButton = null;
+            /**
+             * Fired every time the active button is changed.
+             *
+             * When xr is entered via a button that launches xr that button will be the callback parameter
+             *
+             * When exiting xr the callback parameter will be null)
+             */
+            this.activeButtonChangedObservable = new BABYLON.Observable();
             this._overlay = document.createElement("div");
             this._overlay.style.cssText = "z-index:11;position: absolute; right: 20px;bottom: 50px;";
             if (options.customButtons) {
@@ -108954,6 +109093,7 @@ var BABYLON;
                         }); };
                     }
                 });
+                return ui;
             });
         };
         WebXREnterExitUI.prototype._updateButtons = function (activeButton) {
@@ -108962,6 +109102,7 @@ var BABYLON;
             this._buttons.forEach(function (b) {
                 b.update(_this._activeButton);
             });
+            this.activeButtonChangedObservable.notifyObservers(this._activeButton);
         };
         /**
          * Disposes of the object
@@ -108971,6 +109112,7 @@ var BABYLON;
             if (renderCanvas && renderCanvas.parentNode && renderCanvas.parentNode.contains(this._overlay)) {
                 renderCanvas.parentNode.removeChild(this._overlay);
             }
+            this.activeButtonChangedObservable.clear();
         };
         return WebXREnterExitUI;
     }());

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.worker.js


+ 144 - 2
dist/preview release/es6.js

@@ -5320,6 +5320,47 @@ var BABYLON;
             return this.normalizeFromLength(this.length());
         };
         /**
+         * Reorders the x y z properties of the vector in place
+         * @param order new ordering of the properties (eg. for vector 1,2,3 with "ZYX" will produce 3,2,1)
+         * @returns the current updated vector
+         */
+        Vector3.prototype.reorderInPlace = function (order) {
+            var _this = this;
+            order = order.toLowerCase();
+            if (order === "xyz") {
+                return this;
+            }
+            MathTmp.Vector3[0].copyFrom(this);
+            ["x", "y", "z"].forEach(function (val, i) {
+                _this[val] = MathTmp.Vector3[0][order[i]];
+            });
+            return this;
+        };
+        /**
+         * Rotates the vector around 0,0,0 by a quaternion
+         * @param quaternion the rotation quaternion
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionToRef = function (quaternion, result) {
+            quaternion.toRotationMatrix(MathTmp.Matrix[0]);
+            Vector3.TransformCoordinatesToRef(this, MathTmp.Matrix[0], result);
+            return result;
+        };
+        /**
+         * Rotates a vector around a given point
+         * @param quaternion the rotation quaternion
+         * @param point the point to rotate around
+         * @param result vector to store the result
+         * @returns the resulting vector
+         */
+        Vector3.prototype.rotateByQuaternionAroundPointToRef = function (quaternion, point, result) {
+            this.subtractToRef(point, MathTmp.Vector3[0]);
+            MathTmp.Vector3[0].rotateByQuaternionToRef(quaternion, MathTmp.Vector3[0]);
+            point.addToRef(MathTmp.Vector3[0], result);
+            return result;
+        };
+        /**
          * Normalize the current Vector3 with the given input length.
          * Please note that this is an in place operation.
          * @param len the length of the vector
@@ -7203,6 +7244,16 @@ var BABYLON;
             return new Quaternion(-q.x, -q.y, -q.z, q.w);
         };
         /**
+         * Inverse a given quaternion
+         * @param q defines the source quaternion
+         * @param result the quaternion the result will be stored in
+         * @returns the result quaternion
+         */
+        Quaternion.InverseToRef = function (q, result) {
+            result.set(-q.x, -q.y, -q.z, q.w);
+            return result;
+        };
+        /**
          * Creates an identity quaternion
          * @returns the identity quaternion
          */
@@ -7255,6 +7306,50 @@ var BABYLON;
             return new Quaternion(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         };
         /**
+         * Create a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerAngles = function (x, y, z) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(y, x, z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation angles
+         * @param x Pitch
+         * @param y Yaw
+         * @param z Roll
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerAnglesToRef = function (x, y, z, result) {
+            Quaternion.RotationYawPitchRollToRef(y, x, z, result);
+            return result;
+        };
+        /**
+         * Create a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @returns the new Quaternion
+         */
+        Quaternion.FromEulerVector = function (vec) {
+            var q = new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, q);
+            return q;
+        };
+        /**
+         * Updates a quaternion from Euler rotation vector
+         * @param vec the Euler vector (x Pitch, y Yaw, z Roll)
+         * @param result the quaternion to store the result
+         * @returns the updated quaternion
+         */
+        Quaternion.FromEulerVectorToRef = function (vec, result) {
+            Quaternion.RotationYawPitchRollToRef(vec.y, vec.x, vec.z, result);
+            return result;
+        };
+        /**
          * Creates a new quaternion from the given Euler float angles (y, x, z)
          * @param yaw defines the rotation around Y axis
          * @param pitch defines the rotation around X axis
@@ -34549,7 +34644,12 @@ var BABYLON;
                 serializationObject.rotation = this.rotation.asArray();
             }
             serializationObject.scaling = this.scaling.asArray();
-            serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            if (this._postMultiplyPivotMatrix) {
+                serializationObject.pivotMatrix = this.getPivotMatrix().asArray();
+            }
+            else {
+                serializationObject.localMatrix = this.getPivotMatrix().asArray();
+            }
             serializationObject.isEnabled = this.isEnabled(false);
             serializationObject.isVisible = this.isVisible;
             serializationObject.infiniteDistance = this.infiniteDistance;
@@ -98748,7 +98848,14 @@ var BABYLON;
                 mesh.computeWorldMatrix(true);
                 //get original center with no rotation
                 var c = center.clone();
-                var oldPivot = mesh.getPivotMatrix() || BABYLON.Matrix.Translation(0, 0, 0);
+                var oldPivot = mesh.getPivotMatrix();
+                if (oldPivot) {
+                    // create a copy the pivot Matrix as it is modified in place
+                    oldPivot = oldPivot.clone();
+                }
+                else {
+                    oldPivot = BABYLON.Matrix.Identity();
+                }
                 //calculate the new center using a pivot (since this.BJSCANNON.js doesn't center height maps)
                 var p = BABYLON.Matrix.Translation(boundingInfo.boundingBox.extendSizeWorld.x, 0, -boundingInfo.boundingBox.extendSizeWorld.z);
                 mesh.setPreTransformMatrix(p);
@@ -108406,6 +108513,7 @@ var BABYLON;
                 var newCamera = new BABYLON.TargetCamera("view: " + this.rigCameras.length, BABYLON.Vector3.Zero(), this.getScene());
                 newCamera.minZ = 0;
                 newCamera.parent = this;
+                newCamera.rotationQuaternion = new BABYLON.Quaternion();
                 this.rigCameras.push(newCamera);
             }
             while (this.rigCameras.length > viewCount) {
@@ -108701,6 +108809,7 @@ var BABYLON;
             this.camera = new BABYLON.WebXRCamera("", scene);
             this._sessionManager = new BABYLON.WebXRSessionManager(scene);
             this.container = new BABYLON.AbstractMesh("", scene);
+            this.camera.parent = this.container;
         }
         WebXRExperienceHelper.prototype._setState = function (val) {
             this.state = val;
@@ -108770,6 +108879,27 @@ var BABYLON;
             return this._sessionManager.environmentPointHitTestAsync(ray);
         };
         /**
+         * Updates the global position of the camera by moving the camera's container
+         * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
+         * @param position The desired global position of the camera
+         */
+        WebXRExperienceHelper.prototype.setPositionOfCameraUsingContainer = function (position) {
+            this.camera.globalPosition.subtractToRef(position, WebXRExperienceHelper._TmpVector);
+            this.container.position.subtractInPlace(WebXRExperienceHelper._TmpVector);
+        };
+        /**
+         * Rotates the xr camera by rotating the camera's container around the camera's position
+         * This should be used instead of modifying the camera's rotation as it will be overwritten by an xrSessions's update frame
+         * @param rotation the desired quaternion rotation to apply to the camera
+         */
+        WebXRExperienceHelper.prototype.rotateCameraByQuaternionUsingContainer = function (rotation) {
+            if (!this.container.rotationQuaternion) {
+                this.container.rotationQuaternion = BABYLON.Quaternion.FromEulerVector(this.container.rotation);
+            }
+            this.container.rotationQuaternion.multiplyInPlace(rotation);
+            this.container.position.rotateByQuaternionAroundPointToRef(rotation, this.camera.globalPosition, this.container.position);
+        };
+        /**
          * Checks if the creation options are supported by the xr session
          * @param options creation options
          * @returns true if supported
@@ -108789,6 +108919,7 @@ var BABYLON;
             this.onStateChangedObservable.clear();
             this._sessionManager.dispose();
         };
+        WebXRExperienceHelper._TmpVector = new BABYLON.Vector3();
         return WebXRExperienceHelper;
     }());
     BABYLON.WebXRExperienceHelper = WebXRExperienceHelper;
@@ -108877,6 +109008,14 @@ var BABYLON;
             this.scene = scene;
             this._buttons = [];
             this._activeButton = null;
+            /**
+             * Fired every time the active button is changed.
+             *
+             * When xr is entered via a button that launches xr that button will be the callback parameter
+             *
+             * When exiting xr the callback parameter will be null)
+             */
+            this.activeButtonChangedObservable = new BABYLON.Observable();
             this._overlay = document.createElement("div");
             this._overlay.style.cssText = "z-index:11;position: absolute; right: 20px;bottom: 50px;";
             if (options.customButtons) {
@@ -108954,6 +109093,7 @@ var BABYLON;
                         }); };
                     }
                 });
+                return ui;
             });
         };
         WebXREnterExitUI.prototype._updateButtons = function (activeButton) {
@@ -108962,6 +109102,7 @@ var BABYLON;
             this._buttons.forEach(function (b) {
                 b.update(_this._activeButton);
             });
+            this.activeButtonChangedObservable.notifyObservers(this._activeButton);
         };
         /**
          * Disposes of the object
@@ -108971,6 +109112,7 @@ var BABYLON;
             if (renderCanvas && renderCanvas.parentNode && renderCanvas.parentNode.contains(this._overlay)) {
                 renderCanvas.parentNode.removeChild(this._overlay);
             }
+            this.activeButtonChangedObservable.clear();
         };
         return WebXREnterExitUI;
     }());

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

@@ -1710,6 +1710,13 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
+    /**
+      * Force-apply material configuration right after a material was loaded.
+      */
+    export class ApplyMaterialConfigPlugin implements ILoaderPlugin {
+        onInit(loader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync, model: ViewerModel): void;
+        onMaterialLoaded(material: BABYLON.Material): void;
+    }
 }
 declare module BabylonViewer {
     /**

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 11 - 3
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1010,8 +1010,7 @@ declare module 'babylonjs-viewer/initializer' {
 }
 
 declare module 'babylonjs-viewer/configuration' {
-    export * from 'babylonjs-viewer/configuration/configuration';
-    export * from 'babylonjs-viewer/configuration/interfaces';
+    
 }
 
 declare module 'babylonjs-viewer/configuration/configuration' {
@@ -1847,7 +1846,16 @@ declare module 'babylonjs-viewer/loader/plugins/msftLodLoaderPlugin' {
 }
 
 declare module 'babylonjs-viewer/loader/plugins/applyMaterialConfig' {
-    
+    import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, Material } from 'babylonjs';
+    import { ViewerModel } from 'babylonjs-viewer/model/viewerModel';
+    import { ILoaderPlugin } from 'babylonjs-viewer/loader/plugins/loaderPlugin';
+    /**
+      * Force-apply material configuration right after a material was loaded.
+      */
+    export class ApplyMaterialConfigPlugin implements ILoaderPlugin {
+        onInit(loader: ISceneLoaderPlugin | ISceneLoaderPluginAsync, model: ViewerModel): void;
+        onMaterialLoaded(material: Material): void;
+    }
 }
 
 declare module 'babylonjs-viewer/loader/plugins/extendedMaterialLoaderPlugin' {

+ 2 - 1
tests/validation/config.json

@@ -4,7 +4,8 @@
     {
       "title": "XR camera container rotation",
       "playgroundId": "#JV98QW#1",
-      "referenceImage": "xrCameraContainerRotation.png"
+      "referenceImage": "xrCameraContainerRotation.png",
+      "excludeFromAutomaticTesting": true
     },
     {
       "title": "Sliders",