Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebXR Persistent Anchors #5779

Merged
merged 15 commits into from
Nov 9, 2023
15 changes: 3 additions & 12 deletions src/framework/xr/xr-anchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Quat } from '../../core/math/quat.js';
*/

/**
* Callback used by {@link XrAnchor#persist}.
* Callback used by {@link XrAnchor#forget}.
*
* @callback XrAnchorForgetCallback
* @param {Error|null} err - The Error object if failed to forget an anchor or null if succeeded.
Expand Down Expand Up @@ -117,19 +117,10 @@ class XrAnchor extends EventHandler {
*/
destroy() {
if (!this._xrAnchor) return;
this._anchors._index.delete(this._xrAnchor);

if (this._uuid)
this._anchors._indexByUuid.delete(this._uuid);

const ind = this._anchors._list.indexOf(this);
if (ind !== -1) this._anchors._list.splice(ind, 1);

const xrAnchor = this._xrAnchor;
this._xrAnchor.delete();
this._xrAnchor = null;

this.fire('destroy');
this._anchors.fire('destroy', this);
this.fire('destroy', xrAnchor, this);
}

/**
Expand Down
95 changes: 57 additions & 38 deletions src/framework/xr/xr-anchors.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class XrAnchors extends EventHandler {
/**
* List of anchor creation requests.
Maksims marked this conversation as resolved.
Show resolved Hide resolved
*
* @type {Array<object>}
* @type {object[]}
* @private
*/
_creationQueue = [];
Expand All @@ -50,21 +50,21 @@ class XrAnchors extends EventHandler {
* Index of XrAnchors, with XRAnchor (native handle) used as a key.
*
* @type {Map<XRAnchor,XrAnchor>}
* @ignore
* @private
*/
_index = new Map();

/**
* Index of XrAnchors, with UUID (persistent string) used as a key.
*
* @type {Map<string,XrAnchor>}
* @ignore
* @private
*/
_indexByUuid = new Map();

/**
* @type {Array<XrAnchor>}
* @ignore
* @type {XrAnchor[]}
* @private
*/
_list = [];

Expand Down Expand Up @@ -131,14 +131,43 @@ class XrAnchors extends EventHandler {
}
this._creationQueue.length = 0;

this._index.clear();
this._indexByUuid.clear();

// destroy all anchors
if (this._list) {
let i = this._list.length;
while (i--) {
this._list[i].destroy();
}
this._list.length = 0;
let i = this._list.length;
while (i--) {
this._list[i].destroy();
}
this._list.length = 0;
}

/**
* @param {XRAnchor} xrAnchor - XRAnchor that has been added.
* @param {string|null} [uuid] - UUID string associated with persistent anchor.
* @returns {XrAnchor} new instance of XrAnchor.
* @private
*/
_createAnchor(xrAnchor, uuid = null) {
const anchor = new XrAnchor(this, xrAnchor, uuid);
this._index.set(xrAnchor, anchor);
if (uuid) this._indexByUuid.set(uuid, anchor);
this._list.push(anchor);
anchor.once('destroy', this._onAnchorDestroy, this);
return anchor;
}

/**
* @param {XRAnchor} xrAnchor - XRAnchor that has been destroyed.
* @param {XrAnchor} anchor - Anchor that has been destroyed.
* @private
*/
_onAnchorDestroy(xrAnchor, anchor) {
this._index.delete(xrAnchor);
if (anchor.uuid) this._indexByUuid.delete(anchor.uuid);
const ind = this._list.indexOf(anchor);
if (ind !== -1) this._list.splice(ind, 1);
this.fire('destroy', anchor);
}

/**
Expand Down Expand Up @@ -171,30 +200,23 @@ class XrAnchors extends EventHandler {
callback = rotation;

if (!this._supported) {
if (callback) callback(new Error('Anchors API is not supported'), null);
callback?.(new Error('Anchors API is not supported'), null);
return;
}

if (!hitResult.createAnchor) {
if (callback) callback(new Error('Creating Anchor from Hit Test is not supported'), null);
callback?.(new Error('Creating Anchor from Hit Test is not supported'), null);
return;
}

hitResult.createAnchor()
.then((xrAnchor) => {
const anchor = new XrAnchor(this, xrAnchor);
this._index.set(xrAnchor, anchor);
this._list.push(anchor);

if (callback)
callback(null, anchor);

const anchor = this._createAnchor(xrAnchor);
callback?.(null, anchor);
this.fire('add', anchor);
})
.catch((ex) => {
if (callback)
callback(ex, null);

callback?.(ex, null);
Maksims marked this conversation as resolved.
Show resolved Hide resolved
this.fire('error', ex);
});
} else {
Expand Down Expand Up @@ -226,25 +248,23 @@ class XrAnchors extends EventHandler {
*/
restore(uuid, callback) {
if (!this._persistence) {
if (callback) callback(new Error('Anchor Persistence is not supported'));
callback?.(new Error('Anchor Persistence is not supported'), null);
return;
}

if (!this.manager.active) {
if (callback) callback(new Error('WebXR session is not active'));
callback?.(new Error('WebXR session is not active'), null);
return;
}

this.manager.session.restorePersistentAnchor(uuid)
.then((xrAnchor) => {
const anchor = new XrAnchor(this, xrAnchor, uuid);
this._index.set(xrAnchor, anchor);
this._indexByUuid.set(uuid, anchor);
this._list.push(anchor);
const anchor = this._createAnchor(xrAnchor, uuid);
callback?.(null, anchor);
this.fire('add', anchor);
})
.catch((ex) => {
if (callback) callback(ex, null);
callback?.(ex, null);
this.fire('error', ex);
});
}
Expand All @@ -264,21 +284,21 @@ class XrAnchors extends EventHandler {
*/
forget(uuid, callback) {
if (!this._persistence) {
if (callback) callback(new Error('Anchor Persistence is not supported'));
callback?.(new Error('Anchor Persistence is not supported'));
return;
}

if (!this.manager.active) {
if (callback) callback(new Error('WebXR session is not active'));
callback?.(new Error('WebXR session is not active'));
return;
}

this.manager.session.deletePersistentAnchor(uuid)
.then(() => {
if (callback) callback(null);
callback?.(null);
})
.catch((ex) => {
if (callback) callback(ex);
callback?.(ex);
this.fire('error', ex);
});
}
Expand Down Expand Up @@ -314,6 +334,7 @@ class XrAnchors extends EventHandler {
if (frame.trackedAnchors.has(xrAnchor))
continue;

this._index.delete(xrAnchor);
anchor.destroy();
}

Expand All @@ -335,9 +356,7 @@ class XrAnchors extends EventHandler {
continue;
}

const anchor = new XrAnchor(this, xrAnchor);
this._index.set(xrAnchor, anchor);
this._list.push(anchor);
const anchor = this._createAnchor(xrAnchor);
anchor.update(frame);

const callback = this._callbacksAnchors.get(xrAnchor);
Expand Down Expand Up @@ -386,7 +405,7 @@ class XrAnchors extends EventHandler {
/**
* List of available {@link XrAnchor}s.
*
* @type {Array<XrAnchor>}
* @type {XrAnchor[]}
*/
get list() {
return this._list;
Expand Down