Przeglądaj źródła

Merge branch 'master' into LinesMeshIntersection

Julien Barrois 6 lat temu
rodzic
commit
ff8682a82f
39 zmienionych plików z 22882 dodań i 21664 usunięć
  1. 10803 10690
      Playground/babylon.d.txt
  2. 2 1
      Tools/Gulp/config.json
  3. 10789 10676
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 277 56
      dist/preview release/babylon.max.js
  6. 277 56
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 279 58
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/glTF2Interface/package.json
  10. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  11. 2 2
      dist/preview release/gui/package.json
  12. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  13. 5 5
      dist/preview release/inspector/package.json
  14. 3 3
      dist/preview release/loaders/package.json
  15. 2 2
      dist/preview release/materialsLibrary/package.json
  16. 2 2
      dist/preview release/postProcessesLibrary/package.json
  17. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  18. 3 3
      dist/preview release/serializers/package.json
  19. 19 5
      dist/preview release/viewer/babylon.viewer.d.ts
  20. 2 2
      dist/preview release/viewer/babylon.viewer.js
  21. 3 3
      dist/preview release/viewer/babylon.viewer.max.js
  22. 22 5
      dist/preview release/viewer/babylon.viewer.module.d.ts
  23. 18 13
      dist/preview release/what's new.md
  24. 31 1
      gui/src/2D/controls/button.ts
  25. 1 1
      package.json
  26. 4 3
      src/Cameras/Inputs/babylon.arcRotateCameraMouseWheelInput.ts
  27. 1 1
      src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts
  28. 4 4
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  29. 53 2
      src/Cameras/XR/babylon.webXRCamera.ts
  30. 143 0
      src/Cameras/XR/babylon.webXRSessionManager.ts
  31. 4 3
      src/Cameras/babylon.camera.ts
  32. 17 4
      src/Engine/babylon.engine.ts
  33. 1 1
      src/Engine/babylon.nullEngine.ts
  34. 5 2
      src/Materials/Textures/babylon.internalTexture.ts
  35. 11 9
      src/Materials/Textures/babylon.renderTargetTexture.ts
  36. 21 4
      src/Math/babylon.math.ts
  37. 7 2
      src/babylon.assetContainer.ts
  38. 41 6
      src/babylon.mixins.ts
  39. 23 32
      src/babylon.scene.ts

Plik diff jest za duży
+ 10803 - 10690
Playground/babylon.d.txt


+ 2 - 1
Tools/Gulp/config.json

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

Plik diff jest za duży
+ 10789 - 10676
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 1 - 1
dist/preview release/babylon.js


+ 277 - 56
dist/preview release/babylon.max.js

@@ -7997,6 +7997,24 @@ var BABYLON;
             }
             return this;
         };
+        /**
+         * Toggles model matrix from being right handed to left handed in place and vice versa
+         */
+        Matrix.prototype.toggleModelMatrixHandInPlace = function () {
+            var _this = this;
+            [2, 6, 8, 9, 14].forEach(function (num) {
+                _this.m[num] *= -1;
+            });
+        };
+        /**
+         * Toggles projection matrix from being right handed to left handed in place and vice versa
+         */
+        Matrix.prototype.toggleProjectionMatrixHandInPlace = function () {
+            var _this = this;
+            [8, 9, 10, 11].forEach(function (num) {
+                _this.m[num] *= -1;
+            });
+        };
         // Statics
         /**
          * Creates a matrix from an array
@@ -10031,7 +10049,7 @@ var BABYLON;
         Tmp.Vector3 = BABYLON.Tools.BuildArray(13, Vector3.Zero); // 13 temp Vector3 at once should be enough
         Tmp.Vector4 = BABYLON.Tools.BuildArray(3, Vector4.Zero); // 3 temp Vector4 at once should be enough
         Tmp.Quaternion = BABYLON.Tools.BuildArray(2, Quaternion.Zero); // 2 temp Quaternion at once should be enough
-        Tmp.Matrix = BABYLON.Tools.BuildArray(6, Matrix.Identity); // 6 temp Matrices at once should be enough
+        Tmp.Matrix = BABYLON.Tools.BuildArray(8, Matrix.Identity); // 8 temp Matrices at once should be enough
         return Tmp;
     }());
     BABYLON.Tmp = Tmp;
@@ -10355,7 +10373,12 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.math.scalar.js.map
 
-
+var XRFrameOfReferenceType;
+(function (XRFrameOfReferenceType) {
+    XRFrameOfReferenceType[XRFrameOfReferenceType["head-model"] = 0] = "head-model";
+    XRFrameOfReferenceType[XRFrameOfReferenceType["eye-level"] = 1] = "eye-level";
+    XRFrameOfReferenceType[XRFrameOfReferenceType["stage"] = 2] = "stage";
+})(XRFrameOfReferenceType || (XRFrameOfReferenceType = {}));
 
 //# sourceMappingURL=babylon.mixins.js.map
 
@@ -12643,7 +12666,7 @@ var BABYLON;
             this._badOS = /iPad/i.test(navigator.userAgent) || /iPhone/i.test(navigator.userAgent);
             // Detect if we are running on a faulty buggy desktop OS.
             this._badDesktopOS = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
-            console.log("Babylon.js engine (v" + Engine.Version + ") launched");
+            console.log("Babylon.js v" + Engine.Version + " - " + this.description);
             this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
         }
         Object.defineProperty(Engine, "LastCreatedEngine", {
@@ -12694,7 +12717,21 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.1";
+                return "4.0.0-alpha.2";
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Engine.prototype, "description", {
+            /**
+             * Returns a string describing the current engine
+             */
+            get: function () {
+                var description = "WebGL" + this.webGLVersion;
+                if (this._caps.parallelShaderCompile) {
+                    description += " - Parallel shader compilation";
+                }
+                return description;
             },
             enumerable: true,
             configurable: true
@@ -23466,7 +23503,7 @@ var BABYLON;
              */
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
             /**
-             * Defines the list of custom render target the camera should render to.
+             * Defines the list of custom render target which are rendered to and then used as the input to this camera's render. Eg. display another camera view on a TV in the main scene
              * This is pretty helpfull if you wish to make a camera render to a texture you could reuse somewhere
              * else in the scene.
              */
@@ -23474,7 +23511,7 @@ var BABYLON;
             /**
              * When set, the camera will render to this render target instead of the default canvas
              */
-            _this.customDefaultRenderTarget = null;
+            _this.outputRenderTarget = null;
             /**
              * Observable triggered when the camera view matrix has changed.
              */
@@ -23503,6 +23540,7 @@ var BABYLON;
             /** @hidden */
             _this._activeMeshes = new BABYLON.SmartArray(256);
             _this._globalPosition = BABYLON.Vector3.Zero();
+            /** hidden */
             _this._computedViewMatrix = BABYLON.Matrix.Identity();
             _this._doNotComputeProjectionMatrix = false;
             _this._transformMatrix = BABYLON.Matrix.Zero();
@@ -25777,6 +25815,7 @@ var BABYLON;
             _this._transformMatrix = BABYLON.Matrix.Zero();
             _this._useAlternateCameraConfiguration = false;
             _this._alternateRendering = false;
+            _this._wheelEventName = "";
             /**
              * Gets or sets a boolean indicating if lights must be sorted by priority (off by default)
              * This is useful if there are more lights that the maximum simulteanous authorized
@@ -26705,7 +26744,7 @@ var BABYLON;
                 pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
             }
             if (pickResult) {
-                var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                var type = evt.type === this._wheelEventName ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
                 if (this.onPointerMove) {
                     this.onPointerMove(evt, pickResult, type);
                 }
@@ -26808,8 +26847,6 @@ var BABYLON;
         Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit) {
             var evt = new PointerEvent("pointerup", pointerEventInit);
             var clickInfo = new ClickInfo();
-            clickInfo.singleClick = true;
-            clickInfo.ignore = true;
             if (this._checkPrePointerObservable(pickResult, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -26857,27 +26894,17 @@ var BABYLON;
             }
             var type = BABYLON.PointerEventTypes.POINTERUP;
             if (this.onPointerObservable.hasObservers()) {
-                if (!clickInfo.ignore) {
-                    if (!clickInfo.hasSwiped) {
-                        if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
-                            var type_2 = BABYLON.PointerEventTypes.POINTERTAP;
-                            var pi = new BABYLON.PointerInfo(type_2, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type_2);
-                        }
-                        if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
-                            var type_3 = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
-                            var pi = new BABYLON.PointerInfo(type_3, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type_3);
-                        }
+                if (!clickInfo.ignore && !clickInfo.hasSwiped) {
+                    if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                        type = BABYLON.PointerEventTypes.POINTERTAP;
+                    }
+                    else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                        type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
                     }
                 }
-                else {
-                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
-                    this._setRayOnPointerInfo(pi);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
+                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                this.onPointerObservable.notifyObservers(pi, type);
             }
             if (this.onPointerUp && !clickInfo.ignore) {
                 this.onPointerUp(evt, pickResult, type);
@@ -26943,7 +26970,6 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
-                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -27035,7 +27061,7 @@ var BABYLON;
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
                 // PreObservable support
-                if (_this._checkPrePointerObservable(null, evt, evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE)) {
+                if (_this._checkPrePointerObservable(null, evt, evt.type === _this._wheelEventName ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE)) {
                     return;
                 }
                 if (!_this.cameraToUseForPointers && !_this.activeCamera) {
@@ -27190,8 +27216,10 @@ var BABYLON;
             if (attachMove) {
                 canvas.addEventListener(eventPrefix + "move", this._onPointerMove, false);
                 // Wheel
-                canvas.addEventListener('mousewheel', this._onPointerMove, false);
-                canvas.addEventListener('DOMMouseScroll', this._onPointerMove, false);
+                this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
+                    document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
+                        "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
+                canvas.addEventListener(this._wheelEventName, this._onPointerMove, false);
             }
             if (attachDown) {
                 canvas.addEventListener(eventPrefix + "down", this._onPointerDown, false);
@@ -27219,8 +27247,7 @@ var BABYLON;
                 engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
             }
             // Wheel
-            canvas.removeEventListener('mousewheel', this._onPointerMove);
-            canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
+            canvas.removeEventListener(this._wheelEventName, this._onPointerMove);
             // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keyup", this._onKeyUp);
@@ -29100,8 +29127,8 @@ var BABYLON;
                     step.action(this.activeCamera);
                 }
                 this._intermediateRendering = false;
-                if (this.activeCamera.customDefaultRenderTarget) {
-                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                if (this.activeCamera.outputRenderTarget) {
+                    var internalTexture = this.activeCamera.outputRenderTarget.getInternalTexture();
                     if (internalTexture) {
                         engine.bindFramebuffer(internalTexture);
                     }
@@ -30097,6 +30124,11 @@ var BABYLON;
         function AssetContainer(scene) {
             var _this = _super.call(this) || this;
             _this.scene = scene;
+            _this["sounds"] = [];
+            _this["effectLayers"] = [];
+            _this["layers"] = [];
+            _this["lensFlareSystems"] = [];
+            _this["proceduralTextures"] = [];
             return _this;
         }
         /**
@@ -30145,7 +30177,7 @@ var BABYLON;
             });
             for (var _i = 0, _a = this.scene._serializableComponents; _i < _a.length; _i++) {
                 var component = _a[_i];
-                component.addFromContainer(this.scene);
+                component.addFromContainer(this);
             }
         };
         /**
@@ -30194,7 +30226,7 @@ var BABYLON;
             });
             for (var _i = 0, _a = this.scene._serializableComponents; _i < _a.length; _i++) {
                 var component = _a[_i];
-                component.removeFromContainer(this.scene);
+                component.removeFromContainer(this);
             }
         };
         AssetContainer.prototype._moveAssets = function (sourceAssets, targetAssets, keepAssets) {
@@ -30874,8 +30906,10 @@ var BABYLON;
          * Creates a new InternalTexture
          * @param engine defines the engine to use
          * @param dataSource defines the type of data that will be used
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        function InternalTexture(engine, dataSource) {
+        function InternalTexture(engine, dataSource, delayAllocation) {
+            if (delayAllocation === void 0) { delayAllocation = false; }
             /**
              * Observable called when the texture is loaded
              */
