diff --git a/explainer.md b/explainer.md index 9250b2f8..6c01df84 100644 --- a/explainer.md +++ b/explainer.md @@ -21,10 +21,10 @@ That said, given the shared subject matter many of the same concepts are represe ### Goals Enable XR applications on the web by allowing pages to do the following: -* Detect available VR/AR devices. -* Query the devices capabilities. -* Poll the device’s position and orientation. -* Display imagery on the device at the appropriate frame rate. +* Detect if XR capabilities are available. +* Query the XR devices capabilities. +* Poll the XR device and associated input device state. +* Display imagery on the XR device at the appropriate frame rate. ### Non-goals @@ -50,75 +50,46 @@ VR provides an interesting canvas for artists looking to explore the possibiliti The basic steps most WebXR applications will go through are: - 1. Request an XR device. - 1. If a device is available, application advertises XR functionality to the user. + 1. Query to see if the desired XR mode is supported. + 1. If support is available, application advertises XR functionality to the user. 1. Request an immersive XR session from the device in response to a [user-activation event](https://html.spec.whatwg.org/multipage/interaction.html#activation). 1. Use the session to run a render loop that produces graphical frames to be displayed on the XR device. 1. Continue producing frames until the user indicates that they wish to exit XR mode. 1. End the XR session. -### Acquiring a Device +### XR hardware -The first thing that any XR-enabled page will want to do is request an `XRDevice` and, if one is available, advertise XR functionality to the user. (For example, by adding a button to the page that the user can click to start XR content.) +The UA will identify an available physical unit of XR hardware that can present imagery to the user, referred to here as an "XR device". On desktop clients this will usually be a headset peripheral; on mobile clients it may represent the mobile device itself in conjunction with a viewer harness (e.g., Google Cardboard/Daydream or Samsung Gear VR). It may also represent devices without stereo-presentation capabilities but with more advanced tracking, such as ARCore/ARKit-compatible devices. Any queries for XR capabilities or functionality are implicitly made against this device. -`navigator.xr.requestDevice` returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that resolves to an `XRDevice` if one is available. If no `XRDevice` is available, it will reject with a "NotFoundError". The promise will also be rejected with an appropriate error if an error occurs during the device query. For example, if the page does not have the appropriate permissions to access XR capabilities it would reject with a "NotAllowedError". +> **Non-normative Note:** If there are multiple XR devices available, the UA will need to pick which one to expose. The UA is allowed to use any criteria it wishes to select which device is used, including settings UI that allows users to manage device priority. Calling `navigator.xr.supportsSession` or `navigator.xr.requestSession` with `{ immersive: false }` should **not** trigger device-selection UI, however, as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation. -A `XRDevice` represents a physical unit of XR hardware that can present imagery to the user somehow, referred to here as an "XR hardware device". On desktop clients this will usually be a headset peripheral; on mobile clients it may represent the mobile device itself in conjunction with a viewer harness (e.g., Google Cardboard/Daydream or Samsung Gear VR). It may also represent devices without stereo-presentation capabilities but with more advanced tracking, such as ARCore/ARKit-compatible devices. +It's possible that even if no XR device is available initially, one may become available while the application is running, or that a previously available device becomes unavailable. This will be most common with PC peripherals that can be connected or disconnected at any time. Pages can listen to the `devicechange` event emitted on `navigator.xr` to respond to changes in device availability after the page loads. (XR devices already available when the page loads will not cause a `devicechange` event to be fired.) `devicechange` fires an event of type `Event`. ```js -function checkForXR() { - navigator.xr.requestDevice().then(device => { - onXRAvailable(device); - }, err => { - if (err.name === 'NotFoundError') { - // No XRDevices available. - console.error('No XR devices available:', err); - } else { - // An error occurred while requesting an XRDevice. - console.error('Requesting XR device failed:', err); - } - }); -} -``` - -Future revisions of the API may add filter criteria to `navigator.xr.requestDevice`. - -> **Non-normative Note:** If there are multiple XR devices available, the UA will need to pick which one to return. The UA is allowed to use any criteria it wishes to select which device is returned, including settings UI that allows users to manage device priority. Calling `navigator.xr.requestDevice` should not trigger device-selection UI, however, as this would cause many sites to display XR-specific dialogs early in the document lifecycle without user activation. - -It's possible that even if no XR device is available initially, one may become available while the application is running, or that a previously available device becomes unavailable. This will be most common with PC peripherals that can be connected or disconnected at any time. Pages can listen to the `devicechange` event emitted on `navigator.xr` to respond to changes in device availability after the page loads. (XR devices already available when the page loads will not cause a `devicechange` event to be fired.) - -```js -navigator.xr.addEventListener('devicechange', checkForXR); +navigator.xr.addEventListener('devicechange', checkForXRSupport); ``` -### Sessions - -A `XRDevice` indicates only the availability of an XR device. In order to do anything that involves the device's presentation or tracking capabilities, the application will need to request an `XRSession` from the `XRDevice`. +### Detecting and advertising XR capabilities -There are two primary classes of session that can be created: +The first thing that any XR-enabled page will want to do is query to determine if the type of XR content desired is supported by the current hardware and UA. If it is, the page can then advertise XR functionality to the user. (For example, by adding a button to the page that the user can click to start XR content.) -**Immersive**: Requested with the `immersive: true` dictionary argument. Immersive sessions present content directly to the `XRDevice`, enabling immersive presentation. Only one immersive session per XR hardware device is allowed at a time across the entire UA. Immersive sessions must be created within a user activation event or within another callback that has been explicitly indicated to allow immersive session creation. +Testing to see if the device supports the capabilities the application needs is done via the `navigator.xr.supportsSession` call, which takes a dictionary describing the desired functionality and returns a promise which resolves if the device can support those properties and rejects otherwise. Querying for support this way is necessary because it allows the application to detect what XR features are available without actually engaging the sensors or beginning presentation, which can incur significant power or performance overhead on some systems and may have side effects such as launching a status tray, launching a storefront, or terminating another application's access to XR hardware. Calling `navigator.xr.supportsSession` should also not interfere with any running XR applications on the system. -**Non-Immersive (in-page)**: The default mode, but can be explicitly requested with the `immersive: false` dictionary argument. Non-immersive sessions do not have the ability to display immersive content on the `XRDevice` but are able to access device tracking information and use it to render content on the page. This technique, where a scene rendered to the page is responsive to device movement, is sometimes referred to as "Magic Window" mode. It's especially useful for mobile devices, where moving the device can be used to look around a scene. Devices like Tango phones and tablets with 6DoF tracking capabilities may expose them via non-immersive sessions even if the hardware is not capable of immersive, stereo presentation. Any non-immersive sessions are suspended when an immersive session is active. Non-immersive sessions are not required to be created within a user activation event unless paired with another option that explicitly does require it. +There are two primary classes of XR content that can be displayed to the user: -### Detecting and advertising XR mode +**Immersive**: Indicated with the `immersive: true` dictionary argument. Immersive content is presented directly to the XR device (for example: displayed on a VR headset). Immersive presentation must be started within a user activation event or within another callback that has been explicitly indicated to allow immersive presentation. As a result, if immersive content is supported, the application will usually want to add some UI to trigger activation of "XR Presentation Mode", where the application can begin sending imagery to the device. -If an `XRDevice` is available and able to create an immersive session, the application will usually want to add some UI to trigger activation of "XR Presentation Mode", where the application can begin sending imagery to the device. Testing to see if the device supports the capabilities the application needs is done via the `supportsSession` call, which takes a dictionary of the desired functionality and returns a promise which resolves if the device can create a session which supporting those properties and rejects otherwise. Querying for support this way is necessary because it allows the application to detect what XR features are available without actually engaging the sensors or beginning presentation, which can incur significant power or performance overhead on some systems and may have side effects such as launching a status tray or storefront. +**Non-Immersive (in-page)**: The default mode, but can be explicitly requested with the `immersive: false` dictionary argument. Non-immersive content does not have the ability to display on the XR device, but is able to access device tracking information and use it to render content on the page. This technique, where a scene rendered to the page is responsive to device movement, is sometimes referred to as "Magic Window" mode. It's especially useful for mobile devices, where moving the device can be used to look around a scene. Devices like Tango phones and tablets with 6DoF tracking capabilities may expose them via non-immersive sessions even if the hardware is not capable of immersive, stereo presentation. -In the following examples we will focus on using immersive sessions, and cover non-immersive session use in the [`Advanced Functionality`](#non-immersive-sessions-magic-windows) section. With that in mind, we ask here if the `XRDevice` supports immersive sessions, since we want the ability to display imagery on the headset. +In the following examples we will focus on using immersive content, and cover non-immersive content use in the [`Advanced Functionality`](#non-immersive-sessions-magic-windows) section. With that in mind, this code checks for supports of immersive content, since we want the ability to display imagery on a device like a headset. ```js -let xrDevice = null; - -async function onXRAvailable(device) { - xrDevice = device; - - // Many XRDevices are capable of immersive presentation to - // the device, which is necessary to show imagery in a headset. If the device - // has that capability the page will want to add an "Enter VR" button (similar - // to "Enter Fullscreen") that triggers the page to begin showing imagery on - // the headset. - xrDevice.supportsSession({ immersive: true }).then(() => { +async function checkForXRSupport() { + // Check to see if there is an XR device available that's capable of immersive + // presentation (for example: displaying in a headset). If the device has that + // capability the page will want to add an "XR" button to the page (similar to + // a "Fullscreen" button) that starts the display of immersive content. + navigator.xr.supportsSession({ immersive: true }).then(() => { var enterXrBtn = document.createElement("button"); enterXrBtn.innerHTML = "Enter VR"; enterXrBtn.addEventListener("click", beginXRSession); @@ -129,15 +100,17 @@ async function onXRAvailable(device) { } ``` -### Beginning an XR session +### Sessions + +Checking `navigator.xr.supportsSession()` indicates only that the requested XR mode is supported. In order to do anything that involves the XR device's presentation or tracking capabilities, the application will need to request an `XRSession`. -Clicking the button in the previous sample will attempt to acquire an `XRSession` by callling `XRDevice`'s `requestSession()` method. This returns a promise that resolves to an `XRSession` upon success. When requesting a session, the capabilities that the returned session must have are passed in via a dictionary, exactly like the `supportsSession` call. If `supportsSession` resolved for a given dictionary, then calling `requestSession` with the same dictionary values should be reasonably expected to succeed, barring external factors (such as `requestSession` not being called in a user activation event for an immersive session.) The UA is ultimately responsible for determining if it can honor the request. +Clicking the button in the previous sample will attempt to acquire an `XRSession` by calling `navigator.xr.requestSession()` method. This returns a promise that resolves to an `XRSession` upon success. When requesting a session, the capabilities that the returned session must have are passed in via a dictionary, exactly like the `supportsSession` call. If `supportsSession` resolved for a given dictionary, then calling `requestSession` with the same dictionary values should be reasonably expected to succeed, barring external factors (such as `requestSession` not being called in a user activation event for an immersive session.) The UA is ultimately responsible for determining if it can honor the request. ```js function beginXRSession() { // requestSession must be called within a user gesture event // like click or touch when requesting an immersive session. - xrDevice.requestSession({ immersive: true }) + navigator.xr.requestSession({ immersive: true }) .then(onSessionStarted) .catch(err => { // May fail for a variety of reasons. Probably just want to @@ -146,6 +119,9 @@ function beginXRSession() { }); } ``` + +Only one immersive session per XR hardware device is allowed at a time across the entire UA. Any non-immersive sessions are suspended when an immersive session is active. Non-immersive sessions are not required to be created within a user activation event unless paired with another option that explicitly does require it. + Once the session has started, some setup must be done to prepare for rendering. - A `XRFrameOfReference` must be created to define the coordinate system in which the `XRDevicePose` objects will be defined. See the Advanced Functionality section for more details about frames of reference. - The depth range of the session should be set to something appropriate for the application. This range will be used in the construction of the projection matrices provided by `XRFrame`. @@ -178,21 +154,21 @@ function onSessionStarted(session) { The content to present to the device is defined by an `XRLayer`. In the initial version of the spec only one layer type, `XRWebGLLayer`, is defined and only one layer can be used at a time. This is set via the `XRSession`'s `baseLayer` attribute. Future iterations of the spec will define new types of `XRLayer`s. For example: a new layer type would be added to enable use with any new graphics APIs that get added to the browser. The ability to use multiple layers at once and have them composited by the UA will likely also be added in a future API revision. -In order for a WebGL canvas to be used with an `XRWebGLLayer`, its context must be _compatible_ with the `XRDevice`. This can mean different things for different environments. For example, on a desktop computer this may mean the context must be created against the graphics adapter that the `XRDevice` is physically plugged into. On most mobile devices though, that's not a concern and so the context will always be compatible. In either case, the WebXR application must take steps to ensure WebGL context compatibility before using it with an `XRWebGLLayer`. +In order for a WebGL canvas to be used with an `XRWebGLLayer`, its context must be _compatible_ with the XR device. This can mean different things for different environments. For example, on a desktop computer this may mean the context must be created against the graphics adapter that the XR device is physically plugged into. On most mobile devices though, that's not a concern and so the context will always be compatible. In either case, the WebXR application must take steps to ensure WebGL context compatibility before using it with an `XRWebGLLayer`. When it comes to ensuring canvas compatibility there's two broad categories that apps will fall under. **XR Enhanced:** The app can take advantage of XR hardware, but it's used as a progressive enhancement rather than a core part of the experience. Most users will probably not interact with the app's XR features, and as such asking them to make XR-centric decisions early in the app lifetime would be confusing and inappropriate. An example would be a news site with an embedded 360 photo gallery or video. (We expect the large majority of early WebXR content to fall into this category.) -This style of application should call `WebGLRenderingContextBase`'s `setCompatibleXRDevice()` method with the `XRDevice` in question. This will set a compatibility bit on the context that allows it to be used. Contexts without the compatibility bit will fail when attempting to create an `XRLayer` with them. In the event that a context is not already compatible with the `XRDevice` the [context will be lost and attempt to recreate itself](https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.13) using the compatible graphics adapter. It is the page's responsibility to handle WebGL context loss properly, recreating any necessary WebGL resources in response. If the context loss is not handled by the page, the promise returned by `setCompatibleXRDevice` will fail. The promise may also fail for a variety of other reasons, such as the context being actively used by a different, incompatible `XRDevice`. +This style of application should call `WebGLRenderingContextBase`'s `makeXRCompatible()` method. This will set a compatibility bit on the context that allows it to be used. Contexts without the compatibility bit will fail when attempting to create an `XRLayer` with them. In the event that a context is not already compatible with the XR device the [context will be lost and attempt to recreate itself](https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14.13) using the compatible graphics adapter. It is the page's responsibility to handle WebGL context loss properly, recreating any necessary WebGL resources in response. If the context loss is not handled by the page, the promise returned by `makeXRCompatible` will fail. The promise may also fail for a variety of other reasons, such as the context being actively used by a different, incompatible XR device. ```js let glCanvas = document.createElement("canvas"); let gl = glCanvas.getContext("webgl"); function setupWebGLLayer() { - // Make sure the canvas context we want to use is compatible with the device. - return gl.setCompatibleXRDevice(xrDevice).then(() => { + // Make sure the canvas context we want to use is compatible with the current xr device. + return gl.makeXRCompatible().then(() => { // The content that will be shown on the device is defined by the session's // baseLayer. xrSession.baseLayer = new XRWebGLLayer(xrSession, gl); @@ -200,13 +176,15 @@ function setupWebGLLayer() { } ``` -**XR Centric:** The app's primary use case is displaying XR content, and as such it doesn't mind initializing resources in an XR-centric fashion, which may include asking users to select a headset as soon as the app starts. An example would be a game which is dependent on XR presentation and input. These types of applications can avoid the need to call `setCompatibleXRDevice` and the possible context loss that it may trigger by passing the `XRDevice` that the context will be used with as a context creation argument. +**XR Centric:** The app's primary use case is displaying XR content, and as such it doesn't mind initializing resources in an XR-centric fashion, which may include asking users to select a headset as soon as the app starts. An example would be a game which is dependent on XR presentation and input. These types of applications can avoid the need to call `makeXRCompatible` and the possible context loss that it may trigger by passing the XR device that the context will be used with as a context creation argument. ```js -let gl = glCanvas.getContext("webgl", { compatibleXRDevice: xrDevice }); +let gl = glCanvas.getContext("webgl", { xrCompatible: true }); ``` -Ensuring context compatibility with an `XRDevice` through either method may have side effects on other graphics resources in the page, such as causing the entire user agent to switch from rendering using an integrated GPU to a discrete GPU. +Ensuring context compatibility with an XR device through either method may have side effects on other graphics resources in the page, such as causing the entire user agent to switch from rendering using an integrated GPU to a discrete GPU. + +If the system's underlying XR device changes (signaled by the `devicechange` event on the `navigator.xr` object) any previously set context compatibility bits will be cleared, and `makeXRCompatible` will need to be called again prior to using the context with a `XRWebGLLayer`. Any active sessions will also be ended, and as a result new `XRSession`s with corresponding new `XRWebGLLayer`s will need to be created as well. ### Main render loop @@ -266,7 +244,7 @@ function drawScene(view, pose) { ### Handling suspended sessions -The UA may temporarily "suspend" a session at any time. While suspended a session has restricted or throttled access to the `XRDevice` state and may process frames slowly or not at all. Suspended sessions can be reasonably be expected to be resumed at some point, usually when the user has finished performing whatever action triggered the suspension in the first place. +The UA may temporarily "suspend" a session at any time. While suspended a session has restricted or throttled access to the XR device state and may process frames slowly or not at all. Suspended sessions can be reasonably be expected to be resumed at some point, usually when the user has finished performing whatever action triggered the suspension in the first place. The UA may suspend a session if allowing the page to continue reading the headset position represents a security or privacy risk (like when the user is entering a password or URL with a virtual keyboard, in which case the head motion may infer the user's input), or if other content is obscuring the page's output. Additionally, non-immersive sessions are suspended while an immersive session is active. @@ -290,7 +268,7 @@ xrSession.addEventListener('focus', xrSessionEvent => { ### Ending the XR session -A `XRSession` is "ended" when it is no longer expected to be used. An ended session object becomes detached and all operations on the object will fail. Ended sessions cannot be restored, and if a new active session is needed it must be requested from `XRDevice.requestSession()`. +A `XRSession` is "ended" when it is no longer expected to be used. An ended session object becomes detached and all operations on the object will fail. Ended sessions cannot be restored, and if a new active session is needed it must be requested from `navigator.xr.requestSession()`. To manually end a session the application calls `XRSession`'s `end()` method. This returns a promise that, when resolved, indicates that presentation to the XR hardware device by that session has stopped. Once the session has ended any continued animation the application's requires should be done using `window.requestAnimationFrame()`. @@ -316,7 +294,7 @@ function onSessionEnd() { } ``` -The UA may end a session at any time for a variety of reasons. For example: The user may forcibly end presentation via a gesture to the UA, other native applications may take exclusive access of the XR hardware device, or the XR hardware device may become disconnected from the system. Well behaved applications should monitor the `end` event on the `XRSession` to detect when that happens. +The UA may end a session at any time for a variety of reasons. For example: The user may forcibly end presentation via a gesture to the UA, other native applications may take exclusive access of the XR hardware device, or the XR hardware device may become disconnected from the system. Additionally, if the system's underlying XR device changes (signaled by the `devicechange` event on the `navigator.xr` object) any active `XRSession`s will be ended. This applies to both Immersive and Non-immersive sessions. Well behaved applications should monitor the `end` event on the `XRSession` to detect when the UA forces the session to end. ```js xrSession.addEventListener('end', onSessionEnd); @@ -346,7 +324,7 @@ function beginXRSession() { let mirrorCtx = mirrorCanvas.getContext('xrpresent'); document.body.appendChild(mirrorCanvas); - xrDevice.requestSession({ immersive: true, outputContext: mirrorCtx }) + navigator.xr.requestSession({ immersive: true, outputContext: mirrorCtx }) .then(onSessionStarted) .catch((reason) => { console.log("requestSession failed: " + reason); }); } @@ -366,7 +344,7 @@ The [`RelativeOrientationSensor`](https://w3c.github.io/orientation-sensor/#rela Similar to mirroring, to make use of this mode an `XRPresentationContext` is provided as the `outputContext` at session creation time with a non-immersive session. At that point content rendered to the `XRSession`'s `baseLayer` will be rendered to the canvas associated with the `outputContext`. The UA is also allowed to composite in additional content if desired. In the future, if multiple `XRLayers` are used their composited result will be what is displayed in the `outputContext`. Requests to create a non-immersive session without an output context will be rejected. -Immersive and non-immersive sessions can use the same render loop, but there are some differences in behavior to be aware of. The sessions may run their render loops at at different rates. During immersive sessions the UA runs the rendering loop at the `XRDevice`'s native refresh rate. During non-immersive sessions the UA runs the rendering loop at the refresh rate of page (aligned with `window.requestAnimationFrame`.) The method of computation of `XRView` projection and view matrices also differs between immersive and non-immersive sessions, with non-immersive sessions taking into account the output canvas dimensions and possibly the position of the users head in relation to the canvas if that can be determined. +Immersive and non-immersive sessions can use the same render loop, but there are some differences in behavior to be aware of. The sessions may run their render loops at at different rates. During immersive sessions the UA runs the rendering loop at the XR device's native refresh rate. During non-immersive sessions the UA runs the rendering loop at the refresh rate of page (aligned with `window.requestAnimationFrame`.) The method of computation of `XRView` projection and view matrices also differs between immersive and non-immersive sessions, with non-immersive sessions taking into account the output canvas dimensions and possibly the position of the users head in relation to the canvas if that can be determined. Most instances of non-immersive sessions will only provide a single `XRView` to be rendered, but UA may request multiple views be rendered if, for example, it's detected that that output medium of the page supports stereo rendering. As a result pages should always draw every `XRView` provided by the `XRFrame` regardless of what type of session has been requested. @@ -379,18 +357,18 @@ document.body.appendChild(magicWindowCanvas); function beginMagicWindowXRSession() { // Request a non-immersive session for magic window rendering. - xrDevice.requestSession({ outputContext: magicWindowCtx }) + navigator.xr.requestSession({ outputContext: magicWindowCtx }) .then(OnSessionStarted) .catch((reason) => { console.log("requestSession failed: " + reason); }); } ``` -The UA may reject requests for a non-immersive sessions for a variety of reasons, such as the inability of the underlying hardware to provide tracking data without actively rendering to the device. Pages should be designed to robustly handle the inability to acquire non-immersive sessions. `XRDevice.supportsSession()` can be used if a page wants to test for non-immersive session support before attempting to create the `XRSession`. +The UA may reject requests for a non-immersive sessions for a variety of reasons, such as the inability of the underlying hardware to provide tracking data without actively rendering to the device. Pages should be designed to robustly handle the inability to acquire non-immersive sessions. `navigator.xr.supportsSession()` can be used if a page wants to test for non-immersive session support before attempting to create the `XRSession`. ```js function checkMagicWindowSupport() { // Check to see if the UA can support a non-immersive sessions with the given output context. - return xrDevice.supportsSession({ outputContext: magicWindowCtx }) + return navigator.xr.supportsSession({ outputContext: magicWindowCtx }) .then(() => { console.log("Magic Window content is supported!"); }) .catch((reason) => { console.log("Magic Window content is not supported: " + reason); }); } @@ -701,7 +679,7 @@ Any `XRDevicePose`s queried with a "head-model" `XRFrameOfReference` must have t ### Room-scale tracking and boundaries -Some XR devices have been configured with details about the area they are being used in, including things like where the floor is and what boundaries of the safe space is so that it can be communicated to the user in XR. It can be beneficial to render the virtual scene so that it lines up with the users physical space for added immersion, especially ensuring that the virtual floor and the physical floor align. This is frequently called "room scale" or "standing space". It helps the user feel grounded in the virtual space. WebXR refers to this type of bounded, floor-relative play space as a "stage". Applications can take advantage of that space by creating a stage `XRFrameOfReference`. This will report values relative to the floor, ideally at the center of the room. (In other words the users physical floor is at Y = 0.) Not all `XRDevices` will support this mode, however. `requestFrameOfReference` will reject the promise in that case. +Some XR devices have been configured with details about the area they are being used in, including things like where the floor is and what boundaries of the safe space is so that it can be communicated to the user in XR. It can be beneficial to render the virtual scene so that it lines up with the users physical space for added immersion, especially ensuring that the virtual floor and the physical floor align. This is frequently called "room scale" or "standing space". It helps the user feel grounded in the virtual space. WebXR refers to this type of bounded, floor-relative play space as a "stage". Applications can take advantage of that space by creating a stage `XRFrameOfReference`. This will report values relative to the floor, ideally at the center of the room. (In other words the users physical floor is at Y = 0.) Not all XR devices will support this mode, however. `requestFrameOfReference` will reject the promise in that case. ```js // Try to get a frame of reference where the floor is at Y = 0 @@ -801,7 +779,7 @@ When `XRWebGLLayer.multiview` is true: ```js function setupWebGLLayer() { - return gl.setCompatibleXRDevice(xrDevice).then(() => { + return gl.makeXRCompatible().then(() => { // XRWebGLLayer allows for the optional use of the WEBGL_multiview extension xrSession.baseLayer = new XRWebGLLayer(xrSession, gl, { multiview: true }); }); @@ -856,13 +834,13 @@ function drawMultiviewScene(views, pose) { While in immersive sessions, the UA is responsible for providing a framebuffer that is correctly optimized for presentation to the `XRSession` in each `XRFrame`. Developers can optionally request either the buffer size or viewport size be scaled, though the UA may not respect the request. Even when the UA honors the scaling requests, the result is not guaranteed to be the exact percentage requested. -The first scaling mechanism is done by specifying a `framebufferScaleFactor` at `XRWebGLLayer` creation time. Each `XRDevice` has a default framebuffer size, which corresponds to a `framebufferScaleFactor` of `1.0`. This default size is determined by the UA and should represent a reasonable balance between rendering quality and performance. It may not be the 'native' size for the device (that is, a buffer which would match the native screen resolution 1:1 at point of highest magnification). For example, mobile platforms such as GearVR or Daydream frequently suggest using lower resolutions than their screens are capable of to ensure consistent performance. +The first scaling mechanism is done by specifying a `framebufferScaleFactor` at `XRWebGLLayer` creation time. Each XR device has a default framebuffer size, which corresponds to a `framebufferScaleFactor` of `1.0`. This default size is determined by the UA and should represent a reasonable balance between rendering quality and performance. It may not be the 'native' size for the device (that is, a buffer which would match the native screen resolution 1:1 at point of highest magnification). For example, mobile platforms such as GearVR or Daydream frequently suggest using lower resolutions than their screens are capable of to ensure consistent performance. If the `framebufferScaleFactor` is set to a number higher or lower than `1.0` the UA should create a framebuffer that is the default resolution multiplied by the given scale factor. So a `framebufferScaleFactor` of `0.5` would specify a framebuffer with 50% the default height and width, and so on. The UA may clamp the scale factor however it sees fit, or may round it to a desired increment if needed (for example, fitting the buffer dimensions to powers of two if that is known to increase performance.) ```js function setupWebGLLayer() { - return gl.setCompatibleXRDevice(xrDevice).then(() => { + return gl.makeXRCompatible().then(() => { // Create a WebGL layer with a slightly lower than default resolution. xrSession.baseLayer = new XRWebGLLayer(xrSession, gl, { framebufferScaleFactor: 0.8 }); }); @@ -872,7 +850,7 @@ In some cases the developer may want to ensure that their application is renderi ```js function setupNativeScaleWebGLLayer() { - return gl.setCompatibleXRDevice(xrDevice).then(() => { + return gl.makeXRCompatible().then(() => { // Create a WebGL layer that matches the device's native resolution. let nativeScaleFactor = XRWebGLLayer.getNativeFramebufferScaleFactor(xrSession); xrSession.baseLayer = new XRWebGLLayer(xrSession, gl, { framebufferScaleFactor: nativeScaleFactor }); @@ -956,7 +934,7 @@ The data provided by an `XRDevicePose` instance is similar to the data provided * It’s an explicit polling interface, which ensures that new input is available for each frame. The event-driven `DeviceOrientation` data may skip a frame, or may deliver two updates in a single frame, which can lead to disruptive, jittery motion in an XR application. * `DeviceOrientation` events do not provide positional data, which is a key feature of high-end XR hardware. -* More can be assumed about the intended use case of `XRDevice` data, so optimizations such as motion prediction can be applied. +* More can be assumed about the intended use case of XR device data, so optimizations such as motion prediction can be applied. * `DeviceOrientation` events are typically not available on desktops. It should be noted that `DeviceOrientation` events have not been standardized, have behavioral differences between browser, and there are ongoing efforts to change or remove the API. This makes it difficult for developers to rely on for a use case where accurate tracking is necessary to prevent user discomfort. @@ -992,14 +970,6 @@ partial interface Navigator { [SecureContext, Exposed=Window] interface XR : EventTarget { attribute EventHandler ondevicechange; - Promise requestDevice(); -}; - -// -// Device -// - -[SecureContext, Exposed=Window] interface XRDevice { Promise supportsSession(optional XRSessionCreationOptions parameters); Promise requestSession(optional XRSessionCreationOptions parameters); }; @@ -1014,7 +984,6 @@ dictionary XRSessionCreationOptions { }; [SecureContext, Exposed=Window] interface XRSession : EventTarget { - readonly attribute XRDevice device; readonly attribute boolean immersive; readonly attribute XRPresentationContext outputContext; readonly attribute XREnvironmentBlendMode environmentBlendMode; @@ -1235,11 +1204,11 @@ dictionary XRInputSourceEventInit : EventInit { // WebGL // partial dictionary WebGLContextAttributes { - XRDevice compatibleXRDevice = null; + boolean xrCompatible = false; }; partial interface WebGLRenderingContextBase { - Promise setCompatibleXRDevice(XRDevice device); + Promise makeXRCompatible(); }; //