ソースを参照

Merge remote-tracking branch 'upstream/master' into fixInstancesLinesMeshEdgeRendering

Julien Barrois 6 年 前
コミット
e5d6fa0748
45 ファイル変更26329 行追加24976 行削除
  1. 12566 12439
      Playground/babylon.d.txt
  2. 2 1
      Tools/Gulp/config.json
  3. 12310 12191
      dist/preview release/babylon.d.ts
  4. 1 1
      dist/preview release/babylon.js
  5. 308 66
      dist/preview release/babylon.max.js
  6. 308 66
      dist/preview release/babylon.no-module.max.js
  7. 1 1
      dist/preview release/babylon.worker.js
  8. 310 68
      dist/preview release/es6.js
  9. 1 1
      dist/preview release/glTF2Interface/package.json
  10. 8 0
      dist/preview release/gui/babylon.gui.d.ts
  11. 1 1
      dist/preview release/gui/babylon.gui.js
  12. 1 1
      dist/preview release/gui/babylon.gui.min.js
  13. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  14. 19 1
      dist/preview release/gui/babylon.gui.module.d.ts
  15. 2 2
      dist/preview release/gui/package.json
  16. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  17. 5 5
      dist/preview release/inspector/package.json
  18. 3 3
      dist/preview release/loaders/package.json
  19. 2 2
      dist/preview release/materialsLibrary/package.json
  20. 2 2
      dist/preview release/postProcessesLibrary/package.json
  21. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  22. 3 3
      dist/preview release/serializers/package.json
  23. 15 1
      dist/preview release/viewer/babylon.viewer.d.ts
  24. 2 2
      dist/preview release/viewer/babylon.viewer.js
  25. 3 3
      dist/preview release/viewer/babylon.viewer.max.js
  26. 18 1
      dist/preview release/viewer/babylon.viewer.module.d.ts
  27. 18 13
      dist/preview release/what's new.md
  28. 31 1
      gui/src/2D/controls/button.ts
  29. 1 1
      package.json
  30. 13 8
      sandbox/index.js
  31. 4 3
      src/Cameras/Inputs/babylon.arcRotateCameraMouseWheelInput.ts
  32. 1 1
      src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts
  33. 4 4
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  34. 53 2
      src/Cameras/XR/babylon.webXRCamera.ts
  35. 143 0
      src/Cameras/XR/babylon.webXRSessionManager.ts
  36. 4 3
      src/Cameras/babylon.camera.ts
  37. 17 4
      src/Engine/babylon.engine.ts
  38. 1 1
      src/Engine/babylon.nullEngine.ts
  39. 5 2
      src/Materials/Textures/babylon.internalTexture.ts
  40. 11 9
      src/Materials/Textures/babylon.renderTargetTexture.ts
  41. 8 8
      src/Materials/babylon.materialHelper.ts
  42. 49 11
      src/Math/babylon.math.ts
  43. 7 2
      src/babylon.assetContainer.ts
  44. 41 6
      src/babylon.mixins.ts
  45. 23 32
      src/babylon.scene.ts

ファイルの差分が大きいため隠しています
+ 12566 - 12439
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",

ファイルの差分が大きいため隠しています
+ 12310 - 12191
dist/preview release/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/babylon.js


+ 308 - 66
dist/preview release/babylon.max.js

