Procházet zdrojové kódy

enable experimental features during session init

Raanan Weber před 5 roky
rodič
revize
7126d61aba

+ 2 - 2
src/LibDeclarations/webxr.d.ts

@@ -69,8 +69,8 @@ interface XRInputSource {
 }
 
 interface XRSessionInit {
-    optionalFeatures?: XRReferenceSpaceType[];
-    requiredFeatures?: XRReferenceSpaceType[];
+    optionalFeatures?: string[];
+    requiredFeatures?: string[];
 }
 
 interface XRSession extends XRAnchorCreator {

+ 12 - 3
src/XR/features/WebXRHitTest.ts

@@ -4,6 +4,7 @@ import { Observable } from '../../Misc/observable';
 import { Vector3, Matrix, Quaternion } from '../../Maths/math.vector';
 import { WebXRAbstractFeature } from './WebXRAbstractFeature';
 import { IWebXRLegacyHitTestOptions, IWebXRLegacyHitResult } from './WebXRHitTestLegacy';
+import { Tools } from '../../Misc/tools';
 
 /**
  * Options used for hit testing (version 2)
@@ -68,12 +69,19 @@ export class WebXRHitTest extends WebXRAbstractFeature {
     private _transientXrHitTestSource: XRTransientInputHitTestSource;
     // in XR space z-forward is negative
     private _xrHitTestSource: XRHitTestSource;
-    private initHitTestSource = () => {
+    private initHitTestSource = (referenceSpace: XRReferenceSpace) => {
+        if (!referenceSpace) {
+            return;
+        }
         const offsetRay = new XRRay(this.options.offsetRay || {});
         const options: XRHitTestOptionsInit = {
-            space: this.options.useReferenceSpace ? this._xrSessionManager.referenceSpace : this._xrSessionManager.viewerReferenceSpace,
+            space: this.options.useReferenceSpace ? referenceSpace : this._xrSessionManager.viewerReferenceSpace,
             offsetRay: offsetRay
         };
+        if (!options.space) {
+            Tools.Warn('waiting for viewer reference space to initialize');
+            return;
+        }
         this._xrSessionManager.session.requestHitTestSource(options).then((hitTestSource) => {
             if (this._xrHitTestSource) {
                 this._xrHitTestSource.cancel();
@@ -123,6 +131,7 @@ export class WebXRHitTest extends WebXRAbstractFeature {
          */
         public readonly options: IWebXRHitTestOptions = {}) {
         super(_xrSessionManager);
+        Tools.Warn('Hit test is an experimental and unstable feature. make sure you enable optionalFeatures when creating the XR session');
     }
 
     /**
@@ -138,7 +147,7 @@ export class WebXRHitTest extends WebXRAbstractFeature {
 
         if (!this.options.disablePermanentHitTest) {
             if (this._xrSessionManager.referenceSpace) {
-                this.initHitTestSource();
+                this.initHitTestSource(this._xrSessionManager.referenceSpace);
             }
             this._xrSessionManager.onXRReferenceSpaceChanged.add(this.initHitTestSource);
         }

+ 18 - 3
src/XR/webXRDefaultExperience.ts

@@ -52,6 +52,12 @@ export class WebXRDefaultExperienceOptions {
      * An optional rendering group id that will be set globally for teleportation, pointer selection and default controller meshes
      */
     public renderingGroupId?: number;
+
+    /**
+     * A list of optional features to init the session with
+     * If set to true, all features we support will be added
+     */
+    optionalFeatures?: boolean | string[];
 }
 
 /**
@@ -131,11 +137,20 @@ export class WebXRDefaultExperience {
             result.renderTarget = result.baseExperience.sessionManager.getWebXRRenderTarget(options.outputCanvasOptions);
 
             if (!options.disableDefaultUI) {
-                if (options.uiOptions) {
-                    options.uiOptions.renderTarget = options.uiOptions.renderTarget || result.renderTarget;
+
+                const uiOptions: WebXREnterExitUIOptions = {
+                    renderTarget: result.renderTarget,
+                    ...(options.uiOptions || {})
+                };
+                if (options.optionalFeatures) {
+                    if (typeof options.optionalFeatures === 'boolean') {
+                        uiOptions.optionalFeatures = ['hit-test', 'anchors'/*, 'hand-tracking'*/];
+                    } else {
+                        uiOptions.optionalFeatures = options.optionalFeatures;
+                    }
                 }
                 // Create ui for entering/exiting xr
