Bladeren bron

Adjusting to the WebVR specs

Thou working when called multiple times, the requestAnimationFrame
should only be called once when the device is presenting.
Also added the possibility of auto-enabling WebVR, while not being
initialized automatically.  This was done because when WebVR is
initializing it starts the native VR software, which might not be
desired.
The WebVR camera forces WebVR init.
Raanan Weber 9 jaren geleden
bovenliggende
commit
88d4d6413a
3 gewijzigde bestanden met toevoegingen van 49 en 22 verwijderingen
  1. 27 15
      src/Cameras/VR/babylon.webVRCamera.ts
  2. 4 1
      src/Tools/babylon.tools.ts
  3. 18 6
      src/babylon.engine.ts

+ 27 - 15
src/Cameras/VR/babylon.webVRCamera.ts

@@ -26,23 +26,30 @@ module BABYLON {
             vrCameraMetrics.compensateDistortion = compensateDistortion;
             this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: vrCameraMetrics });
 
-            //this._getWebVRDevices = this._getWebVRDevices.bind(this);
+            //enable VR
+            this.getEngine().initWebVR();
+
             if (!this.getEngine().vrDisplaysPromise) {
                 Tools.Error("WebVR is not enabled on your browser");
             } else {
                 //TODO get the metrics updated using the device's eye parameters!
+                //TODO also check that the device has the right capabilities!
                 this.getEngine().vrDisplaysPromise.then((devices) => {
                     if (devices.length > 0) {
                         this._vrEnabled = true;
                         if (this.webVROptions.displayName) {
-                            devices.some(device => {
+                            var found = devices.some(device => {
                                 if (device.displayName === this.webVROptions.displayName) {
                                     this._vrDevice = device;
                                     return true;
                                 } else {
                                     return false;
                                 }
-                            })
+                            });
+                            if (!found) {
+                                this._vrDevice = devices[0];
+                                Tools.Warn("Display " + this.webVROptions.displayName + " was not found. Using " + this._vrDevice.displayName);
+                            }
                         } else {
                             //choose the first one
                             this._vrDevice = devices[0];
@@ -59,19 +66,24 @@ module BABYLON {
 
         public _checkInputs(): void {
             if (this._vrEnabled) {
-                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]);
-                    this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale)
-                }
-                //Flip in XY plane
-                this.rotationQuaternion.z *= -1;
-                this.rotationQuaternion.w *= -1;
-                if (this._initialQuaternion) {
-                    this._quaternionCache.copyFrom(this.rotationQuaternion);
-                    this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                var currentPost = this._vrDevice.getPose();
+                //make sure we have data
+                if (currentPost && currentPost.orientation) {
+                    this._cacheState = currentPost;
+                    this.rotationQuaternion.copyFromFloats(this._cacheState.orientation[0], this._cacheState.orientation[1], this._cacheState.orientation[2], this._cacheState.orientation[3]);
+                    if (this.webVROptions.trackPosition && this._cacheState.position) {
+                        this.position.copyFromFloats(this._cacheState.position[0], this._cacheState.position[1], -this._cacheState.position[2]);
+                        this.webVROptions.positionScale && this.position.scaleInPlace(this.webVROptions.positionScale)
+                    }
+                    //Flip in XY plane
+                    this.rotationQuaternion.z *= -1;
+                    this.rotationQuaternion.w *= -1;
+                    if (this._initialQuaternion) {
+                        this._quaternionCache.copyFrom(this.rotationQuaternion);
+                        this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
+                    }
                 }
+
             }
 
             super._checkInputs();

+ 4 - 1
src/Tools/babylon.tools.ts

@@ -256,7 +256,10 @@
          * @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)
+            //if WebVR is enabled AND presenting, requestAnimationFrame is triggered when enabled.
+            if(requester.isPresenting) {
+                return;
+            } else if (requester.requestAnimationFrame)
                 requester.requestAnimationFrame(func);
             else if (requester.msRequestAnimationFrame)
                 requester.msRequestAnimationFrame(func);

+ 18 - 6
src/babylon.engine.ts

@@ -187,6 +187,7 @@
 
     export interface EngineOptions extends WebGLContextAttributes {
         limitDeviceRatio?: number;
+        autoEnableWebVR?: boolean;
     }
 
     /**
@@ -321,6 +322,7 @@
         private _vrDisplayEnabled;
         private _oldSize: BABYLON.Size;
         private _oldHardwareScaleFactor: number;
+        private _vrAnimationFrameHandler: number;
 
         // Private Members
         public _gl: WebGLRenderingContext;
@@ -564,7 +566,9 @@
             this._loadingScreen = new DefaultLoadingScreen(this._renderingCanvas);
 
             //Load WebVR Devices
-            this._getVRDisplays();
+            if(options.autoEnableWebVR) {
+                this.initWebVR();
+            }
 
             Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
         }
@@ -908,7 +912,7 @@
             //this.flushFramebuffer();
 
             //submit frame to the vr device, if enabled
-            if(this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
+            if (this._vrDisplayEnabled && this._vrDisplayEnabled.isPresenting) {
                 this._vrDisplayEnabled.submitFrame()
             }
         }
@@ -957,6 +961,12 @@
 
         //WebVR functions
 
+        public initWebVR() {
+            if (!this.vrDisplaysPromise) {
+                this._getVRDisplays();
+            }
+        }
+
         public enableVR(vrDevice) {
             this._vrDisplayEnabled = vrDevice;
             this._vrDisplayEnabled.requestPresent([{ source: this.getRenderingCanvas() }]).then(this._onVRFullScreenTriggered);
@@ -964,9 +974,7 @@
 
         public disableVR() {
             if (this._vrDisplayEnabled) {
-                this._vrDisplayEnabled.exitPresent();
-                this._vrDisplayEnabled = null;
-                this._onVRFullScreenTriggered()
+                this._vrDisplayEnabled.exitPresent().then(this._onVRFullScreenTriggered);
             }
         }
 
@@ -976,13 +984,17 @@
                 this._oldSize = new BABYLON.Size(this.getRenderWidth(), this.getRenderHeight());
                 this._oldHardwareScaleFactor = this.getHardwareScalingLevel();
 
+                //according to the WebVR specs, requestAnimationFrame should be triggered only once.
+                this._vrAnimationFrameHandler = this._vrDisplayEnabled.requestAnimationFrame(this._bindedRenderFunction);
+
                 //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._vrDisplayEnabled.cancelAnimationFrame(this._vrAnimationFrameHandler);
+                this._vrDisplayEnabled = null;
                 this.setHardwareScalingLevel(this._oldHardwareScaleFactor);
                 this.setSize(this._oldSize.width, this._oldSize.height);
             }