@@ -7437,6 +7437,8 @@ var BABYLON;
         function Matrix() {
             this._isIdentity = false;
             this._isIdentityDirty = true;
+            this._isIdentity3x2 = true;
+            this._isIdentity3x2Dirty = true;
             /**
              * Gets or sets the internal data of the matrix
              */
@@ -7447,18 +7449,17 @@ var BABYLON;
         Matrix.prototype._markAsUpdated = function () {
             this.updateFlag = Matrix._updateFlagSeed++;
             this._isIdentityDirty = true;
+            this._isIdentity3x2Dirty = true;
         };
         // Properties
         /**
-         * Check if the current matrix is indentity
-         * @param considerAsTextureMatrix defines if the current matrix must be considered as a texture matrix (3x2)
+         * Check if the current matrix is identity
          * @returns true is the matrix is the identity matrix
          */
-        Matrix.prototype.isIdentity = function (considerAsTextureMatrix) {
-            if (considerAsTextureMatrix === void 0) { considerAsTextureMatrix = false; }
+        Matrix.prototype.isIdentity = function () {
             if (this._isIdentityDirty) {
                 this._isIdentityDirty = false;
-                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[10] !== 1.0 || this.m[15] !== 1.0) {
                     this._isIdentity = false;
                 }
                 else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
@@ -7470,13 +7471,32 @@ var BABYLON;
                 else {
                     this._isIdentity = true;
                 }
-                if (!considerAsTextureMatrix && this.m[10] !== 1.0) {
-                    this._isIdentity = false;
-                }
             }
             return this._isIdentity;
         };
         /**
+         * Check if the current matrix is identity as a texture matrix (3x2 store in 4x4)
+         * @returns true is the matrix is the identity matrix
+         */
+        Matrix.prototype.isIdentityAs3x2 = function () {
+            if (this._isIdentity3x2Dirty) {
+                this._isIdentity3x2Dirty = false;
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                    this._isIdentity3x2 = false;
+                }
+                else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
+                    this.m[4] !== 0.0 || this.m[6] !== 0.0 || this.m[7] !== 0.0 ||
+                    this.m[8] !== 0.0 || this.m[9] !== 0.0 || this.m[10] !== 0.0 || this.m[11] !== 0.0 ||
+                    this.m[12] !== 0.0 || this.m[13] !== 0.0 || this.m[14] !== 0.0) {
+                    this._isIdentity3x2 = false;
+                }
+                else {
+                    this._isIdentity3x2 = true;
+                }
+            }
+            return this._isIdentity3x2;
+        };
+        /**
          * Gets the determinant of the matrix
          * @returns the matrix determinant
          */
@@ -7997,6 +8017,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 +10069,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 +10393,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 +12686,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 +12737,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 +23523,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 +23531,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 +23560,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 +25835,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 +26764,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 +26867,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 +26914,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 +26990,6 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
-                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -27035,7 +27081,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 +27236,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 +27267,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 +29147,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 +30144,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 +30197,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 +30246,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 +30926,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 +30963,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 +36625,7 @@ var BABYLON;
             if (!doNotAdd) {
                 this._scene.addMaterial(this);
             }
-            if (scene.useMaterialMeshMap) {
+            if (this._scene.useMaterialMeshMap) {
                 this.meshMap = {};
             }
         }
