瀏覽代碼

Adjusting the WebVR architecture to fit the new WebVR API

The engine is now responsible to search for new devices, if WebVR is
enabled in the browser.
If WebVR is enabled (and a device was chosen (attachControl), the
fullscreen and request animation frame will be triggered by the
vrDisplay device.
Users with no WebVR enabled can still use the API in the same way.
Raanan Weber 9 年之前
父節點
當前提交
bb3fc341ec
共有 4 個文件被更改,包括 185 次插入88 次删除
  1. 47 44
      src/Cameras/VR/babylon.webVRCamera.ts
  2. 30 17
      src/Tools/babylon.tools.ts
  3. 107 26
      src/babylon.engine.ts
  4. 1 1
      src/babylon.mixins.ts

+ 47 - 44
src/Cameras/VR/babylon.webVRCamera.ts

@@ -1,60 +1,46 @@
 declare var HMDVRDevice;
 declare var HMDVRDevice;
-declare var PositionSensorVRDevice;
+declare var VRDisplay;
 
 
 module BABYLON {
 module BABYLON {
+
+    export interface WebVROptions {
+        trackPosition?: boolean; //update the camera's position
+        displayName?: string; //if there are more than one VRDisplays.
+    }
+
     export class WebVRFreeCamera extends FreeCamera {
     export class WebVRFreeCamera extends FreeCamera {
-        public _hmdDevice = null;
-        public _sensorDevice = null;
+        public _vrDevice = null;
         private _cacheState = null;
         private _cacheState = null;
-        public _vrEnabled = false;
+        private _vrEnabled = false;
+
+        private _oldSize: BABYLON.Size;
+        private _oldHardwareScaleFactor: number;
 
 
         private _initialQuaternion: Quaternion;
         private _initialQuaternion: Quaternion;
         private _quaternionCache: Quaternion;
         private _quaternionCache: Quaternion;
 
 
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true, vrCameraMetrics: VRCameraMetrics = VRCameraMetrics.GetDefault()) {
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true, vrCameraMetrics: VRCameraMetrics = VRCameraMetrics.GetDefault(), private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
             super(name, position, scene);
 
 
             vrCameraMetrics.compensateDistortion = compensateDistortion;
             vrCameraMetrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics });
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics });
 
 
-            this._getWebVRDevices = this._getWebVRDevices.bind(this);
+            //this._getWebVRDevices = this._getWebVRDevices.bind(this);
+            if (!this.getEngine().vrDisplaysPromise) {
+                Tools.Error("WebVR is not enabled on your browser");
+            }
 
 
             this.rotationQuaternion = new Quaternion();
             this.rotationQuaternion = new Quaternion();
             this._quaternionCache = new Quaternion();
             this._quaternionCache = new Quaternion();
         }
         }
 
 
