From b3bca9e6ed2bf98bb61347f93f3cbe9d0ea531df Mon Sep 17 00:00:00 2001 From: mrmaxm Date: Mon, 18 Mar 2024 12:14:39 +0200 Subject: [PATCH 1/4] wip --- src/framework/xr/xr-body.js | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/framework/xr/xr-body.js diff --git a/src/framework/xr/xr-body.js b/src/framework/xr/xr-body.js new file mode 100644 index 00000000000..5bda20d8736 --- /dev/null +++ b/src/framework/xr/xr-body.js @@ -0,0 +1,58 @@ +import { EventHandler } from '../../core/event-handler.js'; +import { XrJoint } from './xr-joint.js'; + +class XrBody extends EventHandler { + _manager; + _tracking = false; + _joints = []; + _jointsById = {}; + + // supported + // available + + constructor(manager) { + super(); + this._manager = manager; + } + + update(frame) { + const body = frame.body; + if (!body) return; + + for (const [name, space] of body) { + const pose = frame.getPose(space, this._manager._referenceSpace); + let joint = this._jointsById[name]; + if (!joint) { + joint = new XrJoint(0, name, null, this); + this._jointsById[name] = joint; + this._joints.push(joint); + } + joint.update(pose); + } + } + + /** + * Returns joint by its id. + * + * @param {string} id - Id of a joint. + * @returns {XrJoint|null} Joint or null if not available. + */ + getJointById(id) { + return this._jointsById[id] || null; + } + + /** + * List of joints of a body. + * + * @type {XrJoint[]} + */ + get joints() { + return this._joints; + } + + get supported() { + return true; + } +} + +export { XrBody }; From db125283abf0316ddf9b729d63cafc8312538a7d Mon Sep 17 00:00:00 2001 From: mrmaxm Date: Mon, 18 Mar 2024 13:44:40 +0200 Subject: [PATCH 2/4] XRSession.enabledFeatures might not be available --- .../xr/ar-anchors-persistence/example.mjs | 8 ++- .../xr/ar-hit-test-anchors/example.mjs | 8 ++- .../src/examples/xr/ar-hit-test/example.mjs | 10 ++-- src/framework/xr/xr-anchors.js | 26 ++++++++- src/framework/xr/xr-body.js | 58 ------------------- src/framework/xr/xr-hit-test.js | 36 ++++++++++-- src/framework/xr/xr-mesh-detection.js | 20 +++++-- src/framework/xr/xr-plane-detection.js | 20 +++++-- src/framework/xr/xr-views.js | 3 + 9 files changed, 104 insertions(+), 85 deletions(-) delete mode 100644 src/framework/xr/xr-body.js diff --git a/examples/src/examples/xr/ar-anchors-persistence/example.mjs b/examples/src/examples/xr/ar-anchors-persistence/example.mjs index 2ea07a96669..a9bd35f74d9 100644 --- a/examples/src/examples/xr/ar-anchors-persistence/example.mjs +++ b/examples/src/examples/xr/ar-anchors-persistence/example.mjs @@ -127,8 +127,8 @@ if (app.xr.supported) { } }); - app.xr.on('start', function () { - message('Immersive AR session has started'); + app.xr.anchors.on('available', () => { + message('Anchors became available'); // restore all persistent anchors if (app.xr.anchors.persistence) { @@ -138,6 +138,10 @@ if (app.xr.supported) { } } }); + + app.xr.on('start', function () { + message('Immersive AR session has started'); + }); app.xr.on('end', function () { message('Immersive AR session has ended'); }); diff --git a/examples/src/examples/xr/ar-hit-test-anchors/example.mjs b/examples/src/examples/xr/ar-hit-test-anchors/example.mjs index a52b837297f..7498ebbe01c 100644 --- a/examples/src/examples/xr/ar-hit-test-anchors/example.mjs +++ b/examples/src/examples/xr/ar-hit-test-anchors/example.mjs @@ -133,9 +133,7 @@ if (app.xr.supported) { } }); - app.xr.on('start', function () { - message('Immersive AR session has started'); - + app.xr.hitTest.on('available', () => { if (!app.xr.hitTest.supported || !app.xr.anchors.supported) return; // provide gaze-like way to create anchors @@ -166,6 +164,10 @@ if (app.xr.supported) { createAnchor(lastHitTestResult); }); }); + + app.xr.on('start', function () { + message('Immersive AR session has started'); + }); app.xr.on('end', function () { message('Immersive AR session has ended'); }); diff --git a/examples/src/examples/xr/ar-hit-test/example.mjs b/examples/src/examples/xr/ar-hit-test/example.mjs index f8ff9e9d608..358ce899e06 100644 --- a/examples/src/examples/xr/ar-hit-test/example.mjs +++ b/examples/src/examples/xr/ar-hit-test/example.mjs @@ -107,11 +107,7 @@ if (app.xr.supported) { } }); - app.xr.on('start', function () { - message('Immersive AR session has started'); - - if (!app.xr.hitTest.supported) return; - + app.xr.hitTest.on('available', () => { app.xr.hitTest.start({ entityTypes: [pc.XRTRACKABLE_POINT, pc.XRTRACKABLE_PLANE], callback: function (err, hitTestSource) { @@ -127,6 +123,10 @@ if (app.xr.supported) { } }); }); + + app.xr.on('start', function () { + message('Immersive AR session has started'); + }); app.xr.on('end', function () { message('Immersive AR session has ended'); }); diff --git a/src/framework/xr/xr-anchors.js b/src/framework/xr/xr-anchors.js index 6ac1ad667ea..638b4d19381 100644 --- a/src/framework/xr/xr-anchors.js +++ b/src/framework/xr/xr-anchors.js @@ -1,5 +1,7 @@ import { EventHandler } from '../../core/event-handler.js'; import { platform } from '../../core/platform.js'; +import { Vec3 } from '../../core/math/vec3.js'; +import { Quat } from '../../core/math/quat.js'; import { XrAnchor } from './xr-anchor.js'; /** @@ -101,6 +103,12 @@ class XrAnchors extends EventHandler { */ _available = false; + /** + * @type {boolean} + * @private + */ + _checkingAvailability = false; + /** * @type {boolean} * @private @@ -380,8 +388,24 @@ class XrAnchors extends EventHandler { * @ignore */ update(frame) { - if (!this._available) + if (!this._available) { + // enabledFeatures - is not available, requires alternative way to check feature availability + if (!this.manager.session.enabledFeatures && !this._checkingAvailability) { + this._checkingAvailability = true; + + frame.createAnchor(new XRRigidTransform(new Vec3(), new Quat()), this.manager._referenceSpace) // eslint-disable-line no-undef + .then((xrAnchor) => { + // successfully created an anchor - feature is available + xrAnchor.delete(); + if (this.manager.active) { + this._available = true; + this.fire('available'); + } + }) + .catch(() => { }); // stay unavailable + } return; + } // check if need to create anchors if (this._creationQueue.length) { diff --git a/src/framework/xr/xr-body.js b/src/framework/xr/xr-body.js deleted file mode 100644 index 5bda20d8736..00000000000 --- a/src/framework/xr/xr-body.js +++ /dev/null @@ -1,58 +0,0 @@ -import { EventHandler } from '../../core/event-handler.js'; -import { XrJoint } from './xr-joint.js'; - -class XrBody extends EventHandler { - _manager; - _tracking = false; - _joints = []; - _jointsById = {}; - - // supported - // available - - constructor(manager) { - super(); - this._manager = manager; - } - - update(frame) { - const body = frame.body; - if (!body) return; - - for (const [name, space] of body) { - const pose = frame.getPose(space, this._manager._referenceSpace); - let joint = this._jointsById[name]; - if (!joint) { - joint = new XrJoint(0, name, null, this); - this._jointsById[name] = joint; - this._joints.push(joint); - } - joint.update(pose); - } - } - - /** - * Returns joint by its id. - * - * @param {string} id - Id of a joint. - * @returns {XrJoint|null} Joint or null if not available. - */ - getJointById(id) { - return this._jointsById[id] || null; - } - - /** - * List of joints of a body. - * - * @type {XrJoint[]} - */ - get joints() { - return this._joints; - } - - get supported() { - return true; - } -} - -export { XrBody }; diff --git a/src/framework/xr/xr-hit-test.js b/src/framework/xr/xr-hit-test.js index f1e26cd6e2c..e775c69a5a8 100644 --- a/src/framework/xr/xr-hit-test.js +++ b/src/framework/xr/xr-hit-test.js @@ -111,6 +111,12 @@ class XrHitTest extends EventHandler { */ _available = false; + /** + * @type {boolean} + * @private + */ + _checkingAvailability = false; + /** * List of active {@link XrHitTestSource}. * @@ -137,10 +143,29 @@ class XrHitTest extends EventHandler { /** @private */ _onSessionStart() { - const available = this.manager.session.enabledFeatures.indexOf('hit-test') !== -1; - if (!available) return; - this._available = available; - this.fire('available'); + if (this.manager.session.enabledFeatures) { + const available = this.manager.session.enabledFeatures.indexOf('hit-test') !== -1; + if (!available) return; + this._available = available; + this.fire('available'); + } else if (!this._checkingAvailability) { + this._checkingAvailability = true; + + // enabledFeatures - is not available, requires alternative way to check feature availability + + this.manager.session.requestReferenceSpace(XRSPACE_VIEWER).then((referenceSpace) => { + this.manager.session.requestHitTestSource({ + space: referenceSpace + }).then((hitTestSource) => { + hitTestSource.cancel(); + + if (this.manager.active) { + this._available = true; + this.fire('available'); + } + }).catch(() => { }); + }).catch(() => {}); + } } /** @private */ @@ -316,6 +341,9 @@ class XrHitTest extends EventHandler { * @ignore */ update(frame) { + if (!this._available) + return; + for (let i = 0; i < this.sources.length; i++) { this.sources[i].update(frame); } diff --git a/src/framework/xr/xr-mesh-detection.js b/src/framework/xr/xr-mesh-detection.js index f9cf413c2bf..be849137f16 100644 --- a/src/framework/xr/xr-mesh-detection.js +++ b/src/framework/xr/xr-mesh-detection.js @@ -120,8 +120,14 @@ class XrMeshDetection extends EventHandler { * @ignore */ update(frame) { - if (!this._supported || !this._available) - return; + if (!this._available) { + if (!this._manager.session.enabledFeatures && frame.detectedMeshes.size) { + this._available = true; + this.fire('available'); + } else { + return; + } + } // add meshes for (const xrMesh of frame.detectedMeshes) { @@ -159,10 +165,12 @@ class XrMeshDetection extends EventHandler { /** @private */ _onSessionStart() { - const available = this._manager.session.enabledFeatures.indexOf('mesh-detection') !== -1; - if (!available) return; - this._available = available; - this.fire('available'); + if (this._manager.session.enabledFeatures) { + const available = this._manager.session.enabledFeatures.indexOf('mesh-detection') !== -1; + if (!available) return; + this._available = available; + this.fire('available'); + } } /** @private */ diff --git a/src/framework/xr/xr-plane-detection.js b/src/framework/xr/xr-plane-detection.js index 154d2db92a2..5aafefa30e3 100644 --- a/src/framework/xr/xr-plane-detection.js +++ b/src/framework/xr/xr-plane-detection.js @@ -117,10 +117,12 @@ class XrPlaneDetection extends EventHandler { /** @private */ _onSessionStart() { - const available = this._supported && this._manager.session.enabledFeatures.indexOf('plane-detection') !== -1; - if (available) { - this._available = true; - this.fire('available'); + if (this._manager.session.enabledFeatures) { + const available = this._manager.session.enabledFeatures.indexOf('plane-detection') !== -1; + if (available) { + this._available = true; + this.fire('available'); + } } } @@ -145,8 +147,14 @@ class XrPlaneDetection extends EventHandler { * @ignore */ update(frame) { - if (!this._supported || !this._available) - return; + if (!this._available) { + if (!this._manager.session.enabledFeatures && frame.detectedPlanes.size) { + this._available = true; + this.fire('available'); + } else { + return; + } + } const detectedPlanes = frame.detectedPlanes; diff --git a/src/framework/xr/xr-views.js b/src/framework/xr/xr-views.js index 8d1bcebcb02..ecc1c93de6d 100644 --- a/src/framework/xr/xr-views.js +++ b/src/framework/xr/xr-views.js @@ -261,6 +261,9 @@ class XrViews extends EventHandler { if (this._manager.type !== XRTYPE_AR) return; + if (!this._manager.session.enabledFeatures) + return; + this._availableColor = this._manager.session.enabledFeatures.indexOf('camera-access') !== -1; this._availableDepth = this._manager.session.enabledFeatures.indexOf('depth-sensing') !== -1; From 9dafd38cc74a7a8aa4540c3f26bc420304bbee5d Mon Sep 17 00:00:00 2001 From: mrmaxm Date: Mon, 18 Mar 2024 14:26:14 +0200 Subject: [PATCH 3/4] PR comments --- package.json | 3 ++- src/framework/xr/xr-anchors.js | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d22b56bf59e..42a39286689 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,8 @@ "twgsl": "readonly", "webkitAudioContext": "readonly", "XRRay": "readonly", - "XRWebGLLayer": "readonly" + "XRWebGLLayer": "readonly", + "XRRigidTransform": "readonly" }, "parser": "@babel/eslint-parser", "parserOptions": { diff --git a/src/framework/xr/xr-anchors.js b/src/framework/xr/xr-anchors.js index 638b4d19381..834bac1f7b5 100644 --- a/src/framework/xr/xr-anchors.js +++ b/src/framework/xr/xr-anchors.js @@ -1,7 +1,5 @@ import { EventHandler } from '../../core/event-handler.js'; import { platform } from '../../core/platform.js'; -import { Vec3 } from '../../core/math/vec3.js'; -import { Quat } from '../../core/math/quat.js'; import { XrAnchor } from './xr-anchor.js'; /** @@ -291,7 +289,7 @@ class XrAnchors extends EventHandler { }); } else { this._creationQueue.push({ - transform: new XRRigidTransform(position, rotation), // eslint-disable-line no-undef + transform: new XRRigidTransform(position, rotation), callback: callback }); } @@ -393,7 +391,7 @@ class XrAnchors extends EventHandler { if (!this.manager.session.enabledFeatures && !this._checkingAvailability) { this._checkingAvailability = true; - frame.createAnchor(new XRRigidTransform(new Vec3(), new Quat()), this.manager._referenceSpace) // eslint-disable-line no-undef + frame.createAnchor(new XRRigidTransform(), this.manager._referenceSpace) .then((xrAnchor) => { // successfully created an anchor - feature is available xrAnchor.delete(); From bfe45882cd676c7b9db7f6feab1a865adf07bc89 Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Mon, 18 Mar 2024 13:48:17 +0000 Subject: [PATCH 4/4] Alphabetic order --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 42a39286689..8dc5ba89ee8 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,8 @@ "twgsl": "readonly", "webkitAudioContext": "readonly", "XRRay": "readonly", - "XRWebGLLayer": "readonly", - "XRRigidTransform": "readonly" + "XRRigidTransform": "readonly", + "XRWebGLLayer": "readonly" }, "parser": "@babel/eslint-parser", "parserOptions": {