@@ -30909,7 +30943,9 @@ var BABYLON;
             this._references = 1;
             this._engine = engine;
             this._dataSource = dataSource;
-            this._webGLTexture = engine._createTexture();
+            if (!delayAllocation) {
+                this._webGLTexture = engine._createTexture();
+            }
         }
         /**
          * Gets the Engine the texture belongs to.
@@ -36569,7 +36605,7 @@ var BABYLON;
             if (!doNotAdd) {
                 this._scene.addMaterial(this);
             }
-            if (scene.useMaterialMeshMap) {
+            if (this._scene.useMaterialMeshMap) {
                 this.meshMap = {};
             }
         }
@@ -50725,8 +50761,8 @@ var BABYLON;
                         delta = event.wheelDelta / (_this.wheelPrecision * 40);
                     }
                 }
-                else if (event.detail) {
-                    delta = -event.detail / _this.wheelPrecision;
+                else if (event.detail || event.deltaY) {
+                    delta = -(event.detail || event.deltaY) / _this.wheelPrecision;
                 }
                 if (delta) {
                     _this.camera.inertialRadiusOffset += delta;
@@ -73387,8 +73423,9 @@ var BABYLON;
          * @param generateStencilBuffer True to generate a stencil buffer
          * @param isMulti True if multiple textures need to be created (Draw Buffers)
          * @param format The internal format of the buffer in the RTT (RED, RG, RGB, RGBA, ALPHA...)
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        function RenderTargetTexture(name, size, scene, generateMipMaps, doNotChangeAspectRatio, type, isCube, samplingMode, generateDepthBuffer, generateStencilBuffer, isMulti, format) {
+        function RenderTargetTexture(name, size, scene, generateMipMaps, doNotChangeAspectRatio, type, isCube, samplingMode, generateDepthBuffer, generateStencilBuffer, isMulti, format, delayAllocation) {
             if (doNotChangeAspectRatio === void 0) { doNotChangeAspectRatio = true; }
             if (type === void 0) { type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (isCube === void 0) { isCube = false; }
@@ -73397,6 +73434,7 @@ var BABYLON;
             if (generateStencilBuffer === void 0) { generateStencilBuffer = false; }
             if (isMulti === void 0) { isMulti = false; }
             if (format === void 0) { format = BABYLON.Engine.TEXTUREFORMAT_RGBA; }
+            if (delayAllocation === void 0) { delayAllocation = false; }
             var _this = _super.call(this, null, scene, !generateMipMaps) || this;
             _this.isCube = isCube;
             /**
@@ -73475,13 +73513,15 @@ var BABYLON;
                 _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
                 _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             }
-            if (isCube) {
-                _this._texture = scene.getEngine().createRenderTargetCubeTexture(_this.getRenderSize(), _this._renderTargetOptions);
-                _this.coordinatesMode = BABYLON.Texture.INVCUBIC_MODE;
-                _this._textureMatrix = BABYLON.Matrix.Identity();
-            }
-            else {
-                _this._texture = scene.getEngine().createRenderTargetTexture(_this._size, _this._renderTargetOptions);
+            if (!delayAllocation) {
+                if (isCube) {
+                    _this._texture = scene.getEngine().createRenderTargetCubeTexture(_this.getRenderSize(), _this._renderTargetOptions);
+                    _this.coordinatesMode = BABYLON.Texture.INVCUBIC_MODE;
+                    _this._textureMatrix = BABYLON.Matrix.Identity();
+                }
+                else {
+                    _this._texture = scene.getEngine().createRenderTargetTexture(_this._size, _this._renderTargetOptions);
+                }
             }
             return _this;
         }
@@ -73871,7 +73911,7 @@ var BABYLON;
             // Is predicate defined?
             if (this.renderListPredicate) {
                 if (this.renderList) {
-                    this.renderList.splice(0); // Clear previous renderList
+                    this.renderList.length = 0; // Clear previous renderList
                 }
                 else {
                     this.renderList = [];
@@ -105553,7 +105593,7 @@ var BABYLON;
             this._beta = 0;
             this._gamma = 0;
             this._orientationChanged = function () {
-                _this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && window.screen.orientation['angle'] ? window.screen.orientation.angle : 0));
+                _this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && (window.screen.orientation)['angle'] ? (window.screen.orientation).angle : 0));
                 _this._screenOrientationAngle = -BABYLON.Tools.ToRadians(_this._screenOrientationAngle / 2);
                 _this._screenQuaternion.copyFromFloats(0, Math.sin(_this._screenOrientationAngle), 0, Math.cos(_this._screenOrientationAngle));
             };
@@ -108395,11 +108435,57 @@ var BABYLON;
             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[0].outputRenderTarget = 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;
+            this.rigCameras[1].outputRenderTarget = null;
+        };
+        /**
+         * Updates the cameras position from the current pose information of the  XR session
+         * @param xrSessionManager the session containing pose information
+         */
+        WebXRCamera.prototype.updateFromXRSessionManager = function (xrSessionManager) {
+            var _this = this;
+            // Ensure all frame data is available
+            if (!xrSessionManager._currentXRFrame || !xrSessionManager._currentXRFrame.getDevicePose) {
+                return;
+            }
+            var pose = xrSessionManager._currentXRFrame.getDevicePose(xrSessionManager._frameOfReference);
+            if (!pose || !pose.poseModelMatrix) {
+                return;
+            }
+            // Update the parent cameras matrix
+            BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.poseModelMatrix, 0, 1, WebXRCamera._TmpMatrix);
+            if (!this._scene.useRightHandedSystem) {
+                WebXRCamera._TmpMatrix.toggleModelMatrixHandInPlace();
+            }
+            WebXRCamera._TmpMatrix.getTranslationToRef(this.position);
+            WebXRCamera._TmpMatrix.getRotationMatrixToRef(WebXRCamera._TmpMatrix);
+            BABYLON.Quaternion.FromRotationMatrixToRef(WebXRCamera._TmpMatrix, this.rotationQuaternion);
+            this.computeWorldMatrix();
+            // Update camera rigs
+            this._updateNumberOfRigCameras(xrSessionManager._currentXRFrame.views.length);
+            xrSessionManager._currentXRFrame.views.forEach(function (view, i) {
+                // Update view/projection matrix
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.getViewMatrix(view), 0, 1, _this.rigCameras[i]._computedViewMatrix);
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(view.projectionMatrix, 0, 1, _this.rigCameras[i]._projectionMatrix);
+                if (!_this._scene.useRightHandedSystem) {
+                    _this.rigCameras[i]._computedViewMatrix.toggleModelMatrixHandInPlace();
+                    _this.rigCameras[i]._projectionMatrix.toggleProjectionMatrixHandInPlace();
+                }
+                // Update viewport
+                var viewport = xrSessionManager._xrSession.baseLayer.getViewport(view);
+                var width = xrSessionManager._xrSession.baseLayer.framebufferWidth;
+                var height = xrSessionManager._xrSession.baseLayer.framebufferHeight;
+                _this.rigCameras[i].viewport.width = viewport.width / width;
+                _this.rigCameras[i].viewport.height = viewport.height / height;
+                _this.rigCameras[i].viewport.x = viewport.x / width;
+                _this.rigCameras[i].viewport.y = viewport.y / height;
+                // Set cameras to render to the session's render target
+                _this.rigCameras[i].outputRenderTarget = xrSessionManager._sessionRenderTargetTexture;
+            });
         };
+        WebXRCamera._TmpMatrix = new BABYLON.Matrix();
         return WebXRCamera;
     }(BABYLON.FreeCamera));
     BABYLON.WebXRCamera = WebXRCamera;
