Ver código fonte

In-progress changes. Not working yet, I just don't want to lose them.

Justin Murray 5 anos atrás
pai
commit
f022365cd7

+ 1 - 0
src/Cameras/XR/index.ts

@@ -7,4 +7,5 @@ export * from "./webXRControllerPointerSelection";
 export * from "./webXRControllerModelLoader";
 export * from "./webXRController";
 export * from "./webXRManagedOutputCanvas";
+export * from "./webXROutputTarget";
 export * from "./webXRSessionManager";

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

@@ -85,7 +85,7 @@ export class WebXRCamera extends FreeCamera {
 
         // Update camera rigs
         this._updateNumberOfRigCameras(pose.views.length);
-        pose.views.forEach((view: any, i: number) => {
+        pose.views.forEach((view: XRView, i: number) => {
             // Update view/projection matrix
             Matrix.FromFloat32ArrayToRefScaled(view.transform.matrix, 0, 1, this.rigCameras[i]._computedViewMatrix);
             Matrix.FromFloat32ArrayToRefScaled(view.projectionMatrix, 0, 1, this.rigCameras[i]._projectionMatrix);
@@ -106,7 +106,7 @@ export class WebXRCamera extends FreeCamera {
             }
 
             // Set cameras to render to the session's render target
-            this.rigCameras[i].outputRenderTarget = xrSessionManager._sessionRenderTargetTexture;
+            this.rigCameras[i].outputRenderTarget = xrSessionManager.getRenderTargetTextureForEye(view.eye);
         });
         return true;
     }

+ 31 - 11
src/Cameras/XR/webXRDefaultExperience.ts

@@ -5,8 +5,10 @@ import { WebXRControllerModelLoader } from './webXRControllerModelLoader';
 import { WebXRControllerPointerSelection } from './webXRControllerPointerSelection';
 import { WebXRControllerTeleportation } from './webXRControllerTeleportation';
 import { WebXRManagedOutputCanvas } from './webXRManagedOutputCanvas';
+import { WebXROutputTarget } from './webXROutputTarget';
 import { WebXREnterExitUI } from './webXREnterExitUI';
 import { AbstractMesh } from '../../Meshes/abstractMesh';
+
 /**
  * Options for the default xr helper
  */
@@ -15,6 +17,11 @@ export class WebXRDefaultExperienceOptions {
      * Floor meshes that should be used for teleporting
      */
     public floorMeshes: Array<AbstractMesh>;
+
+    /**
+     * Enable or disable default UI to enter XR
+     */
+    public disableDefaultUI: boolean;
 }
 
 /**
@@ -46,9 +53,9 @@ export class WebXRDefaultExperience {
      */
     public enterExitUI: WebXREnterExitUI;
     /**
-     * Default output canvas xr should render to
+     * Default target xr should render to
      */
-    public outputCanvas: WebXRManagedOutputCanvas;
+    public outputTarget: WebXROutputTarget;
 
     /**
      * Creates the default xr experience
@@ -67,15 +74,28 @@ export class WebXRDefaultExperience {
             result.input = new WebXRInput(xrHelper);
             result.controllerModelLoader = new WebXRControllerModelLoader(result.input);
             result.pointerSelection = new WebXRControllerPointerSelection(result.input);
-            result.teleportation = new WebXRControllerTeleportation(result.input, options.floorMeshes);
 
-            // Create output canvas manager (this controls where the xr frames will be rendered)
-            result.outputCanvas = new WebXRManagedOutputCanvas(xrHelper, scene.getEngine().getRenderingCanvas() as HTMLCanvasElement);
+            if (options.floorMeshes) {
+                result.teleportation = new WebXRControllerTeleportation(result.input, options.floorMeshes);
+            }
+
+            if (result.baseExperience.sessionManager.supportsWebXRNativeOutputTarget()) {
+                // Create the WebXR output for native experiences.
+                result.outputTarget = result.baseExperience.sessionManager.getWebXRNativeOutputTarget();
+            } else {
+                // Create output canvas manager (this controls where the xr frames will be rendered)
+                result.outputTarget = new WebXRManagedOutputCanvas(xrHelper, scene.getEngine().getRenderingCanvas() as HTMLCanvasElement);
+            }
 
-            // Create ui for entering/exiting xr
-            return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, {webXRManagedOutputCanvas: result.outputCanvas});
-        }).then((ui) => {
-            result.enterExitUI = ui;
+            if (!options.disableDefaultUI) {
+                // Create ui for entering/exiting xr
+                return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, { outputTarget: result.outputTarget }).then((ui) => {
+                    result.enterExitUI = ui;
+                });
+            } else {
+                return;
+            }
+        }).then(() => {
             return result;
         });
     }
@@ -97,8 +117,8 @@ export class WebXRDefaultExperience {
         if (this.enterExitUI) {
             this.enterExitUI.dispose();
         }
-        if (this.outputCanvas) {
-            this.outputCanvas.dispose();
+        if (this.outputTarget) {
+            this.outputTarget.dispose();
         }
     }
 }

+ 4 - 4
src/Cameras/XR/webXREnterExitUI.ts

@@ -2,7 +2,7 @@ import { Nullable } from "../../types";
 import { Observable } from "../../Misc/observable";
 import { IDisposable, Scene } from "../../scene";
 import { WebXRExperienceHelper, WebXRState } from "./webXRExperienceHelper";
-import { WebXRManagedOutputCanvas } from '../XR/webXRManagedOutputCanvas';
+import { WebXROutputTarget } from './webXROutputTarget';
 /**
  * Button which can be used to enter a different mode of XR
  */
@@ -36,7 +36,7 @@ export class WebXREnterExitUIOptions {
     /**
      * Context to enter xr with
      */
-    webXRManagedOutputCanvas?: Nullable<WebXRManagedOutputCanvas>;
+    outputTarget?: Nullable<WebXROutputTarget>;
 
     /**
      * User provided buttons to enable/disable WebXR. The system will provide default if not set
@@ -86,8 +86,8 @@ export class WebXREnterExitUI implements IDisposable {
                             return;
                         } else if (helper.state == WebXRState.NOT_IN_XR) {
                             ui._updateButtons(ui._buttons[i]);
-                            if (options.webXRManagedOutputCanvas) {
-                                await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.webXRManagedOutputCanvas);
+                            if (options.outputTarget) {
+                                await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.outputTarget);
                             }
                         }
                     };

+ 5 - 5
src/Cameras/XR/webXRExperienceHelper.ts

@@ -6,7 +6,7 @@ import { AbstractMesh } from "../../Meshes/abstractMesh";
 import { Camera } from "../../Cameras/camera";
 import { WebXRSessionManager } from "./webXRSessionManager";
 import { WebXRCamera } from "./webXRCamera";
-import { WebXRManagedOutputCanvas } from './webXRManagedOutputCanvas';
+import { WebXROutputTarget } from './webXROutputTarget';
 /**
  * States of the webXR experience
  */
@@ -110,10 +110,10 @@ export class WebXRExperienceHelper implements IDisposable {
      * Enters XR mode (This must be done within a user interaction in most browsers eg. button click)
      * @param sessionCreationOptions options for the XR session
      * @param referenceSpaceType frame of reference of the XR session
-     * @param outputCanvas the output canvas that will be used to enter XR mode
+     * @param outputTarget the output canvas that will be used to enter XR mode
      * @returns promise that resolves after xr mode has entered
      */
-    public enterXRAsync(sessionCreationOptions: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, outputCanvas: WebXRManagedOutputCanvas) {
+    public enterXRAsync(sessionCreationOptions: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, outputTarget: WebXROutputTarget) {
         if (!this._supported) {
             throw "XR session not supported by this browser";
         }
@@ -121,9 +121,9 @@ export class WebXRExperienceHelper implements IDisposable {
         return this.sessionManager.initializeSessionAsync(sessionCreationOptions).then(() => {
             return this.sessionManager.setReferenceSpaceAsync(referenceSpaceType);
         }).then(() => {
-            return outputCanvas.initializeXRLayerAsync(this.sessionManager.session);
+            return outputTarget.initializeXRLayerAsync(this.sessionManager.session);
         }).then(() => {
-            return this.sessionManager.updateRenderStateAsync({ depthFar: this.camera.maxZ, depthNear: this.camera.minZ, baseLayer: outputCanvas.xrLayer! });
+            return this.sessionManager.updateRenderStateAsync({ depthFar: this.camera.maxZ, depthNear: this.camera.minZ, baseLayer: outputTarget.xrLayer! });
         }).then(() => {
             return this.sessionManager.startRenderingToXRAsync();
         }).then(() => {

+ 3 - 2
src/Cameras/XR/webXRManagedOutputCanvas.ts

@@ -1,10 +1,11 @@
 import { Nullable } from "../../types";
-import { IDisposable } from "../../scene";
 import { WebXRExperienceHelper, WebXRState } from "./webXRExperienceHelper";
+import { WebXROutputTarget } from "./webXROutputTarget";
+
 /**
  * Creates a canvas that is added/removed from the webpage when entering/exiting XR
  */
-export class WebXRManagedOutputCanvas implements IDisposable {
+export class WebXRManagedOutputCanvas implements WebXROutputTarget {
     private _canvas: Nullable<HTMLCanvasElement> = null;
     /**
      * xrpresent context of the canvas which can be used to display/mirror xr content

+ 21 - 0
src/Cameras/XR/webXROutputTarget.ts

@@ -0,0 +1,21 @@
+import { Nullable } from "../../types";
+import { IDisposable } from "../../scene";
+
+export interface WebXROutputTarget extends IDisposable {
+    /**
+     * xrpresent context of the canvas which can be used to display/mirror xr content
+     */
+    canvasContext: WebGLRenderingContext;
+
+    /**
+     * xr layer for the canvas
+     */
+    xrLayer: Nullable<XRWebGLLayer>;
+
+    /**
+     * Initializes the xr layer for the session
+     * @param xrSession xr session
+     * @returns a promise that will resolve once the XR Layer has been created
+     */
+    initializeXRLayerAsync(xrSession: XRSession) : Promise<void>;
+}

+ 50 - 7
src/Cameras/XR/webXRSessionManager.ts

@@ -4,6 +4,24 @@ import { Nullable } from "../../types";
 import { IDisposable, Scene } from "../../scene";
 import { InternalTexture } from "../../Materials/Textures/internalTexture";
 import { RenderTargetTexture } from "../../Materials/Textures/renderTargetTexture";
+import { WebXROutputTarget } from './webXROutputTarget';
+
+interface IRenderTargetProvider {
+    getRenderTargetForEye(eye: XREye): RenderTargetTexture;
+}
+
+class RenderTargetProvider implements IRenderTargetProvider {
+    private _texture: RenderTargetTexture;
+
+    public constructor(texture: RenderTargetTexture) {
+        this._texture = texture;
+    }
+
+    public getRenderTargetForEye(eye: XREye): RenderTargetTexture {
+        return this._texture;
+    }
+}
+
 /**
  * Manages an XRSession to work with Babylon's engine
  * @see https://doc.babylonjs.com/how_to/webxr
@@ -28,15 +46,14 @@ export class WebXRSessionManager implements IDisposable {
      */
     public referenceSpace: XRReferenceSpace;
 
-    /** @hidden */
-    public _sessionRenderTargetTexture: Nullable<RenderTargetTexture> = null;
-
     /**
      * Current XR frame
      */
     public currentFrame: Nullable<XRFrame>;
+
     private _xrNavigator: any;
     private baseLayer: Nullable<XRWebGLLayer> = null;
+    private _rttProvider: Nullable<IRenderTargetProvider>;
 
     /**
      * Constructs a WebXRSessionManager, this must be initialized within a user action before usage
@@ -73,7 +90,7 @@ export class WebXRSessionManager implements IDisposable {
             // handle when the session is ended (By calling session.end or device ends its own session eg. pressing home button on phone)
             this.session.addEventListener("end", () => {
                 // Remove render target texture and notify frame obervers
-                this._sessionRenderTargetTexture = null;
+                this._rttProvider = null;
 
                 // Restore frame buffer to avoid clear on xr framebuffer after session end
                 this.scene.getEngine().restoreDefaultFramebuffer();
@@ -124,8 +141,13 @@ export class WebXRSessionManager implements IDisposable {
                 this.scene.getEngine()._renderLoop();
             }
         };
-        // Create render target texture from xr's webgl render target
-        this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(this.session, this.scene, this.baseLayer!);
+
+        if (this.baseLayer) {
+            // Create render target texture from xr's webgl render target
+            this._rttProvider = new RenderTargetProvider(WebXRSessionManager._CreateRenderTargetTextureFromSession(this.session, this.scene, this.baseLayer!));
+        } else {
+            this._rttProvider = this._xrNavigator.xr.getNativeRenderTargetProvider(this.session);
+        }
 
         // Stop window's animation frame and trigger sessions animation frame
         window.cancelAnimationFrame(this.scene.getEngine()._frameHandler);
@@ -134,6 +156,15 @@ export class WebXRSessionManager implements IDisposable {
     }
 
     /**
+     * Gets the correct render target texture to be rendered this frame for this eye
+     * @param eye the eye for which to get the render target
+     * @returns the render target for the specified eye
+     */
+    public getRenderTargetTextureForEye(eye: XREye) : RenderTargetTexture {
+        return this._rttProvider!.getRenderTargetForEye(eye);
+    }
+
+    /**
      * Stops the xrSession and restores the renderloop
      * @returns Promise which resolves after it exits XR
      */
@@ -152,7 +183,7 @@ export class WebXRSessionManager implements IDisposable {
     public supportsSessionAsync(sessionMode: XRSessionMode) {
         if (!(navigator as any).xr || !(navigator as any).xr.supportsSession) {
             return Promise.resolve(false);
-        }else {
+        } else {
             return (navigator as any).xr.supportsSession(sessionMode).then(() => {
                 return Promise.resolve(true);
             }).catch((e: any) => {
@@ -163,6 +194,18 @@ export class WebXRSessionManager implements IDisposable {
     }
 
     /**
+     * Checks whether the getWebXRNativeOutputTarget() API is supported
+     * @returns true if getWebXRNativeOutputTarget() can be called, false otherwise
+     */
+    public supportsWebXRNativeOutputTarget() : boolean {
+        return this._xrNavigator.xr.native;
+    }
+
+    public getWebXRNativeOutputTarget() : WebXROutputTarget {
+        return this._xrNavigator.xr.getWebXROutputTarget(this.scene.getEngine());
+    }
+
+    /**
      * @hidden
      * Converts the render layer of xrSession to a render target
      * @param session session to create render target for