-        private _getWebVRDevices(devices: Array<any>): void {
-            var size = devices.length;
-            var i = 0;
-
-            // Reset devices.
-            this._sensorDevice = null;
-            this._hmdDevice = null;
-
-            // Search for a HmdDevice.
-            while (i < size && this._hmdDevice === null) {
-                if (devices[i] instanceof HMDVRDevice) {
-                    this._hmdDevice = devices[i];
-                }
-                i++;
-            }
-
-            i = 0;
-
-            while (i < size && this._sensorDevice === null) {
-                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
-                    this._sensorDevice = devices[i];
-                }
-                i++;
-            }
-
-            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
-        }
-
         public _checkInputs(): void {
         public _checkInputs(): void {
             if (this._vrEnabled) {
             if (this._vrEnabled) {
-                this._cacheState = this._sensorDevice.getState();
-                this.rotationQuaternion.copyFrom(this._cacheState.orientation);
+                this._cacheState = this._vrDevice.getPose();
+                this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], this._cacheState.orientation[2], this._cacheState.orientation[3]);
+                if (this.webVROptions.trackPosition) {
+                    this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
+                }
                 //Flip in XY plane
                 //Flip in XY plane
                 this.rotationQuaternion.z *= -1;
                 this.rotationQuaternion.z *= -1;
                 this.rotationQuaternion.w *= -1;
                 this.rotationQuaternion.w *= -1;
@@ -72,22 +58,39 @@ module BABYLON {
 
 
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
             noPreventDefault = Camera.ForceAttachControlToAlwaysPreventDefault ? false : noPreventDefault;
 
 
-            if (navigator.getVRDevices) {
-                navigator.getVRDevices().then(this._getWebVRDevices);
-            }
-            else if (navigator.mozGetVRDevices) {
-                navigator.mozGetVRDevices(this._getWebVRDevices);
-            }
+            //TODO get the metrics updated using the device's eye parameters!
+
+            //sanity check. if no WebVR enabled.
+            this.getEngine().vrDisplaysPromise && this.getEngine().vrDisplaysPromise.then((devices) => {
+                if (devices.length > 0) {
+                    this._vrEnabled = true;
+                    if (this.webVROptions.displayName) {
+                        devices.some(device => {
+                            if (device.displayName === this.webVROptions.displayName) {
+                                this.getEngine().enableVR(device);
+                                return true;
+                            } else {
+                                return false;
+                            }
+                        })
+                    } else {
+                        //choose the first one
+                        this.getEngine().enableVR(devices[0]);
+                    }
+                }
+            })
         }
         }
 
 
         public detachControl(element: HTMLElement): void {
         public detachControl(element: HTMLElement): void {
             super.detachControl(element);
             super.detachControl(element);
             this._vrEnabled = false;
             this._vrEnabled = false;
+            this.getEngine().disableVR();
         }
         }
 
 
         public requestVRFullscreen(requestPointerlock: boolean) {
         public requestVRFullscreen(requestPointerlock: boolean) {
-            if (!this._hmdDevice) return;
-            this.getEngine().switchFullscreen(requestPointerlock, { vrDisplay: this._hmdDevice })
+            //Backwards comp.
+            Tools.Warn("requestVRFullscreen is deprecated. Use engine.switchFullscreen() instead")
+            this.getEngine().switchFullscreen(requestPointerlock);
         }
         }
 
 
         public getTypeName(): string {
         public getTypeName(): string {

+ 30 - 17
src/Tools/babylon.tools.ts

@@ -251,30 +251,43 @@
             return eventPrefix;
             return eventPrefix;
         }
         }
 
 
-        public static QueueNewFrame(func): void {
-            if (window.requestAnimationFrame)
-                window.requestAnimationFrame(func);
-            else if (window.msRequestAnimationFrame)
-                window.msRequestAnimationFrame(func);
-            else if (window.webkitRequestAnimationFrame)
-                window.webkitRequestAnimationFrame(func);
-            else if (window.mozRequestAnimationFrame)
-                window.mozRequestAnimationFrame(func);
-            else if (window.oRequestAnimationFrame)
-                window.oRequestAnimationFrame(func);
+        /**
+         * @param func - the function to be called
+         * @param requester - the object that will request the next frame. Falls back to window.
+         */
+        public static QueueNewFrame(func, requester: any = window): void {
+            if (requester.requestAnimationFrame)
+                requester.requestAnimationFrame(func);
+            else if (requester.msRequestAnimationFrame)
+                requester.msRequestAnimationFrame(func);
+            else if (requester.webkitRequestAnimationFrame)
+                requester.webkitRequestAnimationFrame(func);
+            else if (requester.mozRequestAnimationFrame)
+                requester.mozRequestAnimationFrame(func);
+            else if (requester.oRequestAnimationFrame)
+                requester.oRequestAnimationFrame(func);
             else {
             else {
                 window.setTimeout(func, 16);
                 window.setTimeout(func, 16);
             }
             }
         }
         }
 
 
-        public static RequestFullscreen(element, options?: any): void {
-            var requestFunction = element.requestFullscreen || element.msRequestFullscreen || element.webkitRequestFullscreen || element.mozRequestFullScreen;
-            if (!requestFunction) return;
-            requestFunction.call(element, options);
+        public static RequestFullscreen(element, vrDisplay?): void {
+            //WebVR?
+            if (vrDisplay) {
+                vrDisplay.requestPresent([{ source: element }]);
+            } else {
+                var requestFunction = element.requestFullscreen || element.msRequestFullscreen || element.webkitRequestFullscreen || element.mozRequestFullScreen;
+                if (!requestFunction) return;
+                requestFunction.call(element);
+            }
         }
         }
 
 
-        public static ExitFullscreen(): void {
-            if (document.exitFullscreen) {
+        public static ExitFullscreen(vrDisplay?): void {
+            //WebVR?
+            if (vrDisplay) {
+                vrDisplay.exitPresent();
+            }
+            else if (document.exitFullscreen) {
                 document.exitFullscreen();
                 document.exitFullscreen();
             }
             }
             else if (document.mozCancelFullScreen) {
             else if (document.mozCancelFullScreen) {

+ 107 - 26
src/babylon.engine.ts

@@ -184,8 +184,8 @@
         public textureLOD: boolean;
         public textureLOD: boolean;
         public drawBuffersExtension;
         public drawBuffersExtension;
     }
     }
-    
-    export interface EngineOptions extends WebGLContextAttributes{
+
+    export interface EngineOptions extends WebGLContextAttributes {
         limitDeviceRatio?: number;
         limitDeviceRatio?: number;
     }
     }
 
 
@@ -311,6 +311,17 @@
         public enableOfflineSupport = true;
         public enableOfflineSupport = true;
         public scenes = new Array<Scene>();
         public scenes = new Array<Scene>();
 
 
+        //WebVR 
+
+        //The new WebVR uses promises.
+        //this promise resolves with the current devices available.
+        public vrDisplaysPromise;
+
+        private _vrDisplays;
+        private _vrDisplayEnabled;
+        private _oldSize: BABYLON.Size;
+        private _oldHardwareScaleFactor: number;
+
         // Private Members
         // Private Members
         public _gl: WebGLRenderingContext;
         public _gl: WebGLRenderingContext;
         private _renderingCanvas: HTMLCanvasElement;
         private _renderingCanvas: HTMLCanvasElement;
@@ -328,7 +339,7 @@
         private _caps: EngineCapabilities;
         private _caps: EngineCapabilities;
         private _pointerLockRequested: boolean;
         private _pointerLockRequested: boolean;
         private _alphaTest: boolean;
         private _alphaTest: boolean;
-        private _isStencilEnable: boolean; 
+        private _isStencilEnable: boolean;
 
 
         private _loadingScreen: ILoadingScreen;
         private _loadingScreen: ILoadingScreen;
 
 
@@ -382,7 +393,7 @@
 
 
         private _externalData: StringDictionary<Object>;
         private _externalData: StringDictionary<Object>;
         private _bindedRenderFunction: any;
         private _bindedRenderFunction: any;
-        
+
         /**
         /**
          * @constructor
          * @constructor
          * @param {HTMLCanvasElement} canvas - the canvas to be used for rendering
          * @param {HTMLCanvasElement} canvas - the canvas to be used for rendering
@@ -396,7 +407,7 @@
 
 
             options = options || {};
             options = options || {};
 
 
-            if(antialias != null){
+            if (antialias != null) {
                 options.antialias = antialias;
                 options.antialias = antialias;
             }
             }
 
 
@@ -552,6 +563,9 @@
             //default loading screen
             //default loading screen
             this._loadingScreen = new DefaultLoadingScreen(this._renderingCanvas);
             this._loadingScreen = new DefaultLoadingScreen(this._renderingCanvas);
 
 
+            //Load WebVR Devices
+            this._getVRDisplays();
+
             Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
             Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
         }
         }
 
 
@@ -698,11 +712,11 @@
         public setStencilFunction(stencilFunc: number) {
         public setStencilFunction(stencilFunc: number) {
             this._stencilState.stencilFunc = stencilFunc;
             this._stencilState.stencilFunc = stencilFunc;
         }
         }
-        
+
         public setStencilFunctionReference(reference: number) {
         public setStencilFunctionReference(reference: number) {
             this._stencilState.stencilFuncRef = reference;
             this._stencilState.stencilFuncRef = reference;
         }
         }
-        
+
         public setStencilFunctionMask(mask: number) {
         public setStencilFunctionMask(mask: number) {
             this._stencilState.stencilFuncMask = mask;
             this._stencilState.stencilFuncMask = mask;
         }
         }
@@ -770,7 +784,7 @@
 
 
             if (this._activeRenderLoops.length > 0) {
             if (this._activeRenderLoops.length > 0) {
                 // Register new frame
                 // Register new frame
-                Tools.QueueNewFrame(this._bindedRenderFunction);
+                Tools.QueueNewFrame(this._bindedRenderFunction, this._getFrameRequester());
             } else {
             } else {
                 this._renderingQueueLaunched = false;
                 this._renderingQueueLaunched = false;
             }
             }
@@ -803,19 +817,19 @@
          * @param {boolean} requestPointerLock - should a pointer lock be requested from the user
          * @param {boolean} requestPointerLock - should a pointer lock be requested from the user
          * @param {any} options - an options object to be sent to the requestFullscreen function
          * @param {any} options - an options object to be sent to the requestFullscreen function
          */
          */
-        public switchFullscreen(requestPointerLock: boolean, options?: any): void {
+        public switchFullscreen(requestPointerLock: boolean): void {
             if (this.isFullscreen) {
             if (this.isFullscreen) {
-                Tools.ExitFullscreen();
+                Tools.ExitFullscreen(this._vrDisplayEnabled);
             } else {
             } else {
                 this._pointerLockRequested = requestPointerLock;
                 this._pointerLockRequested = requestPointerLock;
-                Tools.RequestFullscreen(this._renderingCanvas, options);
+                Tools.RequestFullscreen(this._renderingCanvas, this._vrDisplayEnabled);
             }
             }
         }
         }
 
 
-        public clear(color: any, backBuffer: boolean, depth: boolean, stencil:boolean = false): void {
+        public clear(color: any, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
             this.applyStates();
             this.applyStates();
 
 
-            var mode = 0;            
+            var mode = 0;
             if (backBuffer) {
             if (backBuffer) {
                 this._gl.clearColor(color.r, color.g, color.b, color.a !== undefined ? color.a : 1.0);
                 this._gl.clearColor(color.r, color.g, color.b, color.a !== undefined ? color.a : 1.0);
                 mode |= this._gl.COLOR_BUFFER_BIT;
                 mode |= this._gl.COLOR_BUFFER_BIT;
@@ -892,6 +906,11 @@
 
 
         public endFrame(): void {
         public endFrame(): void {
             //this.flushFramebuffer();
             //this.flushFramebuffer();
+
+            //submit frame to the vr device, if enabled
+            if(this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
+                this._vrDisplayEnabled.submitFrame()
+            }
         }
         }
 
 
         /**
         /**
@@ -935,14 +954,73 @@
             }
             }
         }
         }
 
 
+
+        //WebVR functions
+
+        public enableVR(vrDevice) {
+            this._vrDisplayEnabled = vrDevice;
+            window.addEventListener('vrdisplaypresentchange', this._onVRFullScreenTriggered, false);
+        }
+
+        public disableVR() {
+            if (this._vrDisplayEnabled) {
+                this._vrDisplayEnabled = null;
+                window.removeEventListener('vrdisplaypresentchange', this._onVRFullScreenTriggered, false);
+            }
+        }
+
+        private _onVRFullScreenTriggered = () => {
+            if (this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
+                //get the old size before we change
+                this._oldSize = new BABYLON.Size(this.getRenderWidth(), this.getRenderHeight());
+                this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
+
+                //get the width and height, change the render size
+                var leftEye = this._vrDisplayEnabled.getEyeParameters('left');
+                var width, height;
+                this.setHardwareScalingLevel(1);
+                this.setSize(leftEye.renderWidth * 2, leftEye.renderHeight);
+
+            } else {
+                this.setHardwareScalingLevel(this._oldHardwareScaleFactor);
+                this.setSize(this._oldSize.width, this._oldSize.height);
+            }
+        }
+
+        private _getFrameRequester() {
+            if (this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
+                return this._vrDisplayEnabled;
+            } else {
+                return window;
+            }
+        }
+
+        private _getVRDisplays() {
+            var getWebVRDevices = (devices: Array<any>) => {
+                var size = devices.length;
+                var i = 0;
+
+                this._vrDisplays = devices.filter(function (device) {
+                    return devices[i] instanceof VRDisplay;
+                });
+
+                return this._vrDisplays;
+            }
+
+            //using a key due to typescript
+            if (navigator.getVRDisplays) {
+                this.vrDisplaysPromise = navigator.getVRDisplays().then(getWebVRDevices);
+            }
+        }
+
         public bindFramebuffer(texture: WebGLTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number): void {
         public bindFramebuffer(texture: WebGLTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number): void {
             this._currentRenderTarget = texture;
             this._currentRenderTarget = texture;
             this.bindUnboundFramebuffer(texture._framebuffer);
             this.bindUnboundFramebuffer(texture._framebuffer);
             var gl = this._gl;
             var gl = this._gl;
             if (texture.isCube) {
             if (texture.isCube) {
-                
+
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture, 0);
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture, 0);
-            } 
+            }
 
 
             gl.viewport(0, 0, requiredWidth || texture._width, requiredHeight || texture._height);
             gl.viewport(0, 0, requiredWidth || texture._width, requiredHeight || texture._height);
 
 
@@ -1134,12 +1212,12 @@
                 var offset = 0;
                 var offset = 0;
                 for (var index = 0; index < attributesCount; index++) {
                 for (var index = 0; index < attributesCount; index++) {
 
 
-                    if(index < vertexDeclaration.length){
+                    if (index < vertexDeclaration.length) {
 
 
                         var order = effect.getAttributeLocation(index);
                         var order = effect.getAttributeLocation(index);
 
 
                         if (order >= 0) {
                         if (order >= 0) {
-                            if(!this._vertexAttribArraysEnabled[order]){
+                            if (!this._vertexAttribArraysEnabled[order]) {
                                 this._gl.enableVertexAttribArray(order);
                                 this._gl.enableVertexAttribArray(order);
                                 this._vertexAttribArraysEnabled[order] = true;
                                 this._vertexAttribArraysEnabled[order] = true;
                             }
                             }
@@ -1148,11 +1226,11 @@
 
 
                         offset += vertexDeclaration[index] * 4;
                         offset += vertexDeclaration[index] * 4;
 
 
-                    }else{
+                    } else {
 
 
                         //disable effect attributes that have no data
                         //disable effect attributes that have no data
                         var order = effect.getAttributeLocation(index);
                         var order = effect.getAttributeLocation(index);
-                        if(this._vertexAttribArraysEnabled[order]){
+                        if (this._vertexAttribArraysEnabled[order]) {
                             this._gl.disableVertexAttribArray(order);
                             this._gl.disableVertexAttribArray(order);
                             this._vertexAttribArraysEnabled[order] = false;
                             this._vertexAttribArraysEnabled[order] = false;
                         }
                         }
@@ -1183,14 +1261,14 @@
                         var vertexBuffer = vertexBuffers[attributes[index]];
                         var vertexBuffer = vertexBuffers[attributes[index]];
 
 
                         if (!vertexBuffer) {
                         if (!vertexBuffer) {
-                            if(this._vertexAttribArraysEnabled[order]){
+                            if (this._vertexAttribArraysEnabled[order]) {
                                 this._gl.disableVertexAttribArray(order);
                                 this._gl.disableVertexAttribArray(order);
                                 this._vertexAttribArraysEnabled[order] = false;
                                 this._vertexAttribArraysEnabled[order] = false;
                             }
                             }
                             continue;
                             continue;
                         }
                         }
 
 
-                        if(!this._vertexAttribArraysEnabled[order]){
+                        if (!this._vertexAttribArraysEnabled[order]) {
                             this._gl.enableVertexAttribArray(order);
                             this._gl.enableVertexAttribArray(order);
                             this._vertexAttribArraysEnabled[order] = true;
                             this._vertexAttribArraysEnabled[order] = true;
                         }
                         }
@@ -1269,7 +1347,7 @@
                 for (let i = 0; i < offsetLocations.length; i++) {
                 for (let i = 0; i < offsetLocations.length; i++) {
                     let ai = <InstancingAttributeInfo>offsetLocations[i];
                     let ai = <InstancingAttributeInfo>offsetLocations[i];
 
 
-                    if(!this._vertexAttribArraysEnabled[ai.index]){
+                    if (!this._vertexAttribArraysEnabled[ai.index]) {
                         this._gl.enableVertexAttribArray(ai.index);
                         this._gl.enableVertexAttribArray(ai.index);
                         this._vertexAttribArraysEnabled[ai.index] = true;
                         this._vertexAttribArraysEnabled[ai.index] = true;
                     }
                     }
@@ -1283,7 +1361,7 @@
                 for (let index = 0; index < 4; index++) {
                 for (let index = 0; index < 4; index++) {
                     let offsetLocation = <number>offsetLocations[index];
                     let offsetLocation = <number>offsetLocations[index];
 
 
-                    if(!this._vertexAttribArraysEnabled[offsetLocation]){
+                    if (!this._vertexAttribArraysEnabled[offsetLocation]) {
                         this._gl.enableVertexAttribArray(offsetLocation);
                         this._gl.enableVertexAttribArray(offsetLocation);
                         this._vertexAttribArraysEnabled[offsetLocation] = true;
                         this._vertexAttribArraysEnabled[offsetLocation] = true;
                     }
                     }
@@ -2104,7 +2182,7 @@
             this.bindUnboundFramebuffer(framebuffer);
             this.bindUnboundFramebuffer(framebuffer);
 
 
             // Manage attachments
             // Manage attachments
-            if (generateStencilBuffer) {                
+            if (generateStencilBuffer) {
                 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
                 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
             }
             }
             else if (generateDepthBuffer) {
             else if (generateDepthBuffer) {
@@ -2134,7 +2212,7 @@
             texture.references = 1;
             texture.references = 1;
             texture.samplingMode = samplingMode;
             texture.samplingMode = samplingMode;
             texture.type = type;
             texture.type = type;
-            
+
             this.resetTextureCache();
             this.resetTextureCache();
 
 
             this._loadedTexturesCache.push(texture);
             this._loadedTexturesCache.push(texture);
@@ -2201,7 +2279,7 @@
             this.bindUnboundFramebuffer(framebuffer);
             this.bindUnboundFramebuffer(framebuffer);
 
 
             // Manage attachments
             // Manage attachments
-            if (generateStencilBuffer) {                
+            if (generateStencilBuffer) {
                 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
                 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthStencilBuffer);
             }
             }
             else if (generateDepthBuffer) {
             else if (generateDepthBuffer) {
@@ -2768,6 +2846,9 @@
 
 
             this._gl = null;
             this._gl = null;
 
 
+            //WebVR
+            this.disableVR();
+
             // Events
             // Events
             window.removeEventListener("blur", this._onBlur);
             window.removeEventListener("blur", this._onBlur);
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener("focus", this._onFocus);

+ 1 - 1
src/babylon.mixins.ts

@@ -97,7 +97,7 @@ interface MSStyleCSSProperties {
 }
 }
 
 
 interface Navigator {
 interface Navigator {
-    getVRDevices: () => any;
+    getVRDisplays: () => any;
     mozGetVRDevices: (any: any) => any;
     mozGetVRDevices: (any: any) => any;
     isCocoonJS: boolean;
     isCocoonJS: boolean;
 }
 }