@@ -108407,6 +108493,141 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.webXRCamera.js.map
 
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Manages an XRSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    var WebXRSessionManager = /** @class */ (function () {
+        /**
+         * Constructs a WebXRSessionManager, this must be initialized within a user action before usage
+         * @param scene The scene which the session should be created for
+         */
+        function WebXRSessionManager(scene) {
+            this.scene = scene;
+            this._tmpMatrix = new BABYLON.Matrix();
+        }
+        /**
+         * Initializes the manager, this must be done with a user action (eg. button click event)
+         * After initialization enterXR can be called to start an XR session
+         * @returns Promise which resolves after it is initialized
+         */
+        WebXRSessionManager.prototype.initialize = function () {
+            var _this = this;
+            // Check if the browser supports webXR
+            this._xrNavigator = navigator;
+            if (!this._xrNavigator.xr) {
+                return Promise.reject("webXR not supported by this browser");
+            }
+            // Request the webXR device
+            return this._xrNavigator.xr.requestDevice().then(function (device) {
+                _this._xrDevice = device;
+                return _this.scene.getEngine()._gl.setCompatibleXRDevice(_this._xrDevice);
+            });
+        };
+        /**
+         * Enters XR with the desired XR session options
+         * @param sessionCreationOptions xr options to create the session with
+         * @param frameOfReferenceType option to configure how the xr pose is expressed
+         * @returns Promise which resolves after it enters XR
+         */
+        WebXRSessionManager.prototype.enterXR = function (sessionCreationOptions, frameOfReferenceType) {
+            var _this = this;
+            // initialize session
+            return this._xrDevice.requestSession(sessionCreationOptions).then(function (session) {
+                _this._xrSession = session;
+                _this._xrSession.baseLayer = new XRWebGLLayer(_this._xrSession, _this.scene.getEngine()._gl);
+                return _this._xrSession.requestFrameOfReference(frameOfReferenceType);
+            }).then(function (frameOfRef) {
+                _this._frameOfReference = frameOfRef;
+                // Tell the engine's render loop to be driven by the xr session's refresh rate and provide xr pose information
+                _this.scene.getEngine().customAnimationFrameRequester = {
+                    requestAnimationFrame: _this._xrSession.requestAnimationFrame.bind(_this._xrSession),
+                    renderFunction: function (timestamp, xrFrame) {
+                        // Store the XR frame in the manager to be consumed by the XR camera to update pose
+                        _this._currentXRFrame = xrFrame;
+                        _this.scene.getEngine()._renderLoop();
+                    }
+                };
+                // Create render target texture from xr's webgl render target
+                _this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(_this._xrSession, _this.scene);
+            });
+        };
+        /**
+         * Stops the xrSession and restores the renderloop
+         * @returns Promise which resolves after it exits XR
+         */
+        WebXRSessionManager.prototype.exitXR = function () {
+            var _this = this;
+            return new Promise(function (res) {
+                _this.scene.getEngine().customAnimationFrameRequester = null;
+                _this._xrSession.end();
+                // Restore frame buffer to avoid clear on xr framebuffer after session end
+                _this.scene.getEngine().restoreDefaultFramebuffer();
+                // Need to restart render loop as after calling session.end the last request for new frame will never call callback
+                _this.scene.getEngine()._renderLoop();
+                res();
+            });
+        };
+        /**
+         * Fires a ray and returns the closest hit in the xr sessions enviornment, useful to place objects in AR
+         * @param ray ray to cast into the environment
+         * @returns Promise which resolves with a collision point in the environment if it exists
+         */
+        WebXRSessionManager.prototype.environmentPointHitTest = function (ray) {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                // Compute left handed inputs to request hit test
+                var origin = new Float32Array([ray.origin.x, ray.origin.y, ray.origin.z]);
+                var direction = new Float32Array([ray.direction.x, ray.direction.y, ray.direction.z]);
+                if (!_this.scene.useRightHandedSystem) {
+                    origin[2] *= -1;
+                    direction[2] *= -1;
+                }
+                // Fire hittest
+                _this._xrSession.requestHitTest(origin, direction, _this._frameOfReference)
+                    .then(function (hits) {
+                    if (hits.length > 0) {
+                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(hits[0].hitMatrix, 0, 1.0, _this._tmpMatrix);
+                        var hitPoint = _this._tmpMatrix.getTranslation();
+                        if (!_this.scene.useRightHandedSystem) {
+                            hitPoint.z *= -1;
+                        }
+                        res(hitPoint);
+                    }
+                    else {
+                        res(null);
+                    }
+                }).catch(function (e) {
+                    res(null);
+                });
+            });
+        };
+        /**
+         * @hidden
+         * Converts the render layer of xrSession to a render target
+         * @param session session to create render target for
+         * @param scene scene the new render target should be created for
+         */
+        WebXRSessionManager._CreateRenderTargetTextureFromSession = function (session, scene) {
+            // Create internal texture
+            var internalTexture = new BABYLON.InternalTexture(scene.getEngine(), BABYLON.InternalTexture.DATASOURCE_UNKNOWN, true);
+            internalTexture.width = session.baseLayer.framebufferWidth;
+            internalTexture.height = session.baseLayer.framebufferHeight;
+            internalTexture._framebuffer = session.baseLayer.framebuffer;
+            // Create render target texture from the internal texture
+            var renderTargetTexture = new BABYLON.RenderTargetTexture("XR renderTargetTexture", { width: internalTexture.width, height: internalTexture.height }, scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
+            renderTargetTexture._texture = internalTexture;
+            return renderTargetTexture;
+        };
+        return WebXRSessionManager;
+    }());
+    BABYLON.WebXRSessionManager = WebXRSessionManager;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.webXRSessionManager.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/
@@ -115550,7 +115771,7 @@ var BABYLON;
             _this._caps.depthTextureExtension = false;
             _this._caps.vertexArrayObject = false;
             _this._caps.instancedArrays = false;
-            BABYLON.Tools.Log("Babylon.js null engine (v" + BABYLON.Engine.Version + ") launched");
+            BABYLON.Tools.Log("Babylon.js v" + BABYLON.Engine.Version + " - Null engine");
             // Wrappers
             if (typeof URL === "undefined") {
                 URL = {

+ 277 - 56
dist/preview release/babylon.no-module.max.js

@@ -7964,6 +7964,24 @@ var BABYLON;
             }
             return this;
         };
+        /**
+         * Toggles model matrix from being right handed to left handed in place and vice versa
+         */
+        Matrix.prototype.toggleModelMatrixHandInPlace = function () {
+            var _this = this;
+            [2, 6, 8, 9, 14].forEach(function (num) {
+                _this.m[num] *= -1;
+            });
+        };
+        /**
+         * Toggles projection matrix from being right handed to left handed in place and vice versa
+         */
+        Matrix.prototype.toggleProjectionMatrixHandInPlace = function () {
+            var _this = this;
+            [8, 9, 10, 11].forEach(function (num) {
+                _this.m[num] *= -1;
+            });
+        };
         // Statics
         /**
          * Creates a matrix from an array
@@ -9998,7 +10016,7 @@ var BABYLON;
         Tmp.Vector3 = BABYLON.Tools.BuildArray(13, Vector3.Zero); // 13 temp Vector3 at once should be enough
         Tmp.Vector4 = BABYLON.Tools.BuildArray(3, Vector4.Zero); // 3 temp Vector4 at once should be enough
         Tmp.Quaternion = BABYLON.Tools.BuildArray(2, Quaternion.Zero); // 2 temp Quaternion at once should be enough
-        Tmp.Matrix = BABYLON.Tools.BuildArray(6, Matrix.Identity); // 6 temp Matrices at once should be enough
+        Tmp.Matrix = BABYLON.Tools.BuildArray(8, Matrix.Identity); // 8 temp Matrices at once should be enough
         return Tmp;
     }());
     BABYLON.Tmp = Tmp;
@@ -10322,7 +10340,12 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.math.scalar.js.map
 
-
+var XRFrameOfReferenceType;
+(function (XRFrameOfReferenceType) {
+    XRFrameOfReferenceType[XRFrameOfReferenceType["head-model"] = 0] = "head-model";
+    XRFrameOfReferenceType[XRFrameOfReferenceType["eye-level"] = 1] = "eye-level";
+    XRFrameOfReferenceType[XRFrameOfReferenceType["stage"] = 2] = "stage";
+})(XRFrameOfReferenceType || (XRFrameOfReferenceType = {}));
 
 //# sourceMappingURL=babylon.mixins.js.map
 
@@ -12610,7 +12633,7 @@ var BABYLON;
             this._badOS = /iPad/i.test(navigator.userAgent) || /iPhone/i.test(navigator.userAgent);
             // Detect if we are running on a faulty buggy desktop OS.
             this._badDesktopOS = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
-            console.log("Babylon.js engine (v" + Engine.Version + ") launched");
+            console.log("Babylon.js v" + Engine.Version + " - " + this.description);
             this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
         }
         Object.defineProperty(Engine, "LastCreatedEngine", {
@@ -12661,7 +12684,21 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "4.0.0-alpha.1";
+                return "4.0.0-alpha.2";
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Engine.prototype, "description", {
+            /**
+             * Returns a string describing the current engine
+             */
+            get: function () {
+                var description = "WebGL" + this.webGLVersion;
+                if (this._caps.parallelShaderCompile) {
+                    description += " - Parallel shader compilation";
+                }
+                return description;
             },
             enumerable: true,
             configurable: true
@@ -23433,7 +23470,7 @@ var BABYLON;
              */
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
             /**
-             * Defines the list of custom render target the camera should render to.
+             * Defines the list of custom render target which are rendered to and then used as the input to this camera's render. Eg. display another camera view on a TV in the main scene
              * This is pretty helpfull if you wish to make a camera render to a texture you could reuse somewhere
              * else in the scene.
              */
@@ -23441,7 +23478,7 @@ var BABYLON;
             /**
              * When set, the camera will render to this render target instead of the default canvas
              */
-            _this.customDefaultRenderTarget = null;
+            _this.outputRenderTarget = null;
             /**
              * Observable triggered when the camera view matrix has changed.
              */
@@ -23470,6 +23507,7 @@ var BABYLON;
             /** @hidden */
             _this._activeMeshes = new BABYLON.SmartArray(256);
             _this._globalPosition = BABYLON.Vector3.Zero();
+            /** hidden */
             _this._computedViewMatrix = BABYLON.Matrix.Identity();
             _this._doNotComputeProjectionMatrix = false;
             _this._transformMatrix = BABYLON.Matrix.Zero();
@@ -25744,6 +25782,7 @@ var BABYLON;
             _this._transformMatrix = BABYLON.Matrix.Zero();
             _this._useAlternateCameraConfiguration = false;
             _this._alternateRendering = false;
