Spatial Anchors are offered through the following FB OpenXR extensions:
XR_FB_spatial_entity
XR_FB_spatial_entity_storage
XR_FB_spatial_entity_query
Our Spatial Anchors follow an entity-component system architecture pattern. Each Spatial Anchor is an entity represented by a unique identifier (UUID) that is assigned upon creation and remains constant throughout the life of the Spatial Anchor. Spatial Anchor entities can support a subset of the following components given by the XrSpaceComponentTypeFB enum:
Locatable: You can use the xrLocateSpace method to track the 6 DOF pose of the Spatial Anchor.
Storable: You can use the persistence operations save and erase on the Spatial Anchor.
Any operations involving Spatial Anchors use OpenXR XrSpace handles to identify the affected anchors. In other words, any operation which involves anchors uses XrSpace handles to identify the affected anchors. Spatial Anchors support the following operations that are mediated through the component entity model: create, locate, save, erase, destroy, and query.
For the complete API reference as part of the OpenXR spec, read:
To use the functions defined in the extension headers, you must hook up the function pointers to their implementations. The following is an example of how to do this:
In this example, the app is of type ovrApp, which is a struct defined in the XrSpatialAnchor sample app. The FunPtrs field is a struct, which is defined as follows:
Potentially long-running operations, such as saving, erasing, and querying Spatial Anchors, are asynchronous and return a request identifier, which is part of the messages returned via events. This asynchronous request identifier requestId is returned immediately at request-time and can be used to identify the request that triggered the event response.
You can handle events using the event loop in the android_main function:
while (androidApp->destroyRequested == 0) {
// Read all pending events.
for (;;) {
int events;
struct android_poll_source* source;
// If the timeout is zero, returns immediately without blocking.
// If the timeout is negative, waits indefinitely until an event appears.
const int timeoutMilliseconds = (app.Resumed == false && app.SessionActive == false && androidApp->destroyRequested == 0) ? -1 : 0;
if (ALooper_pollAll(timeoutMilliseconds, NULL, &events, (void**)&source) < 0) {
break;
}
// Process this event.
if (source != NULL) {
source->process(androidApp, source);
}
}
app.HandleXrEvents();
...
}
The HandleXrEvents function can get quite long. See the ovrApp::HandleXrEvents function defined in the XrSpatialAnchor sample app for a detailed example.
Spatial Anchors Sample App
The Spatial Anchor sample project for OpenXR demonstrates the capabilities of our Spatial Anchor system while providing example code for handling and maintaining Spatial Anchors that you can use in your own project. You can find the project in XRSamples\XRSpatialAnchor.
The persistent Spatial Anchors you create in the sample will persist between sessions and headset reboots.
Press A on the right Touch controller to place a persistent Spatial Anchor that mirrors the pose of the right controller. When you do, the system will place a rectangular object at the origin of the Spatial Anchor aligned to its frame of reference.
Press B on the right Touch controller to delete the most recent persistent Spatial Anchor and remove its object.
Press X on the left Touch controller to retrieve previously persisted Spatial Anchors.