浏览代码

Merge pull request #7097 from RaananW/isSessionSupported

[WIP] WebXR emulator full support
David Catuhe 5 年之前
父节点
当前提交
360a104f50

+ 2 - 1
dist/preview release/what's new.md

@@ -136,13 +136,14 @@
 
 ### WebXR / WebVR
 
-- Compliance with the mozilla WebXR emulator ([RaananW](https://github.com/RaananW/))
+- Compliance with the mozilla WebXR emulator for chrome and firefox ([RaananW](https://github.com/RaananW/))
 - Use the same icon as in VR ([RaananW](https://github.com/RaananW/))
 - Gamepad object is now exposed in the WebXRController class ([RaananW](https://github.com/RaananW/))
 - If canvas does not have WebXR support the scene will still render (mainly Firefox) ([RaananW](https://github.com/RaananW/))
 - Added support for foveated rendering in Oculus Quest ([Deltakosh](https://github.com/deltakosh/))
 - Added option to configure the output canvas ([RaananW](https://github.com/RaananW/))
 - Supporting multisampled multiview rendering using the oculus multiview extension ([RaananW](https://github.com/RaananW/))
+- Preparing to deprecate supportsSession in favor of isSupportedSession ([RaananW](https://github.com/RaananW/))
 
 ### Ray
 

+ 24 - 15
src/Cameras/XR/webXRCamera.ts

@@ -11,7 +11,11 @@ import { Viewport } from '../../Maths/math.viewport';
  * @see https://doc.babylonjs.com/how_to/webxr
  */
 export class WebXRCamera extends FreeCamera {
-    private static _TmpMatrix = new Matrix();
+
+    /**
+     * Is the camera in debug mode. Used when using an emulator
+     */
+    public debugMode = false;
 
     /**
      * Creates a new webXRCamera, this should only be set at the camera after it has been updated by the xrSessionManager
@@ -72,38 +76,40 @@ export class WebXRCamera extends FreeCamera {
         if (!pose) {
             return false;
         }
-        let globalTransform = false;
-        if (pose && pose.transform && pose.transform.matrix) {
-            globalTransform = true;
-            // Update the parent cameras matrix
-            Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, WebXRCamera._TmpMatrix);
 
+        if (pose.transform && pose.emulatedPosition) {
+            this.position.copyFrom(<any>(pose.transform.position));
+            this.rotationQuaternion.copyFrom(<any>(pose.transform.orientation));
             if (!this._scene.useRightHandedSystem) {
-                WebXRCamera._TmpMatrix.toggleModelMatrixHandInPlace();
+                this.position.z *= -1;
+                this.rotationQuaternion.z *= -1;
+                this.rotationQuaternion.w *= -1;
             }
-            WebXRCamera._TmpMatrix.getTranslationToRef(this.position);
-            WebXRCamera._TmpMatrix.getRotationMatrixToRef(WebXRCamera._TmpMatrix);
-            Quaternion.FromRotationMatrixToRef(WebXRCamera._TmpMatrix, this.rotationQuaternion);
-
             this.computeWorldMatrix();
         }
 
         // Update camera rigs
         this._updateNumberOfRigCameras(pose.views.length);
         pose.views.forEach((view: any, i: number) => {
-            const currentRig = <TargetCamera> this.rigCameras[i];
+            const currentRig = <TargetCamera>this.rigCameras[i];
             // Update view/projection matrix
-            if (!globalTransform && view.transform.position && view.transform.orientation) {
+            if (view.transform.position && view.transform.orientation) {
                 currentRig.position.copyFrom(view.transform.position);
                 currentRig.rotationQuaternion.copyFrom(view.transform.orientation);
-                currentRig.getViewMatrix(true);
+                if (!this._scene.useRightHandedSystem) {
+                    currentRig.position.z *= -1;
+                    currentRig.rotationQuaternion.z *= -1;
+                    currentRig.rotationQuaternion.w *= -1;
+                }
             } else {
                 Matrix.FromFloat32ArrayToRefScaled(view.transform.matrix, 0, 1, currentRig._computedViewMatrix);
+                if (!this._scene.useRightHandedSystem) {
+                    currentRig._computedViewMatrix.toggleModelMatrixHandInPlace();
+                }
             }
             Matrix.FromFloat32ArrayToRefScaled(view.projectionMatrix, 0, 1, currentRig._projectionMatrix);
 
             if (!this._scene.useRightHandedSystem) {
-                currentRig._computedViewMatrix.toggleModelMatrixHandInPlace();
                 currentRig._projectionMatrix.toggleProjectionMatrixHandInPlace();
             }
 
@@ -117,6 +123,9 @@ export class WebXRCamera extends FreeCamera {
                 currentRig.viewport.x = viewport.x / width;
                 currentRig.viewport.y = viewport.y / height;
             }
+            if (this.debugMode) {
+                this._updateForDualEyeDebugging();
+            }
 
             // Set cameras to render to the session's render target
             currentRig.outputRenderTarget = xrSessionManager.getRenderTargetTextureForEye(view.eye);

+ 8 - 8
src/Cameras/XR/webXRController.ts

@@ -48,6 +48,7 @@ export class WebXRController {
         public inputSource: XRInputSource,
         private parentContainer: Nullable<AbstractMesh> = null) {
         this.pointer = new AbstractMesh("controllerPointer", scene);
+        this.pointer.rotationQuaternion = new Quaternion();
         if (parentContainer) {
             parentContainer.addChild(this.pointer);
         }
@@ -72,14 +73,13 @@ export class WebXRController {
 
         // Update the pointer mesh
         if (pose) {
-            Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
-            if (!this.pointer.getScene().useRightHandedSystem) {
-                this._tmpMatrix.toggleModelMatrixHandInPlace();
+            this.pointer.position.copyFrom(<any>(pose.transform.position));
+            this.pointer.rotationQuaternion!.copyFrom(<any>(pose.transform.orientation));
+            if (!this.scene.useRightHandedSystem) {
+                this.pointer.position.z *= -1;
+                this.pointer.rotationQuaternion!.z *= -1;
+                this.pointer.rotationQuaternion!.w *= -1;
             }
-            if (!this.pointer.rotationQuaternion) {
-                this.pointer.rotationQuaternion = new Quaternion();
-            }
-            this._tmpMatrix.decompose(this.pointer.scaling, this.pointer.rotationQuaternion!, this.pointer.position);
         }
 
         // Update the grip mesh if it exists
@@ -87,7 +87,7 @@ export class WebXRController {
             let pose = xrFrame.getPose(this.inputSource.gripSpace, referenceSpace);
             if (pose) {
                 Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
-                if (!this.grip.getScene().useRightHandedSystem) {
+                if (!this.scene.useRightHandedSystem) {
                     this._tmpMatrix.toggleModelMatrixHandInPlace();
                 }
                 if (!this.grip.rotationQuaternion) {

+ 22 - 31
src/Cameras/XR/webXRControllerModelLoader.ts

@@ -1,4 +1,4 @@
-import { Quaternion } from '../../Maths/math.vector';
+import { Quaternion, Vector3 } from '../../Maths/math.vector';
 import { WindowsMotionController } from '../../Gamepads/Controllers/windowsMotionController';
 import { OculusTouchController } from '../../Gamepads/Controllers/oculusTouchController';
 import { WebXRInput } from './webXRInput';
@@ -21,56 +21,47 @@ export class WebXRControllerModelLoader {
 
             let controllerModel: WebVRController;
 
+            let rotation: Quaternion;
+            const position = new Vector3();
+
             switch (c.inputSource.gamepad.id) {
                 case "htc-vive": {
                     controllerModel = new ViveController(c.inputSource.gamepad);
-                    controllerModel.hand = c.inputSource.handedness;
-                    controllerModel.isXR = true;
-                    controllerModel.initControllerMesh(c.getScene(), (m) => {
-                        m.isPickable = false;
-                        m.getChildMeshes(false).forEach((m) => {
-                            m.isPickable = false;
-                        });
-                        controllerModel.mesh!.parent = c.grip!;
-                        controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
-                    });
+                    rotation = Quaternion.FromEulerAngles(0, Math.PI, 0);
                     break;
                 }
                 case "oculus-touch": {
                     controllerModel = new OculusTouchController(c.inputSource.gamepad);
-                    controllerModel.hand = c.inputSource.handedness;
-                    controllerModel.isXR = true;
-                    controllerModel.initControllerMesh(c.getScene(), (m) => {
-                        controllerModel.mesh!.parent = c.grip!;
-                        controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
-                        controllerModel.mesh!.position.y = 0.034;
-                        controllerModel.mesh!.position.z = 0.052;
-                    });
+                    rotation = Quaternion.FromEulerAngles(0, Math.PI, 0);
+                    position.y = 0.034;
+                    position.z = 0.052;
                     break;
                 }
                 case "oculus-quest": {
                     OculusTouchController._IsQuest = true;
                     controllerModel = new OculusTouchController(c.inputSource.gamepad);
-                    controllerModel.hand = c.inputSource.handedness;
-                    controllerModel.isXR = true;
-                    controllerModel.initControllerMesh(c.getScene(), (m) => {
-                        controllerModel.mesh!.parent = c.grip!;
-                        controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(Math.PI / -4, Math.PI, 0);
-                    });
+                    rotation = Quaternion.FromEulerAngles(Math.PI / -4, Math.PI, 0);
                     break;
                 }
                 default: {
                     controllerModel = new WindowsMotionController(c.inputSource.gamepad);
-                    controllerModel.hand = c.inputSource.handedness;
-                    controllerModel.isXR = true;
-                    controllerModel.initControllerMesh(c.getScene(), (m) => {
-                        controllerModel.mesh!.parent = c.grip!;
-                        controllerModel.mesh!.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);
-                    });
+                    rotation = Quaternion.FromEulerAngles(0, Math.PI, 0);
                     break;
                 }
             }
 
+            controllerModel.hand = c.inputSource.handedness;
+            controllerModel.isXR = true;
+            controllerModel.initControllerMesh(c.getScene(), (m) => {
+                controllerModel.mesh!.parent = c.grip || input.baseExperience.container;
+                controllerModel.mesh!.rotationQuaternion = rotation;
+                controllerModel.mesh!.position = position;
+                m.isPickable = false;
+                m.getChildMeshes(false).forEach((m) => {
+                    m.isPickable = false;
+                });
+            });
+
             c.gamepadController = controllerModel;
         });
     }

+ 10 - 2
src/Cameras/XR/webXRControllerPointerSelection.ts

@@ -39,7 +39,7 @@ export class WebXRControllerPointerSelection {
             this._updatePointerDistance(laserPointer, 1);
             laserPointer.isPickable = false;
 
-            // Create a gaze tracker for the  XR controlelr
+            // Create a gaze tracker for the  XR controller
             cursorMesh = Mesh.CreateTorus("gazeTracker", 0.0035 * 3, 0.0025 * 3, 20, scene, false);
             cursorMesh.bakeCurrentTransformIntoVertices();
             cursorMesh.isPickable = false;
@@ -55,7 +55,15 @@ export class WebXRControllerPointerSelection {
                 controller.getWorldPointerRayToRef(this._tmpRay);
                 let pick = scene.pickWithRay(this._tmpRay);
                 if (pick) {
-                    if (controller.inputSource.gamepad && controller.inputSource.gamepad.buttons[0] && controller.inputSource.gamepad.buttons[0].value > 0.7) {
+                    let pressed = false;
+                    if (controller.inputSource.gamepad) {
+                        if (controller.inputSource.gamepad.buttons[0] && controller.inputSource.gamepad.buttons[0].value > 0.7) {
+                            pressed = true;
+                        } else if (controller.inputSource.gamepad.buttons[1] && controller.inputSource.gamepad.buttons[1].pressed) {
+                            pressed = true;
+                        }
+                    }
+                    if (pressed) {
                         if (!triggerDown) {
                             scene.simulatePointerDown(pick, { pointerId: id });
                         }

+ 9 - 4
src/Cameras/XR/webXRSessionManager.ts

@@ -182,7 +182,7 @@ export class WebXRSessionManager implements IDisposable {
      * @param eye the eye for which to get the render target
      * @returns the render target for the specified eye
      */
-    public getRenderTargetTextureForEye(eye: XREye) : RenderTargetTexture {
+    public getRenderTargetTextureForEye(eye: XREye): RenderTargetTexture {
         return this._rttProvider!.getRenderTargetForEye(eye);
     }
 
@@ -203,10 +203,15 @@ export class WebXRSessionManager implements IDisposable {
      * @returns true if supported
      */
     public supportsSessionAsync(sessionMode: XRSessionMode) {
-        if (!(navigator as any).xr || !(navigator as any).xr.supportsSession) {
+        if (!(navigator as any).xr) {
+            return Promise.resolve(false);
+        }
+        // When the specs are final, remove supportsSession!
+        const functionToUse = (navigator as any).xr.isSessionSupported || (navigator as any).xr.supportsSession;
+        if (!functionToUse) {
             return Promise.resolve(false);
         } else {
-            return (navigator as any).xr.supportsSession(sessionMode).then(() => {
+            return functionToUse.call((navigator as any).xr, sessionMode).then(() => {
                 return Promise.resolve(true);
             }).catch((e: any) => {
                 Logger.Warn(e);
@@ -221,7 +226,7 @@ export class WebXRSessionManager implements IDisposable {
      * @param options optional options to provide when creating a new render target
      * @returns a WebXR render target to which the session can render
      */
-    public getWebXRRenderTarget(onStateChangedObservable?: Observable<WebXRState>, options?: WebXRManagedOutputCanvasOptions) : WebXRRenderTarget {
+    public getWebXRRenderTarget(onStateChangedObservable?: Observable<WebXRState>, options?: WebXRManagedOutputCanvasOptions): WebXRRenderTarget {
         if (this._xrNavigator.xr.native) {
             return this._xrNavigator.xr.getWebXRRenderTarget(this.scene.getEngine());
         }