+            _this._wheelEventName = "";
             /**
              * Gets or sets a boolean indicating if lights must be sorted by priority (off by default)
              * This is useful if there are more lights that the maximum simulteanous authorized
@@ -26672,7 +26711,7 @@ var BABYLON;
                 pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
             }
             if (pickResult) {
-                var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                var type = evt.type === this._wheelEventName ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
                 if (this.onPointerMove) {
                     this.onPointerMove(evt, pickResult, type);
                 }
@@ -26775,8 +26814,6 @@ var BABYLON;
         Scene.prototype.simulatePointerUp = function (pickResult, pointerEventInit) {
             var evt = new PointerEvent("pointerup", pointerEventInit);
             var clickInfo = new ClickInfo();
-            clickInfo.singleClick = true;
-            clickInfo.ignore = true;
             if (this._checkPrePointerObservable(pickResult, evt, BABYLON.PointerEventTypes.POINTERUP)) {
                 return this;
             }
@@ -26824,27 +26861,17 @@ var BABYLON;
             }
             var type = BABYLON.PointerEventTypes.POINTERUP;
             if (this.onPointerObservable.hasObservers()) {
-                if (!clickInfo.ignore) {
-                    if (!clickInfo.hasSwiped) {
-                        if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
-                            var type_2 = BABYLON.PointerEventTypes.POINTERTAP;
-                            var pi = new BABYLON.PointerInfo(type_2, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type_2);
-                        }
-                        if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
-                            var type_3 = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
-                            var pi = new BABYLON.PointerInfo(type_3, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type_3);
-                        }
+                if (!clickInfo.ignore && !clickInfo.hasSwiped) {
+                    if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                        type = BABYLON.PointerEventTypes.POINTERTAP;
+                    }
+                    else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                        type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
                     }
                 }
-                else {
-                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
-                    this._setRayOnPointerInfo(pi);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
+                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                this.onPointerObservable.notifyObservers(pi, type);
             }
             if (this.onPointerUp && !clickInfo.ignore) {
                 this.onPointerUp(evt, pickResult, type);
@@ -26910,7 +26937,6 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
-                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -27002,7 +27028,7 @@ var BABYLON;
             this._onPointerMove = function (evt) {
                 _this._updatePointerPosition(evt);
                 // PreObservable support
-                if (_this._checkPrePointerObservable(null, evt, evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE)) {
+                if (_this._checkPrePointerObservable(null, evt, evt.type === _this._wheelEventName ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE)) {
                     return;
                 }
                 if (!_this.cameraToUseForPointers && !_this.activeCamera) {
@@ -27157,8 +27183,10 @@ var BABYLON;
             if (attachMove) {
                 canvas.addEventListener(eventPrefix + "move", this._onPointerMove, false);
                 // Wheel
-                canvas.addEventListener('mousewheel', this._onPointerMove, false);
-                canvas.addEventListener('DOMMouseScroll', this._onPointerMove, false);
+                this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
+                    document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
+                        "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
+                canvas.addEventListener(this._wheelEventName, this._onPointerMove, false);
             }
             if (attachDown) {
                 canvas.addEventListener(eventPrefix + "down", this._onPointerDown, false);
@@ -27186,8 +27214,7 @@ var BABYLON;
                 engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
             }
             // Wheel
-            canvas.removeEventListener('mousewheel', this._onPointerMove);
-            canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
+            canvas.removeEventListener(this._wheelEventName, this._onPointerMove);
             // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keyup", this._onKeyUp);
@@ -29067,8 +29094,8 @@ var BABYLON;
                     step.action(this.activeCamera);
                 }
                 this._intermediateRendering = false;
-                if (this.activeCamera.customDefaultRenderTarget) {
-                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                if (this.activeCamera.outputRenderTarget) {
+                    var internalTexture = this.activeCamera.outputRenderTarget.getInternalTexture();
                     if (internalTexture) {
                         engine.bindFramebuffer(internalTexture);
                     }
@@ -30064,6 +30091,11 @@ var BABYLON;
         function AssetContainer(scene) {
             var _this = _super.call(this) || this;
             _this.scene = scene;
+            _this["sounds"] = [];
+            _this["effectLayers"] = [];
+            _this["layers"] = [];
+            _this["lensFlareSystems"] = [];
+            _this["proceduralTextures"] = [];
             return _this;
         }
         /**
@@ -30112,7 +30144,7 @@ var BABYLON;
             });
             for (var _i = 0, _a = this.scene._serializableComponents; _i < _a.length; _i++) {
                 var component = _a[_i];
-                component.addFromContainer(this.scene);
+                component.addFromContainer(this);
             }
         };
         /**
@@ -30161,7 +30193,7 @@ var BABYLON;
             });
             for (var _i = 0, _a = this.scene._serializableComponents; _i < _a.length; _i++) {
                 var component = _a[_i];
-                component.removeFromContainer(this.scene);
+                component.removeFromContainer(this);
             }
         };
         AssetContainer.prototype._moveAssets = function (sourceAssets, targetAssets, keepAssets) {
@@ -30841,8 +30873,10 @@ var BABYLON;
          * Creates a new InternalTexture
          * @param engine defines the engine to use
          * @param dataSource defines the type of data that will be used
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        function InternalTexture(engine, dataSource) {
+        function InternalTexture(engine, dataSource, delayAllocation) {
+            if (delayAllocation === void 0) { delayAllocation = false; }
             /**
              * Observable called when the texture is loaded
              */
@@ -30876,7 +30910,9 @@ var BABYLON;
             this._references = 1;
             this._engine = engine;
             this._dataSource = dataSource;
-            this._webGLTexture = engine._createTexture();
+            if (!delayAllocation) {
+                this._webGLTexture = engine._createTexture();
+            }
         }
         /**
          * Gets the Engine the texture belongs to.
@@ -36536,7 +36572,7 @@ var BABYLON;
             if (!doNotAdd) {
                 this._scene.addMaterial(this);
             }
-            if (scene.useMaterialMeshMap) {
+            if (this._scene.useMaterialMeshMap) {
                 this.meshMap = {};
             }
         }
@@ -50692,8 +50728,8 @@ var BABYLON;
                         delta = event.wheelDelta / (_this.wheelPrecision * 40);
                     }
                 }
-                else if (event.detail) {
-                    delta = -event.detail / _this.wheelPrecision;
+                else if (event.detail || event.deltaY) {
+                    delta = -(event.detail || event.deltaY) / _this.wheelPrecision;
                 }
                 if (delta) {
                     _this.camera.inertialRadiusOffset += delta;
@@ -73354,8 +73390,9 @@ var BABYLON;
          * @param generateStencilBuffer True to generate a stencil buffer
          * @param isMulti True if multiple textures need to be created (Draw Buffers)
          * @param format The internal format of the buffer in the RTT (RED, RG, RGB, RGBA, ALPHA...)
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        function RenderTargetTexture(name, size, scene, generateMipMaps, doNotChangeAspectRatio, type, isCube, samplingMode, generateDepthBuffer, generateStencilBuffer, isMulti, format) {
+        function RenderTargetTexture(name, size, scene, generateMipMaps, doNotChangeAspectRatio, type, isCube, samplingMode, generateDepthBuffer, generateStencilBuffer, isMulti, format, delayAllocation) {
             if (doNotChangeAspectRatio === void 0) { doNotChangeAspectRatio = true; }
             if (type === void 0) { type = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT; }
             if (isCube === void 0) { isCube = false; }
@@ -73364,6 +73401,7 @@ var BABYLON;
             if (generateStencilBuffer === void 0) { generateStencilBuffer = false; }
             if (isMulti === void 0) { isMulti = false; }
             if (format === void 0) { format = BABYLON.Engine.TEXTUREFORMAT_RGBA; }
+            if (delayAllocation === void 0) { delayAllocation = false; }
             var _this = _super.call(this, null, scene, !generateMipMaps) || this;
             _this.isCube = isCube;
             /**
@@ -73442,13 +73480,15 @@ var BABYLON;
                 _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
                 _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             }
-            if (isCube) {
-                _this._texture = scene.getEngine().createRenderTargetCubeTexture(_this.getRenderSize(), _this._renderTargetOptions);
-                _this.coordinatesMode = BABYLON.Texture.INVCUBIC_MODE;
-                _this._textureMatrix = BABYLON.Matrix.Identity();
-            }
-            else {
-                _this._texture = scene.getEngine().createRenderTargetTexture(_this._size, _this._renderTargetOptions);
+            if (!delayAllocation) {
+                if (isCube) {
+                    _this._texture = scene.getEngine().createRenderTargetCubeTexture(_this.getRenderSize(), _this._renderTargetOptions);
+                    _this.coordinatesMode = BABYLON.Texture.INVCUBIC_MODE;
+                    _this._textureMatrix = BABYLON.Matrix.Identity();
+                }
+                else {
+                    _this._texture = scene.getEngine().createRenderTargetTexture(_this._size, _this._renderTargetOptions);
+                }
             }
             return _this;
         }
@@ -73838,7 +73878,7 @@ var BABYLON;
             // Is predicate defined?
             if (this.renderListPredicate) {
                 if (this.renderList) {
-                    this.renderList.splice(0); // Clear previous renderList
+                    this.renderList.length = 0; // Clear previous renderList
                 }
                 else {
                     this.renderList = [];
@@ -105520,7 +105560,7 @@ var BABYLON;
             this._beta = 0;
             this._gamma = 0;
             this._orientationChanged = function () {
-                _this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && window.screen.orientation['angle'] ? window.screen.orientation.angle : 0));
+                _this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && (window.screen.orientation)['angle'] ? (window.screen.orientation).angle : 0));
                 _this._screenOrientationAngle = -BABYLON.Tools.ToRadians(_this._screenOrientationAngle / 2);
                 _this._screenQuaternion.copyFromFloats(0, Math.sin(_this._screenOrientationAngle), 0, Math.cos(_this._screenOrientationAngle));
             };
@@ -108362,11 +108402,57 @@ var BABYLON;
             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[0].outputRenderTarget = 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;
+            this.rigCameras[1].outputRenderTarget = null;
+        };
+        /**
+         * Updates the cameras position from the current pose information of the  XR session
+         * @param xrSessionManager the session containing pose information
+         */
+        WebXRCamera.prototype.updateFromXRSessionManager = function (xrSessionManager) {
+            var _this = this;
+            // Ensure all frame data is available
+            if (!xrSessionManager._currentXRFrame || !xrSessionManager._currentXRFrame.getDevicePose) {
+                return;
+            }
+            var pose = xrSessionManager._currentXRFrame.getDevicePose(xrSessionManager._frameOfReference);
+            if (!pose || !pose.poseModelMatrix) {
+                return;
+            }
+            // Update the parent cameras matrix
+            BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.poseModelMatrix, 0, 1, WebXRCamera._TmpMatrix);
+            if (!this._scene.useRightHandedSystem) {
+                WebXRCamera._TmpMatrix.toggleModelMatrixHandInPlace();
+            }
+            WebXRCamera._TmpMatrix.getTranslationToRef(this.position);
+            WebXRCamera._TmpMatrix.getRotationMatrixToRef(WebXRCamera._TmpMatrix);
+            BABYLON.Quaternion.FromRotationMatrixToRef(WebXRCamera._TmpMatrix, this.rotationQuaternion);
+            this.computeWorldMatrix();
+            // Update camera rigs
+            this._updateNumberOfRigCameras(xrSessionManager._currentXRFrame.views.length);
+            xrSessionManager._currentXRFrame.views.forEach(function (view, i) {
+                // Update view/projection matrix
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.getViewMatrix(view), 0, 1, _this.rigCameras[i]._computedViewMatrix);
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(view.projectionMatrix, 0, 1, _this.rigCameras[i]._projectionMatrix);
+                if (!_this._scene.useRightHandedSystem) {
+                    _this.rigCameras[i]._computedViewMatrix.toggleModelMatrixHandInPlace();
+                    _this.rigCameras[i]._projectionMatrix.toggleProjectionMatrixHandInPlace();
+                }
+                // Update viewport
+                var viewport = xrSessionManager._xrSession.baseLayer.getViewport(view);
+                var width = xrSessionManager._xrSession.baseLayer.framebufferWidth;
+                var height = xrSessionManager._xrSession.baseLayer.framebufferHeight;
+                _this.rigCameras[i].viewport.width = viewport.width / width;
+                _this.rigCameras[i].viewport.height = viewport.height / height;
+                _this.rigCameras[i].viewport.x = viewport.x / width;
+                _this.rigCameras[i].viewport.y = viewport.y / height;
+                // Set cameras to render to the session's render target
+                _this.rigCameras[i].outputRenderTarget = xrSessionManager._sessionRenderTargetTexture;
+            });
         };
