浏览代码

latest updates

Trevor Baron 6 年之前
父节点
当前提交
f7bb283a47

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

@@ -64,7 +64,7 @@ export class WebXREnterExitUI implements IDisposable {
     public static CreateAsync(scene: Scene, helper: WebXRExperienceHelper, options: WebXREnterExitUIOptions): Promise<WebXREnterExitUI> {
         var ui = new WebXREnterExitUI(scene, options);
         var supportedPromises = ui._buttons.map((btn) => {
-            return helper.supportsSessionAsync(btn.initializationOptions);
+            return null;//helper.supportsSessionAsync(btn.initializationOptions);
         });
         helper.onStateChangedObservable.add((state) => {
             if (state == WebXRState.NOT_IN_XR) {
@@ -82,7 +82,7 @@ export class WebXREnterExitUI implements IDisposable {
                             return;
                         } else if (helper.state == WebXRState.NOT_IN_XR) {
                             ui._updateButtons(ui._buttons[i]);
-                            await helper.enterXRAsync(ui._buttons[i].initializationOptions, "eye-level");
+                            //await helper.enterXRAsync(ui._buttons[i].initializationOptions, "eye-level");
                         }
                     };
                 }
@@ -101,20 +101,20 @@ export class WebXREnterExitUI implements IDisposable {
             var hmdBtn = document.createElement("button");
             hmdBtn.style.cssText = "color: #868686; border-color: #868686; border-style: solid; margin-left: 10px; height: 50px; width: 80px; background-color: rgba(51,51,51,0.7); background-repeat:no-repeat; background-position: center; outline: none;";
             hmdBtn.innerText = "HMD";
-            this._buttons.push(new WebXREnterExitUIButton(hmdBtn, { immersive: true, outputContext: options.outputCanvasContext }));
-            this._buttons[this._buttons.length - 1].update = function(activeButton: WebXREnterExitUIButton) {
-                this.element.style.display = (activeButton === null || activeButton === this) ? "" : "none";
-                this.element.innerText = activeButton === this ? "EXIT" : "HMD";
-            };
+            // this._buttons.push(new WebXREnterExitUIButton(hmdBtn, { immersive: true, outputContext: options.outputCanvasContext }));
+            // this._buttons[this._buttons.length - 1].update = function(activeButton: WebXREnterExitUIButton) {
+            //     this.element.style.display = (activeButton === null || activeButton === this) ? "" : "none";
+            //     this.element.innerText = activeButton === this ? "EXIT" : "HMD";
+            // };
 
-            var windowBtn = document.createElement("button");
-            windowBtn.style.cssText = hmdBtn.style.cssText;
-            windowBtn.innerText = "Window";
-            this._buttons.push(new WebXREnterExitUIButton(windowBtn, { immersive: false, environmentIntegration: true, outputContext: options.outputCanvasContext }));
-            this._buttons[this._buttons.length - 1].update = function(activeButton: WebXREnterExitUIButton) {
-                this.element.style.display = (activeButton === null || activeButton === this) ? "" : "none";
-                this.element.innerText = activeButton === this ? "EXIT" : "Window";
-            };
+            // var windowBtn = document.createElement("button");
+            // windowBtn.style.cssText = hmdBtn.style.cssText;
+            // windowBtn.innerText = "Window";
+            // this._buttons.push(new WebXREnterExitUIButton(windowBtn, { immersive: false, environmentIntegration: true, outputContext: options.outputCanvasContext }));
+            // this._buttons[this._buttons.length - 1].update = function(activeButton: WebXREnterExitUIButton) {
+            //     this.element.style.display = (activeButton === null || activeButton === this) ? "" : "none";
+            //     this.element.innerText = activeButton === this ? "EXIT" : "Window";
+            // };
             this._updateButtons(null);
         }
 
@@ -145,4 +145,4 @@ export class WebXREnterExitUI implements IDisposable {
         }
         this.activeButtonChangedObservable.clear();
     }
-}
+}

+ 40 - 26
src/Cameras/XR/webXRExperienceHelper.ts

@@ -7,6 +7,7 @@ import { Ray } from "../../Culling/ray";
 import { Camera } from "../../Cameras/camera";
 import { WebXRSessionManager } from "./webXRSessionManager";
 import { WebXRCamera } from "./webXRCamera";
