immersive-web / anchors

https://immersive-web.github.io/anchors/
Other
50 stars 20 forks source link

UAs must retain expando XRAnchor attributes in future XRFrame.trackedAnchors sets #35

Open thetuvix opened 4 years ago

thetuvix commented 4 years ago

Given this approach of XRAnchor only representing explicit app-created freespace anchors, having a list of tracked anchors seems harmless to me.

XRFrame.trackedAnchors does feel lower value than is implied by the code in the anchors explainer, as there is no per-anchor ID or other data beyond the anchorSpace to tie a given XRAnchor back to any set of app content. The app itself will need to remember for each anchored scene object it creates which anchor that object is attached to... at which point the app could just loop over its own list of those anchors and poll for isLost or such.

Note that the for loop over trackedAnchors at the bottom stops after getting each XRAnchor's pose - it's not clear what the next line of code would be for the app to make productive use of that pose, unless it was already maintaining an equivalent trackedAnchors map from scene node to anchor itself:

let previousFrameAnchors = Set();

function onXRFrame(timestamp, frame) {
  frame.session.requestAnimationFrame(onXRFrame);

  const trackedAnchors = frame.trackedAnchors;

  for(const anchor of previousFrameAnchors) {
    if(!trackedAnchors.has(anchor)) {
      // Handle anchor tracking loss - `anchor` was present
      // in the present frame but is no longer tracked.
    }
  }

  for(const anchor of trackedAnchors) {
    // Query most recent pose of the anchor relative to some reference space:
    const pose = xrFrame.getPose(anchor.anchorSpace, referenceSpace);
  }

  previousFrameAnchors = trackedAnchors;
}

The primary way I could see an app productively using trackedAnchors is if it set its own additional attribute on each XRAnchor to store the list of its root scene objects whose poses need to be updated each frame:

  for(const anchor of trackedAnchors) {
    // Query most recent pose of the anchor relative to some reference space:
    const pose = xrFrame.getPose(anchor.anchorSpace, referenceSpace);

    for(const sceneNode of anchor.attachedSceneNodes) {
      // Adjust the pose of each scene node attached to this anchor.
      sceneNode.setTransform(pose.transform);
  }

This seems like a reasonable pattern, although it would rely on a promise that the UA will return the same XRAnchor instance on subsequent frames when XRFrame.trackedAnchors is enumerated, rather than returning a new equivalent XRAnchor instance that lost that extra data.

I'll file a new issue around specifying that the UA must retain any extra data on an XRAnchor when it's enumerated moving forward.

Originally posted by @thetuvix in https://github.com/immersive-web/anchors/issues/11#issuecomment-600909006

raviramachandra commented 4 years ago

I am thinking instead of custom extra data such as attachedSceneNodes either a UUID or opaque unique handle per anchor would make UA's management of anchors easier.

bialpio commented 4 years ago

The main value of the trackedAnchors set is to actually enable the application to perform some cleanup when it notices that an anchor is no longer tracked:

  for(const anchor of previousFrameAnchors) {
    if(!trackedAnchors.has(anchor)) {
      // Handle anchor tracking loss - `anchor` was present
      // in the present frame but is no longer tracked.
    }
  }

I'll file a new issue around specifying that the UA must retain any extra data on an XRAnchor when it's enumerated moving forward.

Yes, I had this behavior in mind when designing the API, although it may not be explicitly stated anywhere in the spec. The snippet pasted above is implying that the anchor object is persistent for as long as it's present in trackedAnchors set or as long as app has outstanding reference to it, whichever is longer (if it weren't persistent and we returned different instances, the !trackedAnchors.has(anchor) would always be false). Since we're returning the same objects and it's JavaScript, application could attach new data to those objects (although I've been told it might not be a common / best practice). Let me find a way to be a bit more explicit about it - my approach was that new instances of XRAnchor objects are only created as a result of successful calls to createAnchor(), the trackedAnchors is just regurgitating whatever was already created.

As for UUID, it was discussed in #18 - please take a look and reopen the issue if you disagree with the resolution.

bialpio commented 4 years ago

I thought about it for a bit and it occurred to me that the way the specification draft is written, it is already explicit that the anchor objects are the same ones - the only objects that can appear in trackedAnchors set are the ones that have been created via one of the createAnchor() calls - the objects get placed in set of tracked anchors on a session, and later get added to trackedAnchors on a frame (alternative view is that there are only 2 places where the spec refers to create new anchor object algorithm). Given that, I'm not sure if any special phrasing is needed to ensure that UAs must maintain app-attached attributes - I don't think we mention it anywhere in the WebXR spec but we already half-expect that the application will store for example session mode on an XRSession object for convenience.