+        WebXRCamera._TmpMatrix = new BABYLON.Matrix();
         return WebXRCamera;
     }(BABYLON.FreeCamera));
     BABYLON.WebXRCamera = WebXRCamera;
@@ -108374,6 +108460,141 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.webXRCamera.js.map
 
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Manages an XRSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    var WebXRSessionManager = /** @class */ (function () {
+        /**
+         * Constructs a WebXRSessionManager, this must be initialized within a user action before usage
+         * @param scene The scene which the session should be created for
+         */
+        function WebXRSessionManager(scene) {
+            this.scene = scene;
+            this._tmpMatrix = new BABYLON.Matrix();
+        }
+        /**
+         * Initializes the manager, this must be done with a user action (eg. button click event)
+         * After initialization enterXR can be called to start an XR session
+         * @returns Promise which resolves after it is initialized
+         */
+        WebXRSessionManager.prototype.initialize = function () {
+            var _this = this;
+            // Check if the browser supports webXR
+            this._xrNavigator = navigator;
+            if (!this._xrNavigator.xr) {
+                return Promise.reject("webXR not supported by this browser");
+            }
+            // Request the webXR device
+            return this._xrNavigator.xr.requestDevice().then(function (device) {
+                _this._xrDevice = device;
+                return _this.scene.getEngine()._gl.setCompatibleXRDevice(_this._xrDevice);
+            });
+        };
+        /**
+         * Enters XR with the desired XR session options
+         * @param sessionCreationOptions xr options to create the session with
+         * @param frameOfReferenceType option to configure how the xr pose is expressed
+         * @returns Promise which resolves after it enters XR
+         */
+        WebXRSessionManager.prototype.enterXR = function (sessionCreationOptions, frameOfReferenceType) {
+            var _this = this;
+            // initialize session
+            return this._xrDevice.requestSession(sessionCreationOptions).then(function (session) {
+                _this._xrSession = session;
+                _this._xrSession.baseLayer = new XRWebGLLayer(_this._xrSession, _this.scene.getEngine()._gl);
+                return _this._xrSession.requestFrameOfReference(frameOfReferenceType);
+            }).then(function (frameOfRef) {
+                _this._frameOfReference = frameOfRef;
+                // Tell the engine's render loop to be driven by the xr session's refresh rate and provide xr pose information
+                _this.scene.getEngine().customAnimationFrameRequester = {
+                    requestAnimationFrame: _this._xrSession.requestAnimationFrame.bind(_this._xrSession),
+                    renderFunction: function (timestamp, xrFrame) {
+                        // Store the XR frame in the manager to be consumed by the XR camera to update pose
+                        _this._currentXRFrame = xrFrame;
+                        _this.scene.getEngine()._renderLoop();
+                    }
+                };
+                // Create render target texture from xr's webgl render target
+                _this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(_this._xrSession, _this.scene);
+            });
+        };
+        /**
+         * Stops the xrSession and restores the renderloop
+         * @returns Promise which resolves after it exits XR
+         */
+        WebXRSessionManager.prototype.exitXR = function () {
+            var _this = this;
+            return new Promise(function (res) {
+                _this.scene.getEngine().customAnimationFrameRequester = null;
+                _this._xrSession.end();
+                // Restore frame buffer to avoid clear on xr framebuffer after session end
+                _this.scene.getEngine().restoreDefaultFramebuffer();
+                // Need to restart render loop as after calling session.end the last request for new frame will never call callback
+                _this.scene.getEngine()._renderLoop();
+                res();
+            });
+        };
+        /**
+         * Fires a ray and returns the closest hit in the xr sessions enviornment, useful to place objects in AR
+         * @param ray ray to cast into the environment
+         * @returns Promise which resolves with a collision point in the environment if it exists
+         */
+        WebXRSessionManager.prototype.environmentPointHitTest = function (ray) {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                // Compute left handed inputs to request hit test
+                var origin = new Float32Array([ray.origin.x, ray.origin.y, ray.origin.z]);
+                var direction = new Float32Array([ray.direction.x, ray.direction.y, ray.direction.z]);
+                if (!_this.scene.useRightHandedSystem) {
+                    origin[2] *= -1;
+                    direction[2] *= -1;
+                }
+                // Fire hittest
+                _this._xrSession.requestHitTest(origin, direction, _this._frameOfReference)
+                    .then(function (hits) {
+                    if (hits.length > 0) {
+                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(hits[0].hitMatrix, 0, 1.0, _this._tmpMatrix);
+                        var hitPoint = _this._tmpMatrix.getTranslation();
+                        if (!_this.scene.useRightHandedSystem) {
+                            hitPoint.z *= -1;
+                        }
+                        res(hitPoint);
+                    }
+                    else {
+                        res(null);
+                    }
+                }).catch(function (e) {
+                    res(null);
+                });
+            });
+        };
+        /**
+         * @hidden
+         * Converts the render layer of xrSession to a render target
+         * @param session session to create render target for
+         * @param scene scene the new render target should be created for
+         */
+        WebXRSessionManager._CreateRenderTargetTextureFromSession = function (session, scene) {
+            // Create internal texture
+            var internalTexture = new BABYLON.InternalTexture(scene.getEngine(), BABYLON.InternalTexture.DATASOURCE_UNKNOWN, true);
+            internalTexture.width = session.baseLayer.framebufferWidth;
+            internalTexture.height = session.baseLayer.framebufferHeight;
+            internalTexture._framebuffer = session.baseLayer.framebuffer;
+            // Create render target texture from the internal texture
+            var renderTargetTexture = new BABYLON.RenderTargetTexture("XR renderTargetTexture", { width: internalTexture.width, height: internalTexture.height }, scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
+            renderTargetTexture._texture = internalTexture;
+            return renderTargetTexture;
+        };
+        return WebXRSessionManager;
+    }());
+    BABYLON.WebXRSessionManager = WebXRSessionManager;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.webXRSessionManager.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/
@@ -115517,7 +115738,7 @@ var BABYLON;
             _this._caps.depthTextureExtension = false;
             _this._caps.vertexArrayObject = false;
             _this._caps.instancedArrays = false;
-            BABYLON.Tools.Log("Babylon.js null engine (v" + BABYLON.Engine.Version + ") launched");
+            BABYLON.Tools.Log("Babylon.js v" + BABYLON.Engine.Version + " - Null engine");
             // Wrappers
             if (typeof URL === "undefined") {
                 URL = {

Plik diff jest za duży
+ 1 - 1
dist/preview release/babylon.worker.js


Plik diff jest za duży
+ 279 - 58
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": "4.0.0-alpha.1",
+    "version": "4.0.0-alpha.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Plik diff jest za duży
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


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

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

Plik diff jest za duży
+ 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": "4.0.0-alpha.1",
+    "version": "4.0.0-alpha.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,10 +28,10 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.1",
-        "babylonjs-gui": "4.0.0-alpha.1",
-        "babylonjs-loaders": "4.0.0-alpha.1",
-        "babylonjs-serializers": "4.0.0-alpha.1"
+        "babylonjs": "4.0.0-alpha.2",
+        "babylonjs-gui": "4.0.0-alpha.2",
+        "babylonjs-loaders": "4.0.0-alpha.2",
+        "babylonjs-serializers": "4.0.0-alpha.2"
     },
     "engines": {
         "node": "*"

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

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

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.0.0-alpha.1",
+    "version": "4.0.0-alpha.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.1"
+        "babylonjs": "4.0.0-alpha.2"
     },
     "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": "4.0.0-alpha.1",
+    "version": "4.0.0-alpha.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.0.0-alpha.1"
+        "babylonjs": "4.0.0-alpha.2"
     },
     "engines": {
         "node": "*"

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

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

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

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

+ 19 - 5
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,6 +1558,20 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

Plik diff jest za duży
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


Plik diff jest za duży
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


+ 22 - 5
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<string> | Promise<Template>;
+            hideOverlayScreen(): Promise<Template> | Promise<string>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<string> | Promise<Template>;
+            showLoadingScreen(): Promise<Template> | Promise<string>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<string> | Promise<Template>;
+            hideLoadingScreen(): Promise<Template> | Promise<string>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,13 +985,14 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
+    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1662,6 +1663,22 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
+declare module 'babylonjs-viewer/optimizer/custom/extended' {
+    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
+    /**
+        * A custom upgrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedUpgrade(sceneManager: SceneManager): boolean;
+    /**
+        * A custom degrade-oriented function configuration for the scene optimizer.
+        *
+        * @param viewer the viewer to optimize
+        */
+    export function extendedDegrade(sceneManager: SceneManager): boolean;
+}
+
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

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

@@ -3,32 +3,35 @@
 ## Major updates
 
 - 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))