+import { WebXRManagedOutputCanvas } from './webXRManagedOutputCanvas';
 /**
  * States of the webXR experience
  */
@@ -59,8 +60,8 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     public onStateChangedObservable = new Observable<WebXRState>();
 
-    /** @hidden */
-    public _sessionManager: WebXRSessionManager;
+    /** Session manager used to keep track of xr session */
+    public sessionManager: WebXRSessionManager;
 
     private _nonVRCamera: Nullable<Camera> = null;
     private _originalSceneAutoClear = true;
@@ -74,7 +75,7 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     public static CreateAsync(scene: Scene): Promise<WebXRExperienceHelper> {
         var helper = new WebXRExperienceHelper(scene);
-        return helper._sessionManager.initializeAsync().then(() => {
+        return helper.sessionManager.initializeAsync().then(() => {
             helper._supported = true;
             return helper;
         }).catch(() => {
@@ -88,7 +89,7 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     private constructor(private scene: Scene) {
         this.camera = new WebXRCamera("", scene);
-        this._sessionManager = new WebXRSessionManager(scene);
+        this.sessionManager = new WebXRSessionManager(scene);
         this.container = new AbstractMesh("", scene);
         this.camera.parent = this.container;
     }
@@ -99,7 +100,7 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     public exitXRAsync() {
         this._setState(WebXRState.EXITING_XR);
-        return this._sessionManager.exitXRAsync();
+        return this.sessionManager.exitXRAsync();
     }
 
     /**
@@ -108,13 +109,21 @@ export class WebXRExperienceHelper implements IDisposable {
      * @param frameOfReference frame of reference of the XR session
      * @returns promise that resolves after xr mode has entered
      */
-    public enterXRAsync(sessionCreationOptions: XRSessionCreationOptions, frameOfReference: string) {
+    public enterXRAsync(sessionCreationOptions: XRSessionCreationOptions, frameOfReference: ReferenceSpaceOptions, outputCanvas: WebXRManagedOutputCanvas) {
         if (!this._supported) {
             throw "XR session not supported by this browser";
         }
         this._setState(WebXRState.ENTERING_XR);
-
-        return this._sessionManager.enterXRAsync(sessionCreationOptions, frameOfReference).then(() => {
+        this.sessionManager.initializeSessionAsync(sessionCreationOptions).then(()=>{
+            return this.sessionManager.setReferenceSpaceAsync(frameOfReference)
+        }).then(()=>{
+            return outputCanvas.initializeXRLayerAsync(this.sessionManager._xrSession);
+        }).then(()=>{
+            return this.sessionManager.updateRenderStateAsync({baseLayer: outputCanvas.xrLayer, outputContext: outputCanvas.canvasContext})
+        }).then(()=>{
+            console.log("base layer set")
+            return this.sessionManager.startRenderingToXRAsync();
+        }).then(()=>{
             // Cache pre xr scene settings
             this._originalSceneAutoClear = this.scene.autoClear;
             this._nonVRCamera = this.scene.activeCamera;
@@ -123,11 +132,12 @@ export class WebXRExperienceHelper implements IDisposable {
             this.scene.autoClear = false;
             this.scene.activeCamera = this.camera;
 
-            this._sessionManager.onXRFrameObservable.add(() => {
-                this.camera.updateFromXRSessionManager(this._sessionManager);
+            this.sessionManager.onXRFrameObservable.add(() => {
+                console.log("frame")
+                this.camera.updateFromXRSessionManager(this.sessionManager);
             });
 
-            this._sessionManager.onXRSessionEnded.addOnce(() => {
+            this.sessionManager.onXRSessionEnded.addOnce(() => {
                 // Reset camera rigs output render target to ensure sessions render target is not drawn after it ends
                 this.camera.rigCameras.forEach((c) => {
                     c.outputRenderTarget = null;
@@ -136,11 +146,15 @@ export class WebXRExperienceHelper implements IDisposable {
                 // Restore scene settings
                 this.scene.autoClear = this._originalSceneAutoClear;
                 this.scene.activeCamera = this._nonVRCamera;
-                this._sessionManager.onXRFrameObservable.clear();
+                this.sessionManager.onXRFrameObservable.clear();
 
                 this._setState(WebXRState.NOT_IN_XR);
             });
             this._setState(WebXRState.IN_XR);
+            console.log("started!")
+        }).catch((e:any)=>{
+            console.log("FAILUE")
+            console.log(e)
         });
     }
 
@@ -150,7 +164,7 @@ export class WebXRExperienceHelper implements IDisposable {
      * @returns Promise which resolves with a collision point in the environment if it exists
      */
     public environmentPointHitTestAsync(ray: Ray): Promise<Nullable<Vector3>> {
-        return this._sessionManager.environmentPointHitTestAsync(ray);
+        return this.sessionManager.environmentPointHitTestAsync(ray);
     }
 
     /**
@@ -176,17 +190,17 @@ export class WebXRExperienceHelper implements IDisposable {
         this.container.position.rotateByQuaternionAroundPointToRef(rotation, this.camera.globalPosition, this.container.position);
     }
 
-    /**
-     * Checks if the creation options are supported by the xr session
-     * @param options creation options
-     * @returns true if supported
-     */
-    public supportsSessionAsync(options: XRSessionCreationOptions) {
-        if (!this._supported) {
-            return Promise.resolve(false);
-        }
-        return this._sessionManager.supportsSessionAsync(options);
-    }
+    // /**
+    //  * Checks if the creation options are supported by the xr session
+    //  * @param options creation options
+    //  * @returns true if supported
+    //  */
+    // public supportsSessionAsync(options: XRSessionCreationOptions) {
+    //     if (!this._supported) {
+    //         return Promise.resolve(false);
+    //     }
+    //     return this.sessionManager.supportsSessionAsync(options);
+    // }
 
     /**
      * Disposes of the experience helper
@@ -195,6 +209,6 @@ export class WebXRExperienceHelper implements IDisposable {
         this.camera.dispose();
         this.container.dispose();
         this.onStateChangedObservable.clear();
-        this._sessionManager.dispose();
+        this.sessionManager.dispose();
     }
-}
+}

+ 7 - 7
src/Cameras/XR/webXRInput.ts

@@ -52,16 +52,16 @@ export class WebXRInput implements IDisposable {
      * @param helper experience helper which the input should be created for
      */
     public constructor(private helper: WebXRExperienceHelper) {
-        this._frameObserver = helper._sessionManager.onXRFrameObservable.add(() => {
-            if (!helper._sessionManager._currentXRFrame || !helper._sessionManager._currentXRFrame.getDevicePose) {
+        this._frameObserver = helper.sessionManager.onXRFrameObservable.add(() => {
+            if (!helper.sessionManager._currentXRFrame || !helper.sessionManager._currentXRFrame.getDevicePose) {
                 return;
             }
 
-            var xrFrame = helper._sessionManager._currentXRFrame;
-            var inputSources = helper._sessionManager._xrSession.getInputSources();
+            var xrFrame = helper.sessionManager._currentXRFrame;
+            var inputSources = helper.sessionManager._xrSession.getInputSources();
 
             inputSources.forEach((input, i) => {
-                let inputPose = xrFrame.getInputPose(input, helper._sessionManager._frameOfReference);
+                let inputPose = xrFrame.getInputPose(input, helper.sessionManager._frameOfReference);
                 if (inputPose) {
                     if (this.controllers.length <= i) {
                         this.controllers.push(new WebXRController(helper.container.getScene()));
@@ -103,6 +103,6 @@ export class WebXRInput implements IDisposable {
         this.controllers.forEach((c) => {
             c.dispose();
         });
-        this.helper._sessionManager.onXRFrameObservable.remove(this._frameObserver);
+        this.helper.sessionManager.onXRFrameObservable.remove(this._frameObserver);
     }
-}
+}

+ 13 - 5
src/Cameras/XR/webXRManagedOutputCanvas.ts

@@ -9,13 +9,21 @@ export class WebXRManagedOutputCanvas implements IDisposable {
     /**
      * xrpresent context of the canvas which can be used to display/mirror xr content
      */
-    public canvasContext: Nullable<WebGLRenderingContext> = null;
+    public canvasContext: WebGLRenderingContext;
+    public xrLayer:any;
+    
+    public initializeXRLayerAsync(xrSession:any){
+        return (this.canvasContext as any).makeXRCompatible().then(()=>{
+            this.xrLayer = new XRWebGLLayer(xrSession, this.canvasContext);
+        });
+    }
+
     /**
      * Initializes the canvas to be added/removed upon entering/exiting xr
      * @param helper the xr experience helper used to trigger adding/removing of the canvas
      * @param canvas The canvas to be added/removed (If not specified a full screen canvas will be created)
      */
-    public constructor(helper: WebXRExperienceHelper, canvas?: HTMLCanvasElement) {
+    constructor(helper: WebXRExperienceHelper, canvas?: HTMLCanvasElement) {
         if (!canvas) {
             canvas = document.createElement('canvas');
             canvas.style.cssText = "position:absolute; bottom:0px;right:0px;z-index:10;width:100%;height:100%;background-color: #000000;";
@@ -42,10 +50,10 @@ export class WebXRManagedOutputCanvas implements IDisposable {
         this._removeCanvas();
         if (!canvas) {
             this._canvas = null;
-            this.canvasContext = null;
+            (this.canvasContext as any) = null;
         } else {
             this._canvas = canvas;
-            this.canvasContext = <any>this._canvas.getContext('xrpresent');
+            this.canvasContext = <any>this._canvas.getContext('webgl');
         }
     }
 
@@ -60,4 +68,4 @@ export class WebXRManagedOutputCanvas implements IDisposable {
             document.body.removeChild(this._canvas);
         }
     }
-}
+}

+ 60 - 48
src/Cameras/XR/webXRSessionManager.ts

@@ -29,8 +29,8 @@ export class WebXRSessionManager implements IDisposable {
     /** @hidden */
     public _currentXRFrame: Nullable<XRFrame>;
     private _xrNavigator: any;
-    private _xrDevice: XRDevice;
     private _tmpMatrix = new Matrix();
+    private baseLayer:Nullable<XRWebGLLayer> = null;
 
     /**
      * Constructs a WebXRSessionManager, this must be initialized within a user action before usage
@@ -52,22 +52,11 @@ export class WebXRSessionManager implements IDisposable {
         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);
-        });
+        return Promise.resolve();
     }
 
-    /**
-     * Enters XR with the desired XR session options, this must be done with a user action (eg. button click event)
-     * @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 enterXRAsync(sessionCreationOptions: XRSessionCreationOptions, frameOfReferenceType: string): Promise<void> {
-        // initialize session
-        return this._xrDevice.requestSession(sessionCreationOptions).then((session: XRSession) => {
+    public initializeSessionAsync(sessionCreationOptions: XRSessionCreationOptions){
+        return this._xrNavigator.xr.requestSession(sessionCreationOptions).then((session: XRSession) => {
             this._xrSession = session;
 
             // handle when the session is ended (By calling session.end or device ends its own session eg. pressing home button on phone)
@@ -83,30 +72,43 @@ export class WebXRSessionManager implements IDisposable {
                 this.onXRSessionEnded.notifyObservers(null);
                 this.scene.getEngine()._renderLoop();
             }, { once: true });
-
-            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: Nullable<XRFrame>) => {
-                    // Store the XR frame in the manager to be consumed by the XR camera to update pose
-                    this._currentXRFrame = xrFrame;
-                    this.onXRFrameObservable.notifyObservers(null);
-                    this.scene.getEngine()._renderLoop();
-                }
-            };
-            // Create render target texture from xr's webgl render target
-            this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(this._xrSession, this.scene);
-
-            // Stop window's animation frame and trigger sessions animation frame
-            window.cancelAnimationFrame(this.scene.getEngine()._frameHandler);
-            this.scene.getEngine()._renderLoop();
         });
     }
 
+    public setReferenceSpaceAsync(referenceSpaceOptions: ReferenceSpaceOptions){
+        return this._xrSession.requestReferenceSpace(referenceSpaceOptions).then((referenceSpace: any)=>{
+            this._frameOfReference = referenceSpace;
+        })
+    }
+
+    public updateRenderStateAsync(state:any){
+        if(state.baseLayer){
+            this.baseLayer = state.baseLayer;
+        }
+        return this._xrSession.updateRenderState(state);
+    }
+
+    public startRenderingToXRAsync(){
+        // 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: Nullable<XRFrame>) => {
+                // Store the XR frame in the manager to be consumed by the XR camera to update pose
+                this._currentXRFrame = xrFrame;
+                this.onXRFrameObservable.notifyObservers(null);
+                this.scene.getEngine()._renderLoop();
+            }
+        };
+        // Create render target texture from xr's webgl render target
+        this._sessionRenderTargetTexture = WebXRSessionManager._CreateRenderTargetTextureFromSession(this._xrSession, this.scene, this.baseLayer!);
+
+        // Stop window's animation frame and trigger sessions animation frame
+        window.cancelAnimationFrame(this.scene.getEngine()._frameHandler);
+        debugger;
+        this.scene.getEngine()._renderLoop();
+        return Promise.resolve();
+    }
+
     /**
      * Stops the xrSession and restores the renderloop
      * @returns Promise which resolves after it exits XR
@@ -151,15 +153,20 @@ export class WebXRSessionManager implements IDisposable {
 
     /**
      * Checks if a session would be supported for the creation options specified
-     * @param options creation options to check if they are supported
+     * @param sessionMode session mode to check if supported eg. immersive-vr
      * @returns true if supported
      */
-    public supportsSessionAsync(options: XRSessionCreationOptions) {
-        return this._xrDevice.supportsSession(options).then(() => {
-            return true;
-        }).catch(() => {
-            return false;
-        });
+    public supportsSessionModeAsync(sessionMode: string) {
+        if(!(navigator as any).xr || !(navigator as any).xr.supportsSessionMode){
+            return Promise.resolve(false);
+        }else{
+            return (navigator as any).xr.supportsSessionMode(sessionMode).then(()=>{
+                return Promise.resolve(true)
+            }).catch((e:any)=>{
+                Logger.Warn(e)
+                return Promise.resolve(false);
+            })
+        }
     }
 
     /**
@@ -168,12 +175,17 @@ export class WebXRSessionManager implements IDisposable {
      * @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: Scene) {
+    public static _CreateRenderTargetTextureFromSession(session: XRSession, scene: Scene, baseLayer: XRWebGLLayer) {
+        console.log("creating render target")
+        if(!baseLayer){
+            throw "no layer"
+        }
+        //debugger;
         // Create internal texture
         var internalTexture = new InternalTexture(scene.getEngine(), InternalTexture.DATASOURCE_UNKNOWN, true);
-        internalTexture.width = session.baseLayer.framebufferWidth;
-        internalTexture.height = session.baseLayer.framebufferHeight;
-        internalTexture._framebuffer = session.baseLayer.framebuffer;
+        internalTexture.width = baseLayer.framebufferWidth;
+        internalTexture.height = baseLayer.framebufferHeight;
+        internalTexture._framebuffer = baseLayer.framebuffer;
 
         // Create render target texture from the internal texture
         var renderTargetTexture = new RenderTargetTexture("XR renderTargetTexture", { width: internalTexture.width, height: internalTexture.height }, scene, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, true);
@@ -189,4 +201,4 @@ export class WebXRSessionManager implements IDisposable {
         this.onXRFrameObservable.clear();
         this.onXRSessionEnded.clear();
     }
-}
+}

+ 9 - 4
src/LibDeclarations/webxr.d.ts

@@ -5,17 +5,22 @@ interface XRDevice {
 interface XRSession {
     getInputSources(): Array<any>;
     baseLayer: XRWebGLLayer;
-    requestFrameOfReference(type: string): Promise<void>;
+    requestReferenceSpace(options: ReferenceSpaceOptions): Promise<void>;
     requestHitTest(origin: Float32Array, direction: Float32Array, frameOfReference: any): any;
     end(): Promise<void>;
+    updateRenderState(state:any):Promise<void>;
     requestAnimationFrame: Function;
     addEventListener: Function;
 }
 interface XRSessionCreationOptions {
-    outputContext?: WebGLRenderingContext | null;
-    immersive?: boolean;
-    environmentIntegration?: boolean;
+    mode?: string;
 }
+
+interface ReferenceSpaceOptions {
+    type?: string;
+    subtype?: string;
+}
+
 interface XRLayer {
     getViewport: Function;
     framebufferWidth: number;