From 5f424630366e5ec30a4d3fc6e08eb9cd57c5fde8 Mon Sep 17 00:00:00 2001 From: Maksims Mihejevs Date: Mon, 14 Dec 2020 23:26:56 +0200 Subject: [PATCH 1/2] WebXR Dom Overlay --- src/index.js | 1 + src/xr/xr-dom-overlay.js | 71 ++++++++++++++++++++++++++++++++++++++++ src/xr/xr-manager.js | 25 +++++++++----- 3 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 src/xr/xr-dom-overlay.js diff --git a/src/index.js b/src/index.js index 6f3ac296539..a7f2f562cfa 100644 --- a/src/index.js +++ b/src/index.js @@ -272,6 +272,7 @@ export { XrLightEstimation } from './xr/xr-light-estimation.js'; export { XrManager } from './xr/xr-manager.js'; export { XrHitTest } from './xr/xr-hit-test.js'; export { XrHitTestSource } from './xr/xr-hit-test-source.js'; +export { XrDomOverlay } from './xr/xr-dom-overlay.js'; // BACKWARDS COMPATIBILITY export * from './deprecated.js'; diff --git a/src/xr/xr-dom-overlay.js b/src/xr/xr-dom-overlay.js new file mode 100644 index 00000000000..b944480c695 --- /dev/null +++ b/src/xr/xr-dom-overlay.js @@ -0,0 +1,71 @@ +/** + * @class + * @name pc.XrDomOverlay + * @classdesc DOM Overlay provides ability to use DOM elements as overlay in WebXR AR session. It requires that root DOM element is provided for session start. That way input source select events, first are tested against DOM Elements first, and then propagated down to XR Session. If this propagation is not desirable, use `beforexrselect` event on DOM element, and `preventDefault` function to stop propagation. + * @description DOM Overlay provides ability to use DOM elements as overlay in WebXR AR session. It requires that root DOM element is provided for session start. That way input source select events, first are tested against DOM Elements first, and then propagated down to XR Session. If this propagation is not desirable, use `beforexrselect` event on DOM element, and `preventDefault` function to stop propagation. + * @param {pc.XrManager} manager - WebXR Manager. + * @property {boolean} supported True if DOM Overlay is supported. + * @property {boolean} available True if DOM Overlay is available. It can only be available if it is supported, during valid WebXR session and if valid root element is provided. + * @property {string|null} state State of the DOM Overlay, which defines how root DOM element is rendered. Possible options: + * + * * screen: Screen - this type indicates that DOM element is covering whole physical screen, mathcing XR viewports. + * * floating: Floating - indicates that underlying platform renders DOM element as floating in space, which can move during WebXR session or allow developer to move element. + * * head-locked: Head Locked - indicates that DOM element follows the user’s head movement consistently, appearing similar to a helmet heads-up display. + * + * @example + * app.xr.domOverlay.root = element; + * app.xr.start(camera, pc.XRTYPE_AR, pc.XRSPACE_LOCALFLOOR); + * @example + * // disable input source firing `select` event when some descendant element of DOM overlay root is touched/clicked. This is usefull when user interacts with UI elements, and there should not be `select` events behind UI. + * someElement.addEventListener('beforexrselect', function (evt) { + * evt.preventDefault(); + * }); + */ +function XrDomOverlay(manager) { + this._manager = manager; + this._supported = !! window.XRDOMOverlayState; + this._root = null; +} + +Object.defineProperty(XrDomOverlay.prototype, 'supported', { + get: function () { + return this._supported; + } +}); + +Object.defineProperty(XrDomOverlay.prototype, 'available', { + get: function () { + return this._supported && this._manager.active && this._manager._session.domOverlayState !== null; + } +}); + +Object.defineProperty(XrDomOverlay.prototype, 'state', { + get: function () { + if (! this._supported || ! this._manager.active || ! this._manager._session.domOverlayState) + return null; + + return this._manager._session.domOverlayState.type; + } +}); + +/** + * @name pc.XrDomOverlay#root + * @type {object|null} + * @description DOM element to be used as root for DOM Overlay. Can be changed only outside of active WebXR session. + * @example + * app.xr.domOverlay.root = element; + * app.xr.start(camera, pc.XRTYPE_AR, pc.XRSPACE_LOCALFLOOR); + */ +Object.defineProperty(XrDomOverlay.prototype, 'root', { + set: function (value) { + if (! this._supported || this._manager.active) + return; + + this._root = value; + }, + get: function () { + return this._root; + } +}); + +export { XrDomOverlay }; diff --git a/src/xr/xr-manager.js b/src/xr/xr-manager.js index bfd3af8a68d..f10dc12a2a3 100644 --- a/src/xr/xr-manager.js +++ b/src/xr/xr-manager.js @@ -10,6 +10,7 @@ import { XRTYPE_INLINE, XRTYPE_VR, XRTYPE_AR } from './constants.js'; import { XrHitTest } from './xr-hit-test.js'; import { XrInput } from './xr-input.js'; import { XrLightEstimation } from './xr-light-estimation.js'; +import { XrDomOverlay } from './xr-dom-overlay.js'; /** * @class @@ -54,6 +55,7 @@ function XrManager(app) { this.input = new XrInput(this); this.hitTest = new XrHitTest(this); this.lightEstimation = new XrLightEstimation(this); + this.domOverlay = new XrDomOverlay(this); this._camera = null; this.views = []; @@ -207,23 +209,28 @@ XrManager.prototype.start = function (camera, type, spaceType, options) { // 3. probably immersive-vr will fail to be created // 4. call makeXRCompatible, very likely will lead to context loss - var optionalFeatures = []; + var opts = { + requiredFeatures: [spaceType], + optionalFeatures: [] + }; if (type === XRTYPE_AR) { - optionalFeatures.push('light-estimation'); - optionalFeatures.push('hit-test'); + opts.optionalFeatures.push('light-estimation'); + opts.optionalFeatures.push('hit-test'); + + if (this.domOverlay.root) { + opts.optionalFeatures.push('dom-overlay'); + opts.domOverlay = { root: this.domOverlay.root }; + } } else if (type === XRTYPE_VR) { - optionalFeatures.push('hand-tracking'); + opts.optionalFeatures.push('hand-tracking'); } if (options && options.optionalFeatures) { - optionalFeatures = optionalFeatures.concat(options.optionalFeatures); + opts.optionalFeatures = opts.optionalFeatures.concat(options.optionalFeatures); } - navigator.xr.requestSession(type, { - requiredFeatures: [spaceType], - optionalFeatures: optionalFeatures - }).then(function (session) { + navigator.xr.requestSession(type, opts).then(function (session) { self._onSessionStart(session, spaceType, callback); }).catch(function (ex) { self._camera.camera.xr = null; From 145df7e07c6c89c1fe7ef0443a26bde6105dfe51 Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Tue, 29 Dec 2020 15:37:15 +0000 Subject: [PATCH 2/2] Edit docs --- src/xr/xr-dom-overlay.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/xr/xr-dom-overlay.js b/src/xr/xr-dom-overlay.js index b944480c695..552aecee3e4 100644 --- a/src/xr/xr-dom-overlay.js +++ b/src/xr/xr-dom-overlay.js @@ -1,22 +1,23 @@ /** * @class * @name pc.XrDomOverlay - * @classdesc DOM Overlay provides ability to use DOM elements as overlay in WebXR AR session. It requires that root DOM element is provided for session start. That way input source select events, first are tested against DOM Elements first, and then propagated down to XR Session. If this propagation is not desirable, use `beforexrselect` event on DOM element, and `preventDefault` function to stop propagation. - * @description DOM Overlay provides ability to use DOM elements as overlay in WebXR AR session. It requires that root DOM element is provided for session start. That way input source select events, first are tested against DOM Elements first, and then propagated down to XR Session. If this propagation is not desirable, use `beforexrselect` event on DOM element, and `preventDefault` function to stop propagation. + * @classdesc DOM Overlay provides the ability to use DOM elements as an overlay in a WebXR AR session. It requires that the root DOM element is provided for session start. That way, input source select events are first tested against DOM Elements and then propagated down to the XR Session. If this propagation is not desirable, use the `beforexrselect` event on a DOM element and the `preventDefault` function to stop propagation. + * @description DOM Overlay provides the ability to use DOM elements as an overlay in a WebXR AR session. It requires that the root DOM element is provided for session start. That way, input source select events are first tested against DOM Elements and then propagated down to the XR Session. If this propagation is not desirable, use the `beforexrselect` event on a DOM element and the `preventDefault` function to stop propagation. * @param {pc.XrManager} manager - WebXR Manager. * @property {boolean} supported True if DOM Overlay is supported. - * @property {boolean} available True if DOM Overlay is available. It can only be available if it is supported, during valid WebXR session and if valid root element is provided. - * @property {string|null} state State of the DOM Overlay, which defines how root DOM element is rendered. Possible options: + * @property {boolean} available True if DOM Overlay is available. It can only be available if it is supported, during a valid WebXR session and if a valid root element is provided. + * @property {string|null} state State of the DOM Overlay, which defines how the root DOM element is rendered. Possible options: * - * * screen: Screen - this type indicates that DOM element is covering whole physical screen, mathcing XR viewports. - * * floating: Floating - indicates that underlying platform renders DOM element as floating in space, which can move during WebXR session or allow developer to move element. - * * head-locked: Head Locked - indicates that DOM element follows the user’s head movement consistently, appearing similar to a helmet heads-up display. + * * screen: Screen - indicates that the DOM element is covering whole physical screen, matching XR viewports. + * * floating: Floating - indicates that the underlying platform renders the DOM element as floating in space, which can move during the WebXR session or allow the application to move the element. + * * head-locked: Head Locked - indicates that the DOM element follows the user's head movement consistently, appearing similar to a helmet heads-up display. * * @example * app.xr.domOverlay.root = element; * app.xr.start(camera, pc.XRTYPE_AR, pc.XRSPACE_LOCALFLOOR); * @example - * // disable input source firing `select` event when some descendant element of DOM overlay root is touched/clicked. This is usefull when user interacts with UI elements, and there should not be `select` events behind UI. + * // Disable input source firing `select` event when some descendant element of DOM overlay root is touched/clicked. + * // This is useful when the user interacts with UI elements and there should not be `select` events behind UI. * someElement.addEventListener('beforexrselect', function (evt) { * evt.preventDefault(); * }); @@ -51,7 +52,7 @@ Object.defineProperty(XrDomOverlay.prototype, 'state', { /** * @name pc.XrDomOverlay#root * @type {object|null} - * @description DOM element to be used as root for DOM Overlay. Can be changed only outside of active WebXR session. + * @description The DOM element to be used as the root for DOM Overlay. Can be changed only outside of an active WebXR session. * @example * app.xr.domOverlay.root = element; * app.xr.start(camera, pc.XRTYPE_AR, pc.XRSPACE_LOCALFLOOR);