-                return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, options.uiOptions || { renderTarget: result.renderTarget }).then((ui) => {
+                return WebXREnterExitUI.CreateAsync(scene, result.baseExperience, uiOptions).then((ui) => {
                     result.enterExitUI = ui;
                 });
             } else {

+ 6 - 1
src/XR/webXREnterExitUI.ts

@@ -53,6 +53,11 @@ export class WebXREnterExitUIOptions {
      * Default is immersive-vr
      */
     sessionMode?: XRSessionMode;
+
+    /**
+     * A list of optional features to init the session with
+     */
+    optionalFeatures?: string[];
 }
 /**
  * UI to allow the user to enter/exit XR mode
@@ -152,7 +157,7 @@ export class WebXREnterExitUI implements IDisposable {
                         } else if (helper.state == WebXRState.NOT_IN_XR) {
                             if (options.renderTarget) {
                                 try {
-                                    await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget);
+                                    await helper.enterXRAsync(ui._buttons[i].sessionMode, ui._buttons[i].referenceSpaceType, options.renderTarget, {optionalFeatures: options.optionalFeatures});
                                     ui._updateButtons(ui._buttons[i]);
                                 } catch (e) {
                                     // make sure button is visible

+ 6 - 4
src/XR/webXRExperienceHelper.ts

@@ -91,16 +91,18 @@ export class WebXRExperienceHelper implements IDisposable {
      * @param sessionMode options for the XR session
      * @param referenceSpaceType frame of reference of the XR session
      * @param renderTarget the output canvas that will be used to enter XR mode
+     * @param sessionCreationOptions optional XRSessionInit object to init the session with
      * @returns promise that resolves after xr mode has entered
      */
-    public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget = this.sessionManager.getWebXRRenderTarget()): Promise<WebXRSessionManager> {
+    public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget = this.sessionManager.getWebXRRenderTarget(), sessionCreationOptions: XRSessionInit = {}): Promise<WebXRSessionManager> {
         if (!this._supported) {
             throw "WebXR not supported in this browser or environment";
         }
         this._setState(WebXRState.ENTERING_XR);
-        let sessionCreationOptions: XRSessionInit = {
-            optionalFeatures: (referenceSpaceType !== "viewer" && referenceSpaceType !== "local") ? [referenceSpaceType] : []
-        };
+        if (referenceSpaceType !== "viewer" && referenceSpaceType !== "local") {
+            sessionCreationOptions.optionalFeatures = sessionCreationOptions.optionalFeatures || [];
+            sessionCreationOptions.optionalFeatures.push(referenceSpaceType);
+        }
         // we currently recommend "unbounded" space in AR (#7959)
         if (sessionMode === "immersive-ar" && referenceSpaceType !== "unbounded") {
             Logger.Warn("We recommend using 'unbounded' reference space type when using 'immersive-ar' session mode");

+ 6 - 4
src/XR/webXRSessionManager.ts

@@ -267,12 +267,14 @@ export class WebXRSessionManager implements IDisposable {
                 throw "XR initialization failed: required \"viewer\" reference space type not supported.";
             });
         }).then((referenceSpace) => {
+            // create viewer reference space before setting the first reference space
+            return this.session.requestReferenceSpace("viewer").then((viewerReferenceSpace: XRReferenceSpace) => {
+                this.viewerReferenceSpace = viewerReferenceSpace;
+                return referenceSpace;
+            });
+        }).then((referenceSpace) => {
             // initialize the base and offset (currently the same)
             this.referenceSpace = this.baseReferenceSpace = referenceSpace;
-
-            this.session.requestReferenceSpace("viewer").then((referenceSpace: XRReferenceSpace) => {
-                this.viewerReferenceSpace = referenceSpace;
-            });
             return this.referenceSpace;
         });
     }