+@NEED DEMO- Added FlyCamera for free navigation in 3D space, with a limited set of settings ([Phuein](https://github.com/phuein))
+@NEED DEMO- Added Object Based Motion Blur post-process ([julien-moreau](https://github.com/julien-moreau))
+@NEED DEMO- 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))
+  - webXRSessionManager to bridge xrSession to babylon's engine/camera ([TrevorDev](https://github.com/TrevorDev))
 
 ## Updates
 
 ### GUI
 
+- Added `button.image` and `button.textBlock` to simplify access to button internal parts ([Deltakosh](https://github.com/deltakosh))
+
 ### Core Engine
 
-- Refactor of the SolidParticleSystem code for performance and code quality improvement ([barroij](https://github.com/barroij))
+- Refactored of the SolidParticleSystem code for performance and code quality improvement ([barroij](https://github.com/barroij))
 - 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))
-  - Prevented avoidable matrix inversion or square root computation.
-  - Enabled a removal in O(1) from the `transformNodes` array and `materials` array of the `Scene`. As a consequence, the order of the element within these arrays might change during a removal.
-  - Enabled a removal in O(1) from the `instances` array of a `Mesh`. As a consequence, the order of the element within this array might change during a removal.
-  - Stopped calling `Array.splice` on the `scene.meshes` array and on the `engine._uniformBuffer` when removing an element. As a consequence, the order of the element within these arrays might change during a removal.
-  - Added an option `useMaterialMeshMap` in the `Scene` constructor options. When set to true, each `Material` isntance will have and will keep up-to-date a map of its bound meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones bound to the current material when disposing the Material. Disabled by default.
-  - Added an option `useClonedMeshhMap` in the `Scene` constructor options. When set to true, each `Mesh` will have and will keep up-to-date a map of cloned meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones that have the current mesh as source mesh. Disabled by default.
-  - Added `blockfreeActiveMeshesAndRenderingGroups` property in the `Scene`, following the same model as `blockMaterialDirtyMechanism`. This is to avoid calling `Scene.freeActiveMeshes` and `Scene.freeRenderingGroups` for each disposed mesh when we dispose several meshes in a row. One have to set `blockfreeActiveMeshesAndRenderingGroups` to `true` just before disposing the meshes, and set it back to `false` just after.
-  - Prevented code from doing useless and possible time consuming computation when disposing the `ShaderMaterial` of a `LinesMesh`.
+  - Prevented avoidable matrix inversion or square root computation
+  - Enabled a removal in O(1) from the `transformNodes` array and `materials` array of the `Scene`. As a consequence, the order of the element within these arrays might change during a removal
+  - Enabled a removal in O(1) from the `instances` array of a `Mesh`. As a consequence, the order of the element within this array might change during a removal
+  - Stopped calling `Array.splice` on the `scene.meshes` array and on the `engine._uniformBuffer` when removing an element. As a consequence, the order of the element within these arrays might change during a removal
+  - Added an option `useMaterialMeshMap` in the `Scene` constructor options. When set to true, each `Material` isntance will have and will keep up-to-date a map of its bound meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones bound to the current material when disposing the Material. Disabled by default
+  - Added an option `useClonedMeshhMap` in the `Scene` constructor options. When set to true, each `Mesh` will have and will keep up-to-date a map of cloned meshes. This is to avoid browsing all the meshes of the scene to retrieve the ones that have the current mesh as source mesh. Disabled by default
+  - Added `blockfreeActiveMeshesAndRenderingGroups` property in the `Scene`, following the same model as `blockMaterialDirtyMechanism`. This is to avoid calling `Scene.freeActiveMeshes` and `Scene.freeRenderingGroups` for each disposed mesh when we dispose several meshes in a row. One have to set `blockfreeActiveMeshesAndRenderingGroups` to `true` just before disposing the meshes, and set it back to `false` just after
+  - Prevented code from doing useless and possible time consuming computation when disposing the `ShaderMaterial` of a `LinesMesh`
 
 ### glTF Loader
 
@@ -39,6 +42,7 @@
 ### Materials Library
 
 ## Bug fixes
+- Add missing effect layer to asset container ([TrevorDev](https://github.com/TrevorDev))
 
 ### Core Engine
 - Fixed a bug with `mesh.alwaysSelectAsActiveMesh` preventing layerMask to be taken in account ([Deltakosh](https://github.com/deltakosh))
@@ -53,4 +57,5 @@
 ## Breaking changes
 
 - `Database.IDBStorageEnabled` is now false by default ([Deltakosh](https://github.com/deltakosh))
-- `Database.openAsync` was renamed by `Database.open`
+- `Database.openAsync` was renamed by `Database.open` ([Deltakosh](https://github.com/deltakosh))
+- `scene.database` was renamed to `scene.offlineProvider` ([Deltakosh](https://github.com/deltakosh))

+ 31 - 1
gui/src/2D/controls/button.ts

@@ -2,7 +2,7 @@ import { Rectangle } from "./rectangle";
 import { Control } from "./control";
 import { TextBlock } from "./textBlock";
 import { Image } from "./image";
-import { Vector2 } from "babylonjs";
+import { Vector2, Nullable } from "babylonjs";
 
 /**
  * Class used to create 2D buttons
@@ -25,6 +25,22 @@ export class Button extends Rectangle {
      */
     public pointerUpAnimation: () => void;
 
+    private _image: Nullable<Image>;
+    /**
+     * Returns the image part of the button (if any)
+     */
+    public get image(): Nullable<Image> {
+        return this._image;
+    }
+
+    private _textBlock: Nullable<TextBlock>;
+    /**
+     * Returns the image part of the button (if any)
+     */
+    public get textBlock(): Nullable<TextBlock> {
+        return this._textBlock;
+    }
+
     /**
      * Creates a new Button
      * @param name defines the name of the button
@@ -143,6 +159,10 @@ export class Button extends Rectangle {
         iconImage.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         result.addControl(iconImage);
 
+        // Store
+        result._image = iconImage;
+        result._textBlock = textBlock;
+
         return result;
     }
 
@@ -161,6 +181,9 @@ export class Button extends Rectangle {
         iconImage.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         result.addControl(iconImage);
 
+        // Store
+        result._image = iconImage;
+
         return result;
     }
 
@@ -179,6 +202,9 @@ export class Button extends Rectangle {
         textBlock.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         result.addControl(textBlock);
 
+        // Store
+        result._textBlock = textBlock;
+
         return result;
     }
 
@@ -203,6 +229,10 @@ export class Button extends Rectangle {
         textBlock.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         result.addControl(textBlock);
 
+        // Store
+        result._image = iconImage;
+        result._textBlock = textBlock;
+
         return result;
     }
 }

+ 1 - 1
package.json

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

+ 4 - 3
src/Cameras/Inputs/babylon.arcRotateCameraMouseWheelInput.ts

@@ -48,12 +48,13 @@ module BABYLON {
                     } else {
                         delta = event.wheelDelta / (this.wheelPrecision * 40);
                     }
-                } else if (event.detail) {
-                    delta = -event.detail / this.wheelPrecision;
+                } else {
+                    let deltaValue = event.deltaY || event.detail;
+                    delta = -deltaValue / this.wheelPrecision;
                 }
 
                 if (delta) {
-                    this.camera.inertialRadiusOffset += delta;
+                    this.camera.inertialRadiusOffset += delta;
                 }
 
                 if (event.preventDefault) {

+ 1 - 1
src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts

@@ -53,7 +53,7 @@ module BABYLON {
         }
 
         private _orientationChanged = () => {
-            this._screenOrientationAngle = (window.orientation !== undefined ? +window.orientation : (window.screen.orientation && (<any>window.screen.orientation)['angle'] ? (<any>window.screen.orientation).angle : 0));
+            this._screenOrientationAngle = (<any>window.orientation !== undefined ? +<any>window.orientation : ((<any>window.screen).orientation && ((<any>window.screen).orientation)['angle'] ? ((<any>window.screen).orientation).angle : 0));
             this._screenOrientationAngle = -Tools.ToRadians(this._screenOrientationAngle / 2);
             this._screenQuaternion.copyFromFloats(0, Math.sin(this._screenOrientationAngle), 0, Math.cos(this._screenOrientationAngle));
         }

+ 4 - 4
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -780,8 +780,8 @@ module BABYLON {
         }
 
         private _onFullscreenChange = () => {
-            if (document.fullscreen !== undefined) {
-                this._fullscreenVRpresenting = document.fullscreen;
+            if ((<any>document).fullscreen !== undefined) {
+                this._fullscreenVRpresenting = (<any>document).fullscreen;
             } else if (document.mozFullScreen !== undefined) {
                 this._fullscreenVRpresenting = document.mozFullScreen;
             } else if (document.webkitIsFullScreen !== undefined) {
@@ -814,7 +814,7 @@ module BABYLON {
                 this._webVRpresenting = vrDisplay.isPresenting;
 
                 if (wasPresenting && !this._webVRpresenting) {
-                    this.exitVR();
+                    this.exitVR();
                 }
             } else {
                 Tools.Warn('Detected VRDisplayPresentChange on an unknown VRDisplay. Did you can enterVR on the vrExperienceHelper?');
@@ -880,7 +880,7 @@ module BABYLON {
             }
 
             if (this._webVRrequesting) {
-                return;
+                return;
             }
 
             // If WebVR is supported and a headset is connected

+ 53 - 2
src/Cameras/XR/babylon.webXRCamera.ts

@@ -4,6 +4,8 @@ module BABYLON {
      * @see https://doc.babylonjs.com/how_to/webxr
      */
     export class WebXRCamera extends FreeCamera {
+        private static _TmpMatrix = new BABYLON.Matrix();
+
         /**
          * 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
@@ -40,10 +42,59 @@ module BABYLON {
             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[0].outputRenderTarget = 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;
+            this.rigCameras[1].outputRenderTarget = null;
+        }
+
+        /**
+         * Updates the cameras position from the current pose information of the  XR session
+         * @param xrSessionManager the session containing pose information
+         */
+        public updateFromXRSessionManager(xrSessionManager: WebXRSessionManager) {
+            // Ensure all frame data is available
+            if (!xrSessionManager._currentXRFrame || !xrSessionManager._currentXRFrame.getDevicePose) {
+                return;
+            }
+            var pose = xrSessionManager._currentXRFrame.getDevicePose(xrSessionManager._frameOfReference);
+            if (!pose || !pose.poseModelMatrix) {
+                return;
+            }
+
+            // Update the parent cameras matrix
+            BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.poseModelMatrix, 0, 1, WebXRCamera._TmpMatrix);
+            if (!this._scene.useRightHandedSystem) {
+                WebXRCamera._TmpMatrix.toggleModelMatrixHandInPlace();
+            }
+            WebXRCamera._TmpMatrix.getTranslationToRef(this.position);
+            WebXRCamera._TmpMatrix.getRotationMatrixToRef(WebXRCamera._TmpMatrix);
+            BABYLON.Quaternion.FromRotationMatrixToRef(WebXRCamera._TmpMatrix, this.rotationQuaternion);
+            this.computeWorldMatrix();
+
+            // Update camera rigs
+            this._updateNumberOfRigCameras(xrSessionManager._currentXRFrame.views.length);
+            xrSessionManager._currentXRFrame.views.forEach((view, i) => {
+                // Update view/projection matrix
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(pose.getViewMatrix(view), 0, 1, this.rigCameras[i]._computedViewMatrix);
+                BABYLON.Matrix.FromFloat32ArrayToRefScaled(view.projectionMatrix, 0, 1, this.rigCameras[i]._projectionMatrix);
+                if (!this._scene.useRightHandedSystem) {
+                    this.rigCameras[i]._computedViewMatrix.toggleModelMatrixHandInPlace();
+                    this.rigCameras[i]._projectionMatrix.toggleProjectionMatrixHandInPlace();
+                }
+
+                // Update viewport
+                var viewport  = xrSessionManager._xrSession.baseLayer.getViewport(view);
+                var width = xrSessionManager._xrSession.baseLayer.framebufferWidth;
+                var height = xrSessionManager._xrSession.baseLayer.framebufferHeight;
+                this.rigCameras[i].viewport.width = viewport.width / width;
+                this.rigCameras[i].viewport.height = viewport.height / height;
+                this.rigCameras[i].viewport.x = viewport.x / width;
+                this.rigCameras[i].viewport.y = viewport.y / height;
+
+                // Set cameras to render to the session's render target
+                this.rigCameras[i].outputRenderTarget = xrSessionManager._sessionRenderTargetTexture;
+            });
         }
     }
 }

+ 143 - 0
src/Cameras/XR/babylon.webXRSessionManager.ts

@@ -0,0 +1,143 @@
+module BABYLON {
+    /**
+     * Manages an XRSession
+     * @see https://doc.babylonjs.com/how_to/webxr
+     */
+    export class WebXRSessionManager {
+        private _xrNavigator: any;
+        private _xrDevice: XRDevice;
+        private _tmpMatrix = new BABYLON.Matrix();
+        /** @hidden */
+        public _xrSession: XRSession;
+        /** @hidden */
+        public _frameOfReference: XRFrameOfReference;
+        /** @hidden */
+        public _sessionRenderTargetTexture: RenderTargetTexture;
+        /** @hidden */
+        public _currentXRFrame: XRFrame;
+
+        /**
+         * Constructs a WebXRSessionManager, this must be initialized within a user action before usage
+         * @param scene The scene which the session should be created for
+         */
+        constructor(private scene: BABYLON.Scene) {
+
+        }
+
+        /**
+         * Initializes the manager, this must be done with a user action (eg. button click event)
+         * After initialization enterXR can be called to start an XR session
+         * @returns Promise which resolves after it is initialized
+         */
+        public initialize(): Promise<void> {
+             // Check if the browser supports webXR
+            this._xrNavigator = navigator;
+            if (!this._xrNavigator.xr) {
+                return Promise.reject("webXR not supported by this browser");
+            }
+             // Request the webXR device
+            return this._xrNavigator.xr.requestDevice().then((device: XRDevice) => {
+                this._xrDevice = device;
+                return (<any>this.scene.getEngine()._gl).setCompatibleXRDevice(this._xrDevice);
+            });
+        }
+
+        /**
+         * Enters XR with the desired XR session options
+         * @param sessionCreationOptions xr options to create the session with
+         * @param frameOfReferenceType option to configure how the xr pose is expressed
+         * @returns Promise which resolves after it enters XR
+         */
+        public enterXR(sessionCreationOptions: XRSessionCreationOptions, frameOfReferenceType: XRFrameOfReferenceType): Promise<void> {
+            // initialize session
+            return this._xrDevice.requestSession(sessionCreationOptions).then((session: XRSession) => {
+                this._xrSession = session;
+                this._xrSession.baseLayer = new XRWebGLLayer(this._xrSession, this.scene.getEngine()._gl);
+                return this._xrSession.requestFrameOfReference(frameOfReferenceType);
+            }).then((frameOfRef: any) => {
+                this._frameOfReference = frameOfRef;
+                // Tell the engine's render loop to be driven by the xr session's refresh rate and provide xr pose information
+                this.scene.getEngine().customAnimationFrameRequester = {
+                    requestAnimationFrame: this._xrSession.requestAnimationFrame.bind(this._xrSession),
+                    renderFunction: (timestamp: number, xrFrame: XRFrame) => {
+                        // Store the XR frame in the manager to be consumed by the XR camera to update pose
+                        this._currentXRFrame = xrFrame;
+                        this.scene.getEngine()._renderLoop();
+                    }
+                };
+                // Create render target texture from xr's webgl render target
+                this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(this._xrSession, this.scene);
+            });
+        }
+
+        /**
+         * Stops the xrSession and restores the renderloop
+         * @returns Promise which resolves after it exits XR
+         */
+        public exitXR() {
+            return new Promise((res) => {
+                this.scene.getEngine().customAnimationFrameRequester = null;
+                this._xrSession.end();
+                // Restore frame buffer to avoid clear on xr framebuffer after session end
+                this.scene.getEngine().restoreDefaultFramebuffer();
+                // Need to restart render loop as after calling session.end the last request for new frame will never call callback
+                this.scene.getEngine()._renderLoop();
+                res();
+            });
+        }
+
+        /**
+         * Fires a ray and returns the closest hit in the xr sessions enviornment, useful to place objects in AR
+         * @param ray ray to cast into the environment
+         * @returns Promise which resolves with a collision point in the environment if it exists
+         */
+        public environmentPointHitTest(ray: BABYLON.Ray): Promise<Nullable<Vector3>> {
+            return new Promise((res, rej) => {
+                // Compute left handed inputs to request hit test
+                var origin = new Float32Array([ray.origin.x, ray.origin.y, ray.origin.z]);
+                var direction = new Float32Array([ray.direction.x, ray.direction.y, ray.direction.z]);
+                if (!this.scene.useRightHandedSystem) {
+                    origin[2] *= -1;
+                    direction[2] *= -1;
+                }
+
+                // Fire hittest
+                this._xrSession.requestHitTest(origin, direction, this._frameOfReference)
+                .then((hits: any) => {
+                    if (hits.length > 0) {
+                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(hits[0].hitMatrix, 0, 1.0, this._tmpMatrix);
+                        var hitPoint = this._tmpMatrix.getTranslation();
+                        if (!this.scene.useRightHandedSystem) {
+                            hitPoint.z *= -1;
+                        }
+                        res(hitPoint);
+                    }else {
+                        res(null);
+                    }
+                }).catch((e: Error) => {
+                    res(null);
+                });
+            });
+        }
+
+        /**
+         * @hidden
+         * Converts the render layer of xrSession to a render target
+         * @param session session to create render target for
+         * @param scene scene the new render target should be created for
+         */
+        public static _CreateRenderTargetTextureFromSession(session: XRSession, scene: BABYLON.Scene) {
+            // Create internal texture
+            var internalTexture = new BABYLON.InternalTexture(scene.getEngine(), BABYLON.InternalTexture.DATASOURCE_UNKNOWN, true);
+            internalTexture.width = session.baseLayer.framebufferWidth;
+            internalTexture.height = session.baseLayer.framebufferHeight;
+            internalTexture._framebuffer = session.baseLayer.framebuffer;
+
+             // Create render target texture from the internal texture
+            var renderTargetTexture = new BABYLON.RenderTargetTexture("XR renderTargetTexture", {width: internalTexture.width, height: internalTexture.height}, scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
+            renderTargetTexture._texture = internalTexture;
+
+             return renderTargetTexture;
+        }
+    }
+}

+ 4 - 3
src/Cameras/babylon.camera.ts

@@ -199,7 +199,7 @@ module BABYLON {
         public isStereoscopicSideBySide: boolean;
 
         /**
-         * Defines the list of custom render target the camera should render to.
+         * Defines the list of custom render target which are rendered to and then used as the input to this camera's render. Eg. display another camera view on a TV in the main scene
          * This is pretty helpfull if you wish to make a camera render to a texture you could reuse somewhere
          * else in the scene.
          */
@@ -207,7 +207,7 @@ module BABYLON {
         /**
          * When set, the camera will render to this render target instead of the default canvas
          */
-        public customDefaultRenderTarget: Nullable<RenderTargetTexture> = null;
+        public outputRenderTarget: Nullable<RenderTargetTexture> = null;
 
         /**
          * Observable triggered when the camera view matrix has changed.
@@ -250,7 +250,8 @@ module BABYLON {
 
         protected _globalPosition = Vector3.Zero();
 
-        private _computedViewMatrix = Matrix.Identity();
+        /** hidden */
+        public _computedViewMatrix = Matrix.Identity();
         private _doNotComputeProjectionMatrix = false;
         private _transformMatrix = Matrix.Zero();
         private _frustumPlanes: Plane[];

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

@@ -481,7 +481,20 @@ module BABYLON {
          * Returns the current version of the framework
          */
         public static get Version(): string {
-            return "4.0.0-alpha.1";
+            return "4.0.0-alpha.2";
+        }
+
+        /**
+         * Returns a string describing the current engine
+         */
+        public get description(): string {
+            let description = "WebGL" + this.webGLVersion;
+
+            if (this._caps.parallelShaderCompile) {
+                description += " - Parallel shader compilation";
+            }
+
+            return description;
         }
 
         // Updatable statics so stick with vars here
@@ -1151,8 +1164,8 @@ module BABYLON {
             if (canvas) {
                 // Fullscreen
                 this._onFullscreenChange = () => {
-                    if (document.fullscreen !== undefined) {
-                        this.isFullscreen = document.fullscreen;
+                    if ((<any>document).fullscreen !== undefined) {
+                        this.isFullscreen = (<any>document).fullscreen;
                     } else if (document.mozFullScreen !== undefined) {
                         this.isFullscreen = document.mozFullScreen;
                     } else if (document.webkitIsFullScreen !== undefined) {
@@ -1230,7 +1243,7 @@ module BABYLON {
             // Detect if we are running on a faulty buggy desktop OS.
             this._badDesktopOS = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
 
-            console.log("Babylon.js engine (v" + Engine.Version + ") launched");
+            console.log(`Babylon.js v${Engine.Version} - ${this.description}`);
 
             this.enableOfflineSupport = Engine.OfflineProviderFactory !== undefined;
         }

+ 1 - 1
src/Engine/babylon.nullEngine.ts

@@ -116,7 +116,7 @@ module BABYLON {
             this._caps.vertexArrayObject = false;
             this._caps.instancedArrays = false;
 
-            Tools.Log("Babylon.js null engine (v" + Engine.Version + ") launched");
+            Tools.Log(`Babylon.js v${Engine.Version} - Null engine`);
 
             // Wrappers
             if (typeof URL === "undefined") {

+ 5 - 2
src/Materials/Textures/babylon.internalTexture.ts

@@ -236,12 +236,15 @@ module BABYLON {
          * Creates a new InternalTexture
          * @param engine defines the engine to use
          * @param dataSource defines the type of data that will be used
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        constructor(engine: Engine, dataSource: number) {
+        constructor(engine: Engine, dataSource: number, delayAllocation = false) {
             this._engine = engine;
             this._dataSource = dataSource;
 
-            this._webGLTexture = engine._createTexture();
+            if (!delayAllocation) {
+                this._webGLTexture = engine._createTexture();
+            }
         }
 
         /**

+ 11 - 9
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -260,8 +260,9 @@ module BABYLON {
          * @param generateStencilBuffer True to generate a stencil buffer
          * @param isMulti True if multiple textures need to be created (Draw Buffers)
          * @param format The internal format of the buffer in the RTT (RED, RG, RGB, RGBA, ALPHA...)
+         * @param delayAllocation if the texture allocation should be delayed (default: false)
          */
-        constructor(name: string, size: number | { width: number, height: number } | { ratio: number }, scene: Nullable<Scene>, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false, format = Engine.TEXTUREFORMAT_RGBA) {
+        constructor(name: string, size: number | { width: number, height: number } | { ratio: number }, scene: Nullable<Scene>, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false, format = Engine.TEXTUREFORMAT_RGBA, delayAllocation = false) {
             super(null, scene, !generateMipMaps);
             scene = this.getScene();
 
@@ -305,14 +306,15 @@ module BABYLON {
                 this.wrapV = Texture.CLAMP_ADDRESSMODE;
             }
 
-            if (isCube) {
-                this._texture = scene.getEngine().createRenderTargetCubeTexture(this.getRenderSize(), this._renderTargetOptions);
-                this.coordinatesMode = Texture.INVCUBIC_MODE;
-                this._textureMatrix = Matrix.Identity();
-            } else {
-                this._texture = scene.getEngine().createRenderTargetTexture(this._size, this._renderTargetOptions);
+            if (!delayAllocation) {
+                if (isCube) {
+                    this._texture = scene.getEngine().createRenderTargetCubeTexture(this.getRenderSize(), this._renderTargetOptions);
+                    this.coordinatesMode = Texture.INVCUBIC_MODE;
+                    this._textureMatrix = Matrix.Identity();
+                } else {
+                    this._texture = scene.getEngine().createRenderTargetTexture(this._size, this._renderTargetOptions);
+                }
             }
-
         }
 
         /**
@@ -586,7 +588,7 @@ module BABYLON {
             // Is predicate defined?
             if (this.renderListPredicate) {
                 if (this.renderList) {
-                    this.renderList.splice(0); // Clear previous renderList
+                    this.renderList.length = 0; // Clear previous renderList
                 } else {
                     this.renderList = [];
                 }

+ 21 - 4
src/Math/babylon.math.ts

@@ -8,7 +8,7 @@ module BABYLON {
      * Constant used to convert a value to linear space
      * @ignorenaming
      */
-     export const ToLinearSpace = 2.2;
+    export const ToLinearSpace = 2.2;
     /**
      * Constant used to define the minimal number value in Babylon.js
      * @ignorenaming
@@ -1978,7 +1978,7 @@ module BABYLON {
          * @param len the length of the vector
          * @returns the current updated Vector3
          */
-        public normalizeFromLength(len : number): Vector3 {
+        public normalizeFromLength(len: number): Vector3 {
             if (len === 0 || len === 1.0) {
                 return this;
             }
@@ -4880,9 +4880,26 @@ module BABYLON {
             return this;
         }
 
-        // Statics
+        /**
+         * Toggles model matrix from being right handed to left handed in place and vice versa
+         */
+        public toggleModelMatrixHandInPlace() {
+            [2, 6, 8, 9, 14].forEach((num) => {
+                this.m[num] *= -1;
+            });
+        }
 
         /**
+         * Toggles projection matrix from being right handed to left handed in place and vice versa
+         */
+        public toggleProjectionMatrixHandInPlace() {
+            [8, 9, 10, 11].forEach((num) => {
+                this.m[num] *= -1;
+            });
+        }
+
+        // Statics
+        /**
          * Creates a matrix from an array
          * @param array defines the source array
          * @param offset defines an offset in the source array
@@ -7175,7 +7192,7 @@ module BABYLON {
         public static Vector3: Vector3[] = Tools.BuildArray(13, Vector3.Zero); // 13 temp Vector3 at once should be enough
         public static Vector4: Vector4[] = Tools.BuildArray(3, Vector4.Zero); // 3 temp Vector4 at once should be enough
         public static Quaternion: Quaternion[] = Tools.BuildArray(2, Quaternion.Zero); // 2 temp Quaternion at once should be enough
-        public static Matrix: Matrix[] = Tools.BuildArray(6, Matrix.Identity); // 6 temp Matrices at once should be enough
+        public static Matrix: Matrix[] = Tools.BuildArray(8, Matrix.Identity); // 8 temp Matrices at once should be enough
     }
     /**
      * @hidden

+ 7 - 2
src/babylon.assetContainer.ts

@@ -20,6 +20,11 @@ module BABYLON {
         constructor(scene: Scene) {
             super();
             this.scene = scene;
+            this["sounds"] = [];
+            this["effectLayers"] = [];
+            this["layers"] = [];
+            this["lensFlareSystems"] = [];
+            this["proceduralTextures"] = [];
         }
 
         /**
@@ -67,7 +72,7 @@ module BABYLON {
             });
 
             for (let component of this.scene._serializableComponents) {
-                component.addFromContainer(this.scene);
+                component.addFromContainer(this);
             }
         }
 
@@ -116,7 +121,7 @@ module BABYLON {
             });
 
             for (let component of this.scene._serializableComponents) {
-                component.removeFromContainer(this.scene);
+                component.removeFromContainer(this);
             }
         }
 

+ 41 - 6
src/babylon.mixins.ts

@@ -99,7 +99,6 @@ interface Document {
     webkitCancelFullScreen(): void;
     requestPointerLock(): void;
     exitPointerLock(): void;
-    fullscreen: boolean;
     mozFullScreen: boolean;
     msIsFullScreen: boolean;
     readonly webkitIsFullScreen: boolean;
@@ -155,11 +154,6 @@ interface HTMLVideoElement {
     mozSrcObject: any;
 }
 
-interface Screen {
-    readonly orientation: string;
-    readonly mozOrientation: string;
-}
-
 interface Math {
     fround(x: number): number;
     imul(a: number, b: number): number;
@@ -183,3 +177,44 @@ interface EXT_disjoint_timer_query {
 interface WebGLUniformLocation {
     _currentState: any;
 }
+
+// WebXR
+interface XRDevice {
+    requestSession(options: XRSessionCreationOptions): Promise<XRSession>;
+}
+interface XRSession {
+    baseLayer: XRWebGLLayer;
+    requestFrameOfReference(type: XRFrameOfReferenceType): Promise<void>;
+    requestHitTest(origin: Float32Array, direction: Float32Array, frameOfReference: any): any;
+    end(): void;
+    requestAnimationFrame: Function;
+}
+interface XRSessionCreationOptions {
+}
+interface XRLayer {
+    getViewport: Function;
+    framebufferWidth: number;
+    framebufferHeight: number;
+}
+interface XRView {
+    projectionMatrix: Float32Array;
+}
+interface XRFrame {
+    getDevicePose: Function;
+    views: Array<XRView>;
+    baseLayer: XRLayer;
+}
+interface XRFrameOfReference {
+}
+interface XRWebGLLayer extends XRLayer {
+    framebuffer: WebGLFramebuffer;
+}
+declare var XRWebGLLayer: {
+    prototype: XRWebGLLayer;
+    new(session: XRSession, context?: WebGLRenderingContext): XRWebGLLayer;
+};
+enum XRFrameOfReferenceType {
+    "head-model",
+    "eye-level",
+    "stage",
+}

+ 23 - 32
src/babylon.scene.ts

@@ -1005,6 +1005,7 @@ module BABYLON {
         private _alternateTransformMatrix: Matrix;
         private _useAlternateCameraConfiguration = false;
         private _alternateRendering = false;
+        private _wheelEventName = "";
         /** @hidden */
         public _forcedViewPosition: Nullable<Vector3>;
 
@@ -1635,7 +1636,7 @@ module BABYLON {
             }
 
             if (pickResult) {
-                let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
+                let type = evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
 
                 if (this.onPointerMove) {
                     this.onPointerMove(evt, pickResult, type);
@@ -1752,8 +1753,6 @@ module BABYLON {
         public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
             let evt = new PointerEvent("pointerup", pointerEventInit);
             let clickInfo = new ClickInfo();
-            clickInfo.singleClick = true;
-            clickInfo.ignore = true;
 
             if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERUP)) {
                 return this;
@@ -1805,27 +1804,17 @@ module BABYLON {
 
             let type = PointerEventTypes.POINTERUP;
             if (this.onPointerObservable.hasObservers()) {
-                if (!clickInfo.ignore) {
-                    if (!clickInfo.hasSwiped) {
-                        if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                            let type = PointerEventTypes.POINTERTAP;
-                            let pi = new PointerInfo(type, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type);
-                        }
-                        if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                            let type = PointerEventTypes.POINTERDOUBLETAP;
-                            let pi = new PointerInfo(type, evt, pickResult);
-                            this._setRayOnPointerInfo(pi);
-                            this.onPointerObservable.notifyObservers(pi, type);
-                        }
+                if (!clickInfo.ignore && !clickInfo.hasSwiped) {
+                    if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
+                        type = PointerEventTypes.POINTERTAP;
+                    }
+                    else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
+                        type = PointerEventTypes.POINTERDOUBLETAP;
                     }
                 }
-                else {
-                    let pi = new PointerInfo(type, evt, pickResult);
-                    this._setRayOnPointerInfo(pi);
-                    this.onPointerObservable.notifyObservers(pi, type);
-                }
+                let pi = new PointerInfo(type, evt, pickResult);
+                this._setRayOnPointerInfo(pi);
+                this.onPointerObservable.notifyObservers(pi, type);
             }
 
             if (this.onPointerUp && !clickInfo.ignore) {
@@ -1894,7 +1883,6 @@ module BABYLON {
                         checkPicking = act.hasPickTriggers;
                     }
                 }
-                let eventRaised = false;
                 if (checkPicking) {
                     let btn = evt.button;
                     clickInfo.hasSwiped = this._isPointerSwiping();
@@ -1997,7 +1985,7 @@ module BABYLON {
                 this._updatePointerPosition(evt);
 
                 // PreObservable support
-                if (this._checkPrePointerObservable(null, evt, evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
+                if (this._checkPrePointerObservable(null, evt, evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
                     return;
                 }
 
@@ -2186,9 +2174,13 @@ module BABYLON {
 
             if (attachMove) {
                 canvas.addEventListener(eventPrefix + "move", <any>this._onPointerMove, false);
+
                 // Wheel
-                canvas.addEventListener('mousewheel', <any>this._onPointerMove, false);
-                canvas.addEventListener('DOMMouseScroll', <any>this._onPointerMove, false);
+                this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" :       // Modern browsers support "wheel"
+                    (<any>document).onmousewheel !== undefined ? "mousewheel" :                     // Webkit and IE support at least "mousewheel"
+                        "DOMMouseScroll";                                                           // let's assume that remaining browsers are older Firefox
+
+                canvas.addEventListener(this._wheelEventName, <any>this._onPointerMove, false);
             }
 
             if (attachDown) {
@@ -2225,8 +2217,7 @@ module BABYLON {
             }
 
             // Wheel
-            canvas.removeEventListener('mousewheel', <any>this._onPointerMove);
-            canvas.removeEventListener('DOMMouseScroll', <any>this._onPointerMove);
+            canvas.removeEventListener(this._wheelEventName, <any>this._onPointerMove);
 
             // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
@@ -4403,14 +4394,14 @@ module BABYLON {
 
                 this._intermediateRendering = false;
 
-                if (this.activeCamera.customDefaultRenderTarget) {
-                    var internalTexture = this.activeCamera.customDefaultRenderTarget.getInternalTexture();
+                if (this.activeCamera.outputRenderTarget) {
+                    var internalTexture = this.activeCamera.outputRenderTarget.getInternalTexture();
                     if (internalTexture) {
                         engine.bindFramebuffer(internalTexture);
-                    }else {
+                    } else {
                         Tools.Error("Camera contains invalid customDefaultRenderTarget");
                     }
-                }else {
+                } else {
                     engine.restoreDefaultFramebuffer(); // Restore back buffer if needed
                 }
             }