@@ -42799,7 +42855,7 @@ var BABYLON;
         MaterialHelper.PrepareDefinesForMergedUV = function (texture, defines, key) {
             defines._needUVs = true;
             defines[key] = true;
-            if (texture.getTextureMatrix().isIdentity(true)) {
+            if (texture.getTextureMatrix().isIdentityAs3x2()) {
                 defines[key + "DIRECTUV"] = texture.coordinatesIndex + 1;
                 if (texture.coordinatesIndex === 0) {
                     defines["MAINUV1"] = true;
@@ -42820,7 +42876,7 @@ var BABYLON;
          */
         MaterialHelper.BindTextureMatrix = function (texture, uniformBuffer, key) {
             var matrix = texture.getTextureMatrix();
-            if (!matrix.isIdentity(true)) {
+            if (!matrix.isIdentityAs3x2()) {
                 uniformBuffer.updateMatrix(key + "Matrix", matrix);
             }
         };
@@ -50725,8 +50781,9 @@ var BABYLON;
                         delta = event.wheelDelta / (_this.wheelPrecision * 40);
                     }
                 }
-                else if (event.detail) {
-                    delta = -event.detail / _this.wheelPrecision;
+                else {
+                    var deltaValue = event.deltaY || event.detail;
+                    delta = -deltaValue / _this.wheelPrecision;
                 }
                 if (delta) {
                     _this.camera.inertialRadiusOffset += delta;
@@ -73387,8 +73444,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 +73455,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 +73534,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 +73932,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 +105614,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 +108456,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 +108514,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 +115792,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 = {

+ 308 - 66
dist/preview release/babylon.no-module.max.js

@@ -7404,6 +7404,8 @@ var BABYLON;
         function Matrix() {
             this._isIdentity = false;
             this._isIdentityDirty = true;
+            this._isIdentity3x2 = true;
+            this._isIdentity3x2Dirty = true;
             /**
              * Gets or sets the internal data of the matrix
              */
@@ -7414,18 +7416,17 @@ var BABYLON;
         Matrix.prototype._markAsUpdated = function () {
             this.updateFlag = Matrix._updateFlagSeed++;
             this._isIdentityDirty = true;
+            this._isIdentity3x2Dirty = true;
         };
         // Properties
         /**
-         * Check if the current matrix is indentity
-         * @param considerAsTextureMatrix defines if the current matrix must be considered as a texture matrix (3x2)
+         * Check if the current matrix is identity
          * @returns true is the matrix is the identity matrix
          */
-        Matrix.prototype.isIdentity = function (considerAsTextureMatrix) {
-            if (considerAsTextureMatrix === void 0) { considerAsTextureMatrix = false; }
+        Matrix.prototype.isIdentity = function () {
             if (this._isIdentityDirty) {
                 this._isIdentityDirty = false;
-                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[10] !== 1.0 || this.m[15] !== 1.0) {
                     this._isIdentity = false;
                 }
                 else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
@@ -7437,13 +7438,32 @@ var BABYLON;
                 else {
                     this._isIdentity = true;
                 }
-                if (!considerAsTextureMatrix && this.m[10] !== 1.0) {
-                    this._isIdentity = false;
-                }
             }
             return this._isIdentity;
         };
         /**
+         * Check if the current matrix is identity as a texture matrix (3x2 store in 4x4)
+         * @returns true is the matrix is the identity matrix
+         */
+        Matrix.prototype.isIdentityAs3x2 = function () {
+            if (this._isIdentity3x2Dirty) {
+                this._isIdentity3x2Dirty = false;
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                    this._isIdentity3x2 = false;
+                }
+                else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
+                    this.m[4] !== 0.0 || this.m[6] !== 0.0 || this.m[7] !== 0.0 ||
+                    this.m[8] !== 0.0 || this.m[9] !== 0.0 || this.m[10] !== 0.0 || this.m[11] !== 0.0 ||
+                    this.m[12] !== 0.0 || this.m[13] !== 0.0 || this.m[14] !== 0.0) {
+                    this._isIdentity3x2 = false;
+                }
+                else {
+                    this._isIdentity3x2 = true;
+                }
+            }
+            return this._isIdentity3x2;
+        };
+        /**
          * Gets the determinant of the matrix
          * @returns the matrix determinant
          */
@@ -7964,6 +7984,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 +10036,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 +10360,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 +12653,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 +12704,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 +23490,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 +23498,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 +23527,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 +25802,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 +26731,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 +26834,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 +26881,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 +26957,6 @@ var BABYLON;
                         checkPicking = act.hasPickTriggers;
                     }
                 }
-                var eventRaised = false;
                 if (checkPicking) {
                     var btn = evt.button;
                     clickInfo.hasSwiped = _this._isPointerSwiping();
@@ -27002,7 +27048,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 +27203,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 +27234,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 +29114,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 +30111,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 +30164,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 +30213,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 +30893,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 +30930,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 +36592,7 @@ var BABYLON;
             if (!doNotAdd) {
                 this._scene.addMaterial(this);
             }
-            if (scene.useMaterialMeshMap) {
+            if (this._scene.useMaterialMeshMap) {
                 this.meshMap = {};
             }
         }
@@ -42766,7 +42822,7 @@ var BABYLON;
         MaterialHelper.PrepareDefinesForMergedUV = function (texture, defines, key) {
             defines._needUVs = true;
             defines[key] = true;
-            if (texture.getTextureMatrix().isIdentity(true)) {
+            if (texture.getTextureMatrix().isIdentityAs3x2()) {
                 defines[key + "DIRECTUV"] = texture.coordinatesIndex + 1;
                 if (texture.coordinatesIndex === 0) {
                     defines["MAINUV1"] = true;
@@ -42787,7 +42843,7 @@ var BABYLON;
          */
         MaterialHelper.BindTextureMatrix = function (texture, uniformBuffer, key) {
             var matrix = texture.getTextureMatrix();
-            if (!matrix.isIdentity(true)) {
+            if (!matrix.isIdentityAs3x2()) {
                 uniformBuffer.updateMatrix(key + "Matrix", matrix);
             }
         };
@@ -50692,8 +50748,9 @@ var BABYLON;
                         delta = event.wheelDelta / (_this.wheelPrecision * 40);
                     }
                 }
-                else if (event.detail) {
-                    delta = -event.detail / _this.wheelPrecision;
+                else {
+                    var deltaValue = event.deltaY || event.detail;
+                    delta = -deltaValue / _this.wheelPrecision;
                 }
                 if (delta) {
                     _this.camera.inertialRadiusOffset += delta;
@@ -73354,8 +73411,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 +73422,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 +73501,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 +73899,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 +105581,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 +108423,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 +108481,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 +115759,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 = {

ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/babylon.worker.js


ファイルの差分が大きいため隠しています
+ 310 - 68
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"

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

@@ -594,6 +594,14 @@ declare module BABYLON.GUI {
                 */
             pointerUpAnimation: () => void;
             /**
+                * Returns the image part of the button (if any)
+                */
+            readonly image: BABYLON.Nullable<Image>;
+            /**
+                * Returns the image part of the button (if any)
+                */
+            readonly textBlock: BABYLON.Nullable<TextBlock>;
+            /**
                 * Creates a new Button
                 * @param name defines the name of the button
                 */

ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/gui/babylon.gui.js


ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


+ 19 - 1
dist/preview release/gui/babylon.gui.module.d.ts

@@ -652,7 +652,9 @@ declare module 'babylonjs-gui/3D/vector3WithInfo' {
 declare module 'babylonjs-gui/2D/controls/button' {
     import { Rectangle } from "babylonjs-gui/2D/controls/rectangle";
     import { Control } from "babylonjs-gui/2D/controls/control";
-    import { Vector2 } from "babylonjs";
+    import { TextBlock } from "babylonjs-gui/2D/controls/textBlock";
+    import { Image } from "babylonjs-gui/2D/controls/image";
+    import { Vector2, Nullable } from "babylonjs";
     /**
         * Class used to create 2D buttons
         */
@@ -675,6 +677,14 @@ declare module 'babylonjs-gui/2D/controls/button' {
                 */
             pointerUpAnimation: () => void;
             /**
+                * Returns the image part of the button (if any)
+                */
+            readonly image: Nullable<Image>;
+            /**
+                * Returns the image part of the button (if any)
+                */
+            readonly textBlock: Nullable<TextBlock>;
+            /**
                 * Creates a new Button
                 * @param name defines the name of the button
                 */
@@ -3429,6 +3439,14 @@ declare module BABYLON.GUI {
                 */
             pointerUpAnimation: () => void;
             /**
+                * Returns the image part of the button (if any)
+                */
+            readonly image: BABYLON.Nullable<Image>;
+            /**
+                * Returns the image part of the button (if any)
+                */
+            readonly textBlock: BABYLON.Nullable<TextBlock>;
+            /**
                 * Creates a new Button
                 * @param name defines the name of the button
                 */

+ 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": "*"

ファイルの差分が大きいため隠しています
+ 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": "*"

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

@@ -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 {

ファイルの差分が大きいため隠しています
+ 2 - 2
dist/preview release/viewer/babylon.viewer.js


ファイルの差分が大きいため隠しています
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -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"

+ 13 - 8
sandbox/index.js

@@ -16,6 +16,8 @@ var dropdownLabel = document.getElementById("dropdownLabel");
 var dropdownContent = document.getElementById("dropdownContent");
 var playBtn = document.getElementById("playBtn");
 var slider = document.getElementById("slider");
+var footer = document.getElementById("footer");
+var canvas = document.getElementById("renderCanvas");
 
 var indexOf = location.href.indexOf("?");
 if (indexOf !== -1) {
@@ -41,11 +43,14 @@ if (indexOf !== -1) {
     }
 }
 
+if (kiosk) {
+    footer.style.display = "none";
+    canvas.style.height = "100%";
+}
+
 if (BABYLON.Engine.isSupported()) {
-    var canvas = document.getElementById("renderCanvas");
     var engine = new BABYLON.Engine(canvas, true, { premultipliedAlpha: false, preserveDrawingBuffer: true });
     var htmlInput = document.getElementById("files");
-    var footer = document.getElementById("footer");
     var btnInspector = document.getElementById("btnInspector");
     var errorZone = document.getElementById("errorZone");
     var filesInput;
@@ -128,7 +133,7 @@ if (BABYLON.Engine.isSupported()) {
         btnInspector.classList.remove("hidden");
 
         currentScene = babylonScene;
-        document.title = "BabylonJS - " + sceneFile.name;
+        document.title = "Babylon.js - " + sceneFile.name;
         // Fix for IE, otherwise it will change the default filter for files selection after first use
         htmlInput.value = "";
 
@@ -210,7 +215,7 @@ if (BABYLON.Engine.isSupported()) {
     };
 
     var sceneError = function(sceneFile, babylonScene, message) {
-        document.title = "BabylonJS - " + sceneFile.name;
+        document.title = "Babylon.js - " + sceneFile.name;
         document.getElementById("logo").className = "";
         canvas.style.opacity = 0;
 
@@ -298,10 +303,6 @@ if (BABYLON.Engine.isSupported()) {
         }
     });
 
-    if (kiosk) {
-        footer.style.display = "none";
-    }
-
     btnInspector.addEventListener('click', function() {
         if (currentScene) {
             if (currentScene.debugLayer.isVisible()) {
@@ -321,10 +322,14 @@ if (BABYLON.Engine.isSupported()) {
         if (event.keyCode === 32 && event.target.nodeName !== "INPUT") {
             if (footer.style.display === "none") {
                 footer.style.display = "block";
+                canvas.style.height = "calc(100% - 56px)";                
+                engine.resize();
             }
             else {
                 footer.style.display = "none";
+                canvas.style.height = "100%";
                 errorZone.style.display = "none";
+                engine.resize();
                 if (debugLayerEnabled) {
                     currentScene.debugLayer.hide();
                     debugLayerEnabled = false;

+ 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 = [];
                 }

+ 8 - 8
src/Materials/babylon.materialHelper.ts

@@ -32,7 +32,7 @@ module BABYLON {
         public static PrepareDefinesForMergedUV(texture: BaseTexture, defines: any, key: string): void {
             defines._needUVs = true;
             defines[key] = true;
-            if (texture.getTextureMatrix().isIdentity(true)) {
+            if (texture.getTextureMatrix().isIdentityAs3x2()) {
                 defines[key + "DIRECTUV"] = texture.coordinatesIndex + 1;
                 if (texture.coordinatesIndex === 0) {
                     defines["MAINUV1"] = true;
@@ -53,7 +53,7 @@ module BABYLON {
         public static BindTextureMatrix(texture: BaseTexture, uniformBuffer: UniformBuffer, key: string): void {
             var matrix = texture.getTextureMatrix();
 
-            if (!matrix.isIdentity(true)) {
+            if (!matrix.isIdentityAs3x2()) {
                 uniformBuffer.updateMatrix(key + "Matrix", matrix);
             }
         }
@@ -245,14 +245,14 @@ module BABYLON {
 
                     switch (light.falloffType) {
                         case Light.FALLOFF_GLTF:
-                        defines["LIGHT_FALLOFF_GLTF" + lightIndex] = true;
-                        break;
+                            defines["LIGHT_FALLOFF_GLTF" + lightIndex] = true;
+                            break;
                         case Light.FALLOFF_PHYSICAL:
-                        defines["LIGHT_FALLOFF_PHYSICAL" + lightIndex] = true;
-                        break;
+                            defines["LIGHT_FALLOFF_PHYSICAL" + lightIndex] = true;
+                            break;
                         case Light.FALLOFF_STANDARD:
-                        defines["LIGHT_FALLOFF_STANDARD" + lightIndex] = true;
-                        break;
+                            defines["LIGHT_FALLOFF_STANDARD" + lightIndex] = true;
+                            break;
                     }
 
                     // Specular

+ 49 - 11
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;
             }
@@ -4229,6 +4229,8 @@ module BABYLON {
 
         private _isIdentity = false;
         private _isIdentityDirty = true;
+        private _isIdentity3x2 = true;
+        private _isIdentity3x2Dirty = true;
         /**
          * Gets the update flag of the matrix which is an unique number for the matrix.
          * It will be incremented every time the matrix data change.
@@ -4245,6 +4247,7 @@ module BABYLON {
         public _markAsUpdated() {
             this.updateFlag = Matrix._updateFlagSeed++;
             this._isIdentityDirty = true;
+            this._isIdentity3x2Dirty = true;
         }
 
         /**
@@ -4257,14 +4260,13 @@ module BABYLON {
         // Properties
 
         /**
-         * Check if the current matrix is indentity
-         * @param considerAsTextureMatrix defines if the current matrix must be considered as a texture matrix (3x2)
+         * Check if the current matrix is identity
          * @returns true is the matrix is the identity matrix
          */
-        public isIdentity(considerAsTextureMatrix = false): boolean {
+        public isIdentity(): boolean {
             if (this._isIdentityDirty) {
                 this._isIdentityDirty = false;
-                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[10] !== 1.0 || this.m[15] !== 1.0) {
                     this._isIdentity = false;
                 } else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
                     this.m[4] !== 0.0 || this.m[6] !== 0.0 || this.m[7] !== 0.0 ||
@@ -4274,14 +4276,33 @@ module BABYLON {
                 } else {
                     this._isIdentity = true;
                 }
+            }
 
-                if (!considerAsTextureMatrix && this.m[10] !== 1.0) {
-                    this._isIdentity = false;
+            return this._isIdentity;
+        }
+
+        /**
+         * Check if the current matrix is identity as a texture matrix (3x2 store in 4x4)
+         * @returns true is the matrix is the identity matrix
+         */
+        public isIdentityAs3x2(): boolean {
+            if (this._isIdentity3x2Dirty) {
+                this._isIdentity3x2Dirty = false;
+                if (this.m[0] !== 1.0 || this.m[5] !== 1.0 || this.m[15] !== 1.0) {
+                    this._isIdentity3x2 = false;
+                } else if (this.m[1] !== 0.0 || this.m[2] !== 0.0 || this.m[3] !== 0.0 ||
+                    this.m[4] !== 0.0 || this.m[6] !== 0.0 || this.m[7] !== 0.0 ||
+                    this.m[8] !== 0.0 || this.m[9] !== 0.0 || this.m[10] !== 0.0 || this.m[11] !== 0.0 ||
+                    this.m[12] !== 0.0 || this.m[13] !== 0.0 || this.m[14] !== 0.0) {
+                    this._isIdentity3x2 = false;
+                } else {
+                    this._isIdentity3x2 = true;
                 }
             }
 
-            return this._isIdentity;
+            return this._isIdentity3x2;
         }
+
         /**
          * Gets the determinant of the matrix
          * @returns the matrix determinant
@@ -4880,8 +4901,25 @@ 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
@@ -7175,7 +7213,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
                 }
             }