The XR_FB_spatial_entity extension allows applications to utilize anchors
based on world-locked frames of reference. This extension also defines the
Entity-Components, outlining the capabilities or attributes of an entity. All
Meta spatial entity extensions depend on this extension. Spatial anchors,
representing a single rigid transform in physical space, are the most basic type
of anchor. For more information about additional kinds of anchors with more
components, see the
Scene documentation.
Manage spatial anchors using their anchor handle, an (XrSpace). This handle
holds a reference to all the data for the spatial anchor while it’s active in
the runtime. Once it’s no longer active, you can identify it by its UUID. The
OpenXR
XrSpace
handles are used to grant applications access to spatial anchors. Note that
these will be cleaned up when the OpenXR session ends. Any operation that
involves spatial anchors uses either XrSpace handles, UUIDs, or both, to
identify the impacted spatial anchors.
This extension allows:
An application to create a spatial anchor.
An application to enumerate an anchor’s supported components (spatial anchor
or otherwise).
The architectural pattern of entity/component offers specialization through
composition, not inheritance. This approach prevents the potential exponential
growth of types that may occur when various entity types have shared
characteristics but differ in other aspects.
Components represent the interfaces that are available to the anchor. Every
anchor supports a specific set of components, and enabling these components
allows access to the associated operations/behaviors. Each anchor’s component
support and state are unique.
Anchors may support any subset of the components given in the
XrSpaceComponentTypeFB
enum. Operations supported on components are:
xrEnumerateSpaceSupportedComponentsFB.
xrSetSpaceComponentStatusFB.
xrGetSpaceComponentStatusFB.
Component types
XrSpaceComponentTypeFB specifies the component interfaces that could be
enabled or are already enabled by the system on spatial entities.
XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB: 2D Plane component, see
Scene documentation for
more.
XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB: 3D Plane component, see
Scene documentation for
more.
XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB: Label for an entity, see
Scene documentation for
more.
XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB: Room layout information, see
Scene documentation for
more.
XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB: Entity container, see
Scene documentation for
more.
XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META: Mesh component, see
Scene documentation for
more.
APIs
For more information on the API signatures and runtime guarantees, see the
OpenXR Specification.
xrEnumerateSpaceSupportedComponentsFB
The xrEnumerateSpaceSupportedComponentsFB function discovers any component
interfaces that an entity supports. The list of supported components does not
change as long as the entity exists. The list of component interfaces available
for an entity may depend on which extensions are enabled. Component interfaces
are not enumerated unless the corresponding extension that defines them is also
enabled. The list does not contain which components are currently enabled on an
entity. This API is synchronous and uses a
two-call idiom
to get back the list of XrComponentTypeFB.
componentTypesCapacityInput: The maximum number of component types
expected by the caller. The caller uses this maximum value to ensure the array
returned through the componentTypes out-parameter does not exceed the bounds
of the array allocated by the caller.
componentTypesCountOutput: An output parameter showing the number of
enumerated component types.
componentTypes: An output parameter providing an array of the component
types supported by the specified anchor.
Success
XR_SUCCESS
Failure
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_HANDLE_INVALID
xrSetSpaceComponentStatusFB
The xrSetSpaceComponentStatusFB function enables or disables the specified
component for the specified anchor. This operation is asynchronous.
space: A pointer to the returned
XrSpace
handle of the new spatial anchor.
componentType: The component type you want to query.
status: An output parameter showing information about the status of the
component you queried.
Success
XR_SUCCESS
Failure
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_HANDLE_INVALID
xrCreateSpatialAnchorFB
xrCreateSpatialAnchorFB asynchronously creates a spatial anchor using the specified tracking origin and pose. The anchor is locatable at creation. You can query its 6 DOF pose relative to the tracking origin using xrLocateSpace.
info: Pointer to an XrSpatialAnchorCreateInfoFB structure containing
information about how to create the anchor.
requestId: A pointer to the returned XrAsyncRequestIdFB handle of the
operation that was started.
Success
XR_SUCCESS
Failure
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_HANDLE_INVALID
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_RUNTIME_FAILURE
xrDestroySpace
The xrCreateSpatialAnchorFB operation creates an ephemeral anchor represented
by an XrSpace, which is trackable in the current session. To destroy this
anchor and remove it from the runtime, call the
xrDestroySpace
API on the XrSpace. If the anchor was ephemeral (not already successfully
persisted - for more information, see the
Persistence section) then it won’t be
recoverable across sessions via the Discovery API. For more information, see the
Discovery section.
xrLocateSpace
To track an anchor which has the XR_SPACE_COMPONENT_TYPE_LOCATABLE_FB
component enabled, call the
xrLocateSpace
API per-frame. The Reference Space which you locate with respect to is the same
that you created the spatial anchor with, for example
XR_REFERENCE_SPACE_TYPE_VIEW, XR_REFERENCE_SPACE_TYPE_LOCAL,
XR_REFERENCE_SPACE_TYPE_STAGE. Read more about
XrSpace
and the different
Reference Spaces
in the OpenXR Specification.
Structs
xrSpaceComponentStatusSetFB
The xrSpaceComponentStatusSetFB operation attempts sets a component’s status
to the given value and will return an error if that component is not toggleable
for that spatial entity.
next: Must be NULL or a pointer to the next structure in a structure
chain. Core OpenXR doesn’t define such structures.
space: The
XrSpace
handle to the reference space defining the poseInSpace of the anchor you
created.
poseInSpace: The
XrPosef
location and orientation of the spatial anchor in the specified reference
space.
time: The
XrTime
timestamp associated with the specified pose.
Extended XrResult for spatial entities
XR_ERROR_SPACE_COMPONENT_NOT_SUPPORTED_FB: This component is not supported
for this XrSpace
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB: This component is not enabled for
this XrSpace
XR_ERROR_SPACE_COMPONENT_STATUS_PENDING_FB: There is an ongoing operation to
enable this component for this XrSpace
XR_ERROR_SPACE_COMPONENT_STATUS_ALREADY_SET_FB: This component has already
been set for this XrSpace
Persistence extension and API overview
XR_META_spatial_entity_persistence overview
The XR_META_spatial_entity_persistence extension provides long-term
persistence for spatial entities, allowing them to be stored for retrieval even
after the device is restarted or powered off. It also provides the ability to
manage storage through erasing anchors. This extension uses a storage agnostic
approach, meaning it can work with different types of storage solutions. This
capability is vital for applications that need to ‘remember’ the position of
spatial entities (for example, for the purposes of rendering specific content in
a world-locked position) across different sessions.
Note
Associated content is not stored using this extension, that is the responsibility of the application.
This extension works together with XR_META_spatial_entity_discovery for
single-user experiences, and XR_FB_spatial_entity_query plus
XR_META_spatial_entity_sharing for sharing experiences, to provide robust and
flexible capabilities for developers building AR/VR applications.
Key features of the XR_META_spatial_entity_persistence extension include:
Long-Term Storage: Spatial entities are stored indefinitely until
explicitly erased.
Session Independence: The XR_META_spatial_entity_persistence extension
allows spatial entities to persist across different user sessions. In other
words, once a spatial entity is persisted, it remains available for retrieval,
and should be unchanged in subsequent user sessions until it is explicitly
erased.
Implicit Storage Management: This extension does not require storage
management/synchronization, it is handled on behalf of the developer by the
system.
The Persistence extension can be used with the Discovery extension for
single-user experiences. Alternatively the Persistence extension can be used
with the Query and Sharing extensions for multi-user colocated experiences. The
Persistence extension aims to provide more robust, easy-to-use, and efficient
storage management of spatial entities for XR applications. Through persistence,
sharing, and enhanced discovery, the experiences with world-locked content can
be made more seamless and user-friendly.
The XR_META_spatial_entity_persistence extension is the next version of the
following spatial entity extensions, and as a result, the following extensions
are now obsolete:
XR_FB_spatial_entity_storage
XR_FB_spatial_entity_storage_batch
Prerequisites for the Persistence APIs to be successful:
End user enabled local file system access for the application: End users
need to have opted-in to let the application access the device’s file system.
APIs
For more information on the API signatures and runtime guarantees, see the
OpenXR Specification.
xrSaveSpacesMETA
The xrSaveSpacesMETA function saves the provided anchors. This function will
return an error if the save call fails.
session: The XrSession object representing the current XR session.
info: A pointer to the XrSpacesSaveInfoMETA struct containing the
spatial entities to be saved.
requestId: An XrAsyncRequestIdFB atom that represents the request ID
for the save operation for async event handling.
Synchronous Returns: The xrSaveSpacesMETA function returns an XrResult
indicating the success or failure of triggering the async operation.
Asynchronous Returns: The async event will be returned as a callback, and
that struct contains another XrResult, indicating the success or failure of
the operation as a whole.
XrResult result = xrSaveSpacesMETA(session, &info, &requestId);
if (XR_SUCCESS == result)
{
// Save operation was successfully triggered.
} else {
// Save operation failed to trigger.
}
xrEraseSpacesMETA
The xrEraseSpacesMETA function erases the provided anchors from all storage
locations enabled. This function will return an error if the erase call fails.
Note
This operation does not remove the `XrSpace`s from the runtime or disable tracking, they turn a persisted anchor into an ephemeral anchor such that it won't be discoverable across sessions anymore.
To remove the anchor from tracking, see the
xrDestroySpace
API.
session: The XrSession object representing the current XR session.
info: A pointer to the XrSpacesEraseInfoMETA struct containing the
anchors to be erased (either via XrSpace handle or via UUID).
requestId: An XrAsyncRequestIdFB atom that represents the request ID
for the erase operation for async event handling.
Returns The xrEraseSpacesMETA function returns an XrResult indicating
the success or failure of the operation.
XrResult result = xrEraseSpacesMETA(session, &info, &requestId);
if (XR_SUCCESS == result)
{
// Erase operation was successfully triggered.
} else {
// Erase operation failed to trigger.
}
Structs
/**
* Structure representing the anchor information to be saved.
*/
struct XrSpacesSaveInfoMETA {
XrStructureType type; // XR_TYPE_SPACES_SAVE_INFO_META
const void* XR_MAY_ALIAS next;
uint32_t spaceCount;
XrSpace* spaces;
};
/**
* Structure representing the result of a space save operation.
*/
struct XrEventDataSpacesSaveResultMETA {
XrStructureType type; // XR_TYPE_EVENT_DATA_SPACES_SAVE_RESULT_META
const void* XR_MAY_ALIAS next;
XrAsyncRequestIdFB requestId;
XrResult result;
};
/**
* Structure representing the information for a spaces erase operation.
*/
struct XrSpacesEraseInfoMETA {
XrStructureType type; // XR_TYPE_SPACES_ERASE_INFO_META
const void* XR_MAY_ALIAS next;
uint32_t spaceCount;
XrSpace* spaces;
uint32_t uuidCount;
XrUuidEXT* uuids;
};
/**
* Structure representing the result of a spaces erase operation.
*/
struct XrEventDataSpacesEraseResultMETA {
XrStructureType type; // XR_TYPE_EVENT_DATA_SPACES_ERASE_RESULT_META
const void* XR_MAY_ALIAS next;
XrAsyncRequestIdFB requestId;
XrResult result;
};
Events
XR_TYPE_EVENT_DATA_SPACES_SAVE_RESULT_META
XR_TYPE_EVENT_DATA_SPACES_ERASE_RESULT_META
Handling Anchor Persistence events
// Called per-frame
void handleOpenXrAnchorEvents() {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events.
while (true) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = nullptr;
XrResult result = xrPollEvent(instance, &eventDataBuffer);
if (result != XR_SUCCESS) {
break;
}
...
if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACES_SAVE_RESULT_META) {
const XrEventDataSpacesSaveResultMETA* saveAnchorResult =
(XrEventDataSpacesSaveResultMETA*)(baseEventHeader);
// Find the requestId provided during the sync phase earlier and any associated data
if (saveAnchorResult->result < XR_SUCCESS) {
...
} else {
...
}
} else if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACES_ERASE_RESULT_META) {
const XrEventDataSpacesEraseResultMETA* eraseAnchorResult =
(XrEventDataSpacesEraseResultMETA*)(baseEventHeader);
// Find the requestId provided during the sync phase earlier and any associated data
if (eraseAnchorResult->result < XR_SUCCESS) {
...
} else {
...
}
}
...
}
}
Standard XrResult values
The following are standard XrResult values that can be returned from the
synchronous API call:
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_HANDLE_INVALID
XR_ERROR_RUNTIME_FAILURE
XR_ERROR_INSTANCE_LOST
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_SESSION_NOT_RUNNING
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB
XR_ERROR_INITIALIZATION_FAILED
XR_ERROR_SPACE_RATE_LIMITED_META
XR_SUCCESS
Extended XrResult for persistence
XR_ERROR_SPACE_INSUFFICIENT_RESOURCES_META: Resource limitation prevented
this operation from executing. Recommend retrying, perhaps after a short delay
and/or reducing memory consumption.
XR_ERROR_SPACE_STORAGE_AT_CAPACITY_META: Operation could not be completed
until resources used are reduced or storage expanded.
XR_ERROR_SPACE_INSUFFICIENT_VIEW_META: Look around the environment more for
sufficient space tracking to complete the operation.
XR_ERROR_SPACE_PERMISSION_INSUFFICIENT_META: Space operation permission
insufficient. Recommend confirming the status of the required permissions
needed for using spatial anchor APIs.
XR_ERROR_SPACE_RATE_LIMITED_META: Operation cancelled due to rate limiting.
Recommend retrying after a short delay.
XR_ERROR_SPACE_TOO_DARK_META: Environment too dark for tracking to complete
operation.
XR_ERROR_SPACE_TOO_BRIGHT_META: Environment too bright for tracking to
complete operation.
Discovery extension and API overview
XR_META_spatial_entity_discovery overview
The XR_META_spatial_entity_discovery extension streamlines the discovery
mechanism to support larger areas to retrieve locatable spatial entities. With
this extension, the device can discover efficiently in larger spatial areas to
retrieve relevant spatial entities. There are filtering capabilities offered, by
anchor UUID or by anchor component, which allows for more efficient and targeted
discovery of spatial entities.
This extension works together with XR_META_spatial_entity_persistence in much the
same way as what XR_FB_spatial_entity_query does today, to provide a robust and
flexible suite of Anchor APIs for developers building AR/VR applications.
XR_META_spatial_entity_persistence does not yet support discovery of shared spatial entities.
Key features of the XR_META_spatial_entity_discovery extension include:
UUID Filter: The discovery mechanism can filter spatial entities based on
their UUID (Universally Unique Identifier). This aids in targeted retrieval of
specific spatial entities.
Component Filter: The discovery mechanism can filter spatial entities
based on certain immutable components. These components that anchors are
discoverable by are as follows:
XR_SPACE_COMPONENT_TYPE_BOUNDED_2D_FB
XR_SPACE_COMPONENT_TYPE_BOUNDED_3D_FB
XR_SPACE_COMPONENT_TYPE_SEMANTIC_LABELS_FB
XR_SPACE_COMPONENT_TYPE_ROOM_LAYOUT_FB
XR_SPACE_COMPONENT_TYPE_SPACE_CONTAINER_FB
XR_SPACE_COMPONENT_TYPE_TRIANGLE_MESH_META
No Filter: The discovery mechanism can also be used with no filters
specified. This will return any and all spatial entities the device can find
that are locatable in the user’s physical space.
Support for Larger Spaces: The discovery operation is more efficient than
the Query APIs, and is effective in larger spatial areas.
Together with the Persistence
extension, the Discovery extension aims to provide a more robust and efficient
handling of spatial entities in XR applications. Through persistent storage and
enhanced discovery, the XR experience can be made more seamless and
user-friendly.
Prerequisites for the Discovery APIs to be successful:
End user enabled local file system access for the application: End users
need to have opted-in to let the application access the device’s file system.
[Optional] Enhanced Spatial Services: In order for discovery to retrieve
non-local data (for example, anchors on Meta’s infrastructure), the discoverer
would need to have enabled the Enhanced Spatial Services permission.
APIs
For more information on the API signatures and runtime guarantees, see the
OpenXR Specification.
xrDiscoverSpacesMETA
The xrDiscoverSpacesMETA operation is used to discover spaces from all
available and permitted sources. It will return an XrResult indicating the
success or failure of initiating the asynchronous discovery operation. If
successfully initiated, discovery results are pushed to the runtime
asynchronously.
session: An XrSession for the current application instance.
info: A pointer to the discovery information,
XrSpaceDiscoveryInfoMETA*.
requestId: A pointer to the request ID, XrAsyncRequestIdFB*. This is
an out parameter that will be populated by the API call.
Synchronous Returns: The xrDiscoverSpacesMETA function returns an
XrResult indicating the success or failure of triggering the async
operation.
Asynchronous Returns: The async event will be returned as a callback, and
the Complete event struct contains another XrResult, indicating the
success or failure of the operation as a whole.
Filters: The xrDiscoverSpacesMETA API is designed to accept a list of
filters, subject to certain constraints.
Array Format: The filters are structured in the form of an array of a base
type, to accommodate potential future filter enhancements. For reference, the
filter will act as a pointer to struct pointers.
Filter Types: The array of struct pointers may contain multiple instances
of each of the following filter types:
XrSpaceUuidFilterInfoMETA
XrSpaceComponentFilterInfoMETA The behaviour of filter interaction can be
thought of like distinct filter types behaving like AND and like filter
types behaving like OR.
Batched Operation Support: The XrSpaceUuidFilterInfoMETA is capable of
accepting an array of UUIDs, enabling the API to perform batch operations
effectively.
Note
There is a limit to the number of UUIDs the system can accept for any given call, 50. However the system is capable of providing any number of anchors. That is, a no-filter discovery call may return >50 anchors but a discovery call with UUID filter(s) specified can return at most 50.
The xrRetrieveSpaceDiscoveryResultsMETA operation is used to retrieve
available results for a request synchronously. The results become available
after an XrEventDataSpaceDiscoveryResultsAvailableMETA event from
xrPollEvent() is fired. They will be purged from the runtime once they have
been copied into the application’s buffer. The application should call this
function twice: once to populate resultCount and again to actually retrieve
the results after enough memory has been allocated (Two-Call Idiom).
session: An XrSession for the current application instance.
requestId: The XrAsyncRequestIdFB request ID for which results are
being retrieved.
results: A pointer to the XrSpaceDiscoveryResultsMETA struct where the
discovery results will be stored.
Structs
This section provides an overview of the key structs used in the API.
XrSpaceDiscoveryInfoMETA
This struct may be used to discover spaces. The filter info provided to the
filter member of the struct will be used as an inclusive list of filters. What
this means is all filter structs of the same type will be OR’ed together, while
all filter structs of distinct types will be AND’ed together. All spaces
discoverable by the system that match the criteria provided in the filter member
will be included in the results available event(s).
This struct is a discovery result to be returned in the results array of
xrRetrieveSpaceDiscoveryResultsMETA. No type or next pointer is included to
save space in the results array.
This struct is used in the xrRetrieveSpaceDiscoveryResultsMETA API, using a
two-call idiom. In the first call, 0 should be passed for the
resultCapacityInput field, and the system will populate the
resultCountOutput field. In the second call, the resultCapacityInput field
can be as much as what was returned in the resultCountOutput field, and the
application can allocate the same length buffer for the results field, which
will be populated.
For the Complete event, that indicates that discovery is finished and no
more Results Available events should be returned for this discovery
operation.
You can choose to retrieve the discovery results after receiving a Results
Available event, or after receiving a Discovery Complete event. In this
example, it’s done during the Results Available event.
// Called per-frame
void handleOpenXrAnchorEvents() {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events.
while (true) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = nullptr;
XrResult result = xrPollEvent(instance, &eventDataBuffer);
if (result != XR_SUCCESS) {
// Handle any errors
}
...
if (baseEventHeader->type ==
XR_TYPE_EVENT_DATA_SPACE_DISCOVERY_RESULTS_AVAILABLE_META) {
const XrEventDataSpaceDiscoveryResultsAvailableMETA*
discoverAnchorResultsAvailable = (XrEventDataSpaceDiscoveryResultsAvailableMETA*)(baseEventHeader);
XrResult res = XR_SUCCESS;
XrSpaceDiscoveryResultsMETA discoveryResults{XR_TYPE_SPACE_DISCOVERY_RESULTS_META};
discoveryResults.resultCapacityInput = 0;
discoveryResults.resultCountOutput = 0;
discoveryResults.results = nullptr;
// Call once to find the number of results (as resultCountOutput).
res = xrRetrieveSpaceDiscoveryResultsMETA(
xrSession, discoverAnchorResultsAvailable->requestId, &discoveryResults);
if (res != XR_SUCCESS) {
// Handle any errors
}
// Call it again to get the actual result objects.
std::vector<XrSpaceDiscoveryResultMETA> results(discoveryResults.resultCountOutput);
discoveryResults.resultCapacityInput = results.size();
discoveryResults.results = results.data();
res = xrRetrieveSpaceDiscoveryResultsMETA(
xrSession, discoverAnchorResultsAvailable->requestId, &discoveryResults);
if (res != XR_SUCCESS) {
// Handle any errors
}
for (auto result : results) {
// Use the results: App-specific magic
...
}
} else if (
baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACE_DISCOVERY_COMPLETE_META) {
const XrEventDataSpaceDiscoveryCompleteMETA* discoverAnchorComplete =
(XrEventDataSpaceDiscoveryCompleteMETA*)(baseEventHeader);
if (discoverAnchorComplete->result < XR_SUCCESS) {
// Handle any errors
}
...
}
...
}
}
Standard XrResult values
The following are standard XrResult values that can be returned from the
synchronous API call:
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_HANDLE_INVALID
XR_ERROR_RUNTIME_FAILURE
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_SESSION_NOT_RUNNING
XR_SUCCESS
Extended XrResult for discovery
XR_ERROR_SPACE_INSUFFICIENT_RESOURCES_META: Resource limitation prevented
this operation from executing. Recommend retrying, perhaps after a short delay
and/or reducing memory consumption.
XR_ERROR_SPACE_STORAGE_AT_CAPACITY_META: Operation could not be completed
until resources used are reduced or storage expanded.
XR_ERROR_SPACE_INSUFFICIENT_VIEW_META: Look around the environment more for
space tracking to function.
XR_ERROR_SPACE_PERMISSION_INSUFFICIENT_META: Space operation permission
insufficient. Recommend confirming the status of the required permissions
needed for using Space APIs.
XR_ERROR_SPACE_RATE_LIMITED_META: Operation cancelled due to rate limiting.
Recommend retrying after a short delay.
XR_ERROR_SPACE_TOO_DARK_META: Environment too dark for tracking to complete
operation.
XR_ERROR_SPACE_TOO_BRIGHT_META: Environment too bright for tracking to
complete operation.
Query extension and API overview
XR_FB_spatial_entity_query overview
The XR_FB_spatial_entity_query extension is part of the original suite of
Anchor APIs. Query is still the recommended mechanism for retrieving shared anchors.
Query offers filtering mechanisms similar to Discovery. To retrieve shared
anchors it’s required that the UUID filter is used (populated with UUIDs
communicated to you from the sharer) with the STORAGE_LOCATION set to
CLOUD.
If your usecase doesn’t need sharing, the recommended mechanism to retrieve
anchors is the Discovery API since it supports larger areas to retrieve
locatable spatial entities.
This extension works together with XR_META_spatial_entity_persistence and
XR_META_spatial_entity_sharing to achieve colocated shared AR/VR applications.
Prerequisites for the Query APIs to be successful:
End user enabled local file system access for the application: End users
need to have opted-in to let the application access the device’s file system.
Enhanced Spatial Services: In order for query to retrieve non-local data (for
example anchors on Meta’s infrastructure), the discoverer would need to have
enabled the Enhanced Spatial Services system-wide permission.
APIs
For more information on the API signatures and runtime guarantees, see the
OpenXR Specification.
xrQuerySpacesFB
This function is used to query for spaces from a specified storage location and
with particular filters provided. It will return immediately with an XrResult
indicating the success/failure of initiating the asynchronous query operation.
If successful, asynchronous query results are pushed to the runtime
asynchronously.
session: A XrSession for the current application instance.
info: A pointer to the base type of the query information,
XrSpaceQueryInfoBaseHeaderFB. See the XrSpaceQueryInfoFB struct.
requestId: A pointer to the XrAsyncRequestIdFB request ID. This is an
out parameter that will be populated by the API call.
Synchronous Returns: The xrQuerySpacesFB function returns an XrResult
indicating the success or failure of triggering the async operation.
Asynchronous Returns: The async event will be returned as a callback, and
the Complete event struct contains another XrResult, indicating the
success or failure of the operation as a whole.
Filters: The xrQuerySpacesFB API is designed to accept a list of
filters, subject to certain constraints.
Linked-List Format: The filters are structured in the form of a linked
list of objects utilizing the next* for multi-filter chaining.
Filter Types: The linked list may contain at most one instance of each of
the following filter types:
XrSpaceStorageLocationFilterInfoFB the location to retrieve spatial entities from. (To retrieve shared entities, initialize this with the cloud storage
location)
XrSpaceUuidFilterInfoFB an optional filter for indicating specific spatial entities to be retrieved.
XrSpaceGroupUuidFilterInfoMETA an optional filter for indicating specific sharing groups to query. (Please see the Sharing section below for more details on Group Sharing.). Note, if a Group UUID filter is provided with no Space UUID filter, all entities shared with the Group must be successfully retrieved for the Query to succeed.
XrSpaceComponentFilterInfoFB
Batched Operation Support: The XrSpaceUuidFilterInfoFB accepts an array
of UUIDs, enabling the API to perform batch operations effectively.
Note
To retrieve shared entities, apps must provide at least one `XrSpaceUuidFilterInfoFB` or `XrSpaceGroupUuidFilterInfoMETA`, in addition to an `XrSpaceStorageLocationFilterInfoFB` set to `XR_SPACE_STORAGE_LOCATION_CLOUD_FB`
Note
There is a limit to the number of UUIDs the system can accept for any given call, 50.
// Initialize the Storage Location filter to query from Cloud
XrSpaceStorageLocationFilterInfoFB storageLocationFilter = XrSpaceStorageLocationFilterInfoFB{
XR_TYPE_SPACE_STORAGE_LOCATION_FILTER_INFO_FB, nullptr, XR_SPACE_STORAGE_LOCATION_CLOUD_FB};
XrSpaceFilterInfoBaseHeaderFB* storageLocationFilterPtr =
reinterpret_cast<XrSpaceFilterInfoBaseHeaderFB*>(&storageLocationFilter);
// Initialize the UUID filter with the spatial entity UUIDs you'd like to query for
XrSpaceUuidFilterInfoFB uuidFilter = XrSpaceUuidFilterInfoFB{
XR_TYPE_SPACE_UUID_FILTER_INFO_FB,
nullptr,
static_cast<uint32_t>(uuids.size()),
uuids.data()};
XrSpaceFilterInfoBaseHeaderFB* uuidFilterPtr = reinterpret_cast<XrSpaceFilterInfoBaseHeaderFB*>(&uuidFilter);
storageLocationFilterPtr->next = uuidFilterPtr;
XrSpaceQueryInfoFB info = {
XR_TYPE_SPACE_QUERY_INFO_FB,
nullptr,
XR_SPACE_QUERY_ACTION_LOAD_FB,
maxResultCount,
0,
storageLocationFilterPtr,
nullptr};
XrAsyncRequestIdFB requestId;
XrResult res = xrQuerySpacesFB(openXrSession_, (XrSpaceQueryInfoBaseHeaderFB*)&info, &requestId);
if (res < XrResult::XR_SUCCESS) {
// Handle Query failed at input validation stage
} else {
// Async Query operation successfully initiated
}
xrRetrieveSpaceQueryResultsFB
This function is used to retrieve available results for a request synchronously.
The results become available after an XrEventDataSpaceQueryResultsAvailableFB
event from xrPollEvent() is fired. They will be purged from the runtime once
they have been copied into the application’s buffer. The application should call
this function twice: once to populate resultCount and again to actually
retrieve the results after enough memory has been allocated (Two-Call Idiom).
session: A XrSession for the current application instance.
requestId: The XrAsyncRequestIdFB request ID for which results are
being retrieved.
results: A pointer to the XrSpaceQueryResultsFB struct where the query
results will be stored.
Structs
This section provides an overview of the key structs used in the API.
XrSpaceQueryInfoFB
This struct is used to query for spaces. The filter info provided to the filter
member of the struct will be used as an inclusive list of filters. All spaces
that match these criteria will be included in the results returned.
The `excludeFilter` field is ignored. Additionally, the `XrSpaceQueryActionFB queryAction` field should always be set to `XR_SPACE_QUERY_ACTION_LOAD_FB`.
XrSpaceQueryResultFB
This struct is a single query result to be returned in the results array of
xrRetrieveSpaceQueryResultsFB. No type or next pointer is included to save
space in the results array.
You can choose to retrieve the query results after receiving a Results
Available event, or after receiving a Complete event. In this example,
it’s done during the Results Available event.
// Called per-frame
void handleOpenXrAnchorEvents() {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events.
while (true) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = nullptr;
XrResult result = xrPollEvent(instance, &eventDataBuffer);
if (result != XR_SUCCESS) {
// Handle any errors
}
...
if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) {
const XrEventDataSpaceQueryCompleteFB* completeEvent =
(XrEventDataSpaceQueryCompleteFB*)(baseEventHeader);
if (completeEvent->result < XR_SUCCESS) {
// Handle any errors
}
} else if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) {
const XrEventDataSpaceQueryResultsAvailableFB* querySpacesResultsAvailable =
(XrEventDataSpaceQueryResultsAvailableFB*)baseEventHeader;
XrResult res = XR_SUCCESS;
XrSpaceQueryResultsFB queryResults{XR_TYPE_SPACE_QUERY_RESULTS_FB};
queryResults.resultCapacityInput = 0;
queryResults.resultCountOutput = 0;
queryResults.results = nullptr;
// First call in the two-call idiom
res = xrRetrieveSpaceQueryResultsFB(
openXrSession, querySpacesResultsAvailable->requestId, &queryResults);
if (res < XR_SUCCESS) {
// Handle any errors
}
// Second call in the two-call idiom
std::vector<XrSpaceQueryResultFB> results(queryResults.resultCountOutput);
queryResults.resultCapacityInput = results.size();
queryResults.results = results.data();
res = xrRetrieveSpaceQueryResultsFB(
openXrSession, querySpacesResultsAvailable->requestId, &queryResults);
if (res < XR_SUCCESS || queryResults.resultCountOutput < results.size()) {
// Handle any errors
}
// Do things with the anchor(s)! Insert App magic here
}
...
}
}
Standard XrResult values
The following are standard XrResult values that can be returned from the
synchronous API call:
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_HANDLE_INVALID
XR_ERROR_RUNTIME_FAILURE
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_SESSION_NOT_RUNNING
XR_SUCCESS
Sharing extension and API overview
Currently, we provide two options for sharing:
[Recommended] Group Sharing - Apps can share spatial entities with any app
provided “Group UUID”. Other users running the same app can then query for spatial entities
shared with the Group UUID. This option does not require integration with Oculus User IDs,
and hence should be simpler for developers. This option is provided by the XR_META_spatial_entity_sharing and XR_META_spatial_entity_group_sharing extensions.
User Sharing - Apps can share spatial entities with specific Oculus User IDs. This
option is provided by the XR_FB_spatial_entity_sharing extension and xrShareSpacesFB.
Given xrShareSpaceFB’s dependency on XrSpaceUserFB, apps will need to retreive Oculus
User IDs and exchange them for this option. For more information on User Sharing, please see
the XR_FB_spatial_entity_sharing section below.
XR_META_spatial_entity_sharing overview
The XR_META_spatial_entity_sharing extension enables applications to
share spatial entities.
XR_META_spatial_entity_sharing itself is a base extension that provides
a generic space sharing endpoint. This extension depends on other
extensions (such as XR_META_spatial_entity_group_sharing) to define concrete “recipient
info” structures, which are passed into the generic xrShareSpacesMETA endpoint introduced in this extension.
Prerequisites for the Share API to be successful:
Android manifest permission IMPORT_EXPORT_IOT_MAP_DATA: For more
information, see
Developer Environment Setup.
End user enabled Share Point Cloud Data permission: End users need to have
opted-in to Share Point Cloud Data with Meta. This is a system-permission and
a popup should appear for them.
APIs
For more information on the API signatures and runtime guarantees, see the
OpenXR Specification.
xrShareSpacesMETA
The xrShareSpacesMETA function shares the provided spatial entities with the recipient
specified. This function will return an error if the share call fails.
session: The XrSession object representing the current XR session.
info: A pointer to the XrShareSpacesInfoMETA struct containing the
spatial entities to be shared and the recipient to share them with.
requestId: An XrAsyncRequestIdFB atom that represents the request ID
for the share operation for async event handling.
Synchronous Returns: The xrShareSpacesMETA function returns an XrResult
indicating the success or failure of triggering the async operation.
Asynchronous Returns: The async event will be returned as a callback, and
that struct contains another XrResult, indicating the success or failure of
the operation as a whole.
XrResult result = xrShareSpacesMETA(session, &info, &requestId);
if (XR_SUCCESS == result) {
// Share operation was successfully triggered.
} else {
// Share operation failed to trigger.
}
Structs
/**
* Structure representing the anchor and recipient information used for sharing.
*/
typedef struct XrShareSpacesInfoMETA {
XrStructureType type; // XR_TYPE_SHARE_SPACES_INFO_META
const void* XR_MAY_ALIAS next;
uint32_t spaceCount;
XrSpace* spaces;
const XrShareSpacesRecipientBaseHeaderMETA* recipientInfo;
} XrShareSpacesInfoMETA;
/**
* Group Sharing structure which extends the
* XrShareSpacesRecipientBaseHeaderMETA base type
*/
typedef struct XrShareSpacesRecipientGroupsMETA {
XrStructureType type; // XR_TYPE_SHARE_SPACES_RECIPIENT_GROUPS_META
const void* XR_MAY_ALIAS next;
uint32_t groupCount;
XrUuid* groups;
} XrShareSpacesRecipientGroupsMETA;
/**
* Structure representing the asynchronous event returned by the share operation including an XrResult.
*/
typedef struct XrEventDataShareSpacesCompleteMETA {
XrStructureType type; // XR_TYPE_EVENT_DATA_SHARE_SPACES_COMPLETE_META
const void* XR_MAY_ALIAS next;
XrAsyncRequestIdFB requestId;
XrResult result;
} XrEventDataShareSpacesCompleteMETA;
Events
XR_TYPE_EVENT_DATA_SHARE_SPACES_COMPLETE_META
An example showing how to handle the anchor sharing event follows:
// Called per-frame
void handleOpenXrAnchorEvents() {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events.
while (true) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = nullptr;
XrResult result = xrPollEvent(instance, &eventDataBuffer);
if (result != XR_SUCCESS) {
break;
}
...
if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SHARE_SPACES_COMPLETE_META) {
const XrEventDataShareSpacesCompleteMETA* shareResult =
(XrEventDataShareSpacesCompleteMETA*)(baseEventHeader);
if (shareResult->result < XR_SUCCESS) {
// Handle errors
}
// Optionally communicate the UUID of the shared anchors to the recipients
}
...
}
}
Standard XrResult values
The following are standard XrResult values that can be returned from the
synchronous API call:
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_HANDLE_INVALID
XR_ERROR_RUNTIME_FAILURE
XR_ERROR_INSTANCE_LOST
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_SESSION_NOT_RUNNING
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB
XR_ERROR_SESSION_LOST
XR_ERROR_INITIALIZATION_FAILED
XR_SUCCESS
Anchor-specific asynchronous XrResults for Sharing
XR_SUCCESS
XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB: Cloud storage is required for
this operation but is currently disabled. Ensure that the end-user has Share
Point Cloud Data with Meta permission enabled.
XR_ERROR_SPACE_NETWORK_TIMEOUT_FB: Timeout occurred while waiting for
network request to complete.
XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB: The network request failed.
XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB: Anchor export from device failed.
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB: The required component is not
enabled for this space. If the Sharing component is not enabled on an entity
and Share is attempted for that entity, this will be returned.
XR_META_spatial_entity_group_sharing overview
The XR_META_spatial_entity_group_sharing extension, when used with XR_META_spatial_entity_sharing and XR_FB_spatial_entity_query, enables applications to
share spatial entities with an app defined “group UUID”.
XR_META_spatial_entity_group_sharing itself provides concrete “recipient” info structure which can be passed into xrShareSpacesMETA, as well as an XrSpaceGroupUuidFilterInfoMETA struct which can be passed into xrQuerySpacesFB to retrieve the shared spatial entities from the group.
Applications can share spatial entities with any application provided group UUID. Applications can randomly generate this UUID themselves, or reuse a UUID from another external source. Once spatial entities are successfully shared with a Group UUID, they will be continue to be retrievable for a limited time. Group UUIDs are scoped to the application. If multiple applications attempt to share spatial entities with the same Group UUID, each application will only be able to retrieve the spatial entities they themselves shared.
Note
Don't use shared anchors as an alternative to saving anchors. To re-use shared anchors across multiple sessions, save the anchor before sharing, and re-share the anchor in subsequent sessions to a new group UUID.
APIs
Structs
/**
* Group Sharing structure which extends the
* XrShareSpacesRecipientBaseHeaderMETA base type
*/
typedef struct XrShareSpacesRecipientGroupsMETA {
XrStructureType type; // XR_TYPE_SHARE_SPACES_RECIPIENT_GROUPS_META
const void* XR_MAY_ALIAS next;
uint32_t groupCount;
XrUuid* groups;
} XrShareSpacesRecipientGroupsMETA;
Here is a simple example of how to share an anchor with a Group UUID:
session: The XrSession object representing the current XR session.
info: A pointer to the XrSpaceShareInfoFB struct containing the
spatial entities to be shared and the users to share them with.
requestId: An XrAsyncRequestIdFB atom that represents the request ID
for the share operation for async event handling.
Synchronous Returns: The xrShareSpacesFB function returns an XrResult
indicating the success or failure of triggering the async operation.
Asynchronous Returns: The async event will be returned as a callback, and
that struct contains another XrResult, indicating the success or failure of
the operation as a whole.
XrResult result = xrShareSpacesFB(session, &info, &requestId);
if (XR_SUCCESS == result)
{
// Share operation was successfully triggered.
} else {
// Share operation failed to trigger.
}
Structs
/**
* Structure representing the anchor and user information used for sharing.
*/
typedef struct XrSpaceShareInfoFB {
XrStructureType type; // XR_TYPE_SPACE_SHARE_INFO_FB
const void* XR_MAY_ALIAS next;
uint32_t spaceCount;
XrSpace* spaces;
uint32_t userCount;
XrSpaceUserFB* users;
} XrSpaceShareInfoFB;
/**
* Structure representing the asynchronous event returned by the share operation including an XrResult.
*/
typedef struct XrEventDataSpaceShareCompleteFB {
XrStructureType type; // XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB
const void* XR_MAY_ALIAS next;
XrAsyncRequestIdFB requestId;
XrResult result;
} XrEventDataSpaceShareCompleteFB;
Events
XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB
An example showing how to handle the anchor sharing event follows:
// Called per-frame
void handleOpenXrAnchorEvents() {
XrEventDataBuffer eventDataBuffer = {};
// Poll for events.
while (true) {
XrEventDataBaseHeader* baseEventHeader = (XrEventDataBaseHeader*)(&eventDataBuffer);
baseEventHeader->type = XR_TYPE_EVENT_DATA_BUFFER;
baseEventHeader->next = nullptr;
XrResult result = xrPollEvent(instance, &eventDataBuffer);
if (result != XR_SUCCESS) {
break;
}
...
if (baseEventHeader->type == XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) {
const XrEventDataSpaceShareCompleteFB* shareResult =
(XrEventDataSpaceShareCompleteFB*)(baseEventHeader);
if (shareResult->result < XR_SUCCESS) {
// Handle errors
}
// Optionally communicate the UUID of the shared anchors to the recipients
}
...
}
}
Standard XrResult values
The following are standard XrResult values that can be returned from the
synchronous API call:
XR_ERROR_VALIDATION_FAILURE
XR_ERROR_HANDLE_INVALID
XR_ERROR_RUNTIME_FAILURE
XR_ERROR_INSTANCE_LOST
XR_ERROR_FUNCTION_UNSUPPORTED
XR_ERROR_SESSION_NOT_RUNNING
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB
XR_ERROR_SESSION_LOST
XR_ERROR_INITIALIZATION_FAILED
XR_SUCCESS
Anchor-specific asynchronous XrResults for Sharing
XR_ERROR_SPACE_CLOUD_STORAGE_DISABLED_FB: Cloud storage is required for
this operation but is currently disabled. Ensure that the end-user has Enhanced
Spatial Services permission enabled.
XR_ERROR_SPACE_NETWORK_TIMEOUT_FB: Timeout occurred while waiting for
network request to complete.
XR_ERROR_SPACE_NETWORK_REQUEST_FAILED_FB: The network request failed.
XR_ERROR_SPACE_MAPPING_INSUFFICIENT_FB: Anchor export from device failed.
XR_ERROR_SPACE_COMPONENT_NOT_ENABLED_FB: The required component is not
enabled for this space. If the Sharing component is not enabled on an entity
and Share is attempted for that entity, this will be returned.
XR_SUCCESS
Errors/result codes
This section provides an overview of the two XrResult outcomes associated with
Asynchronous API calls.
Initial Synchronous XrResult: This is the XrResult returned directly
from the function signature. This XrResult informs whether the API call was
initiated successfully or if an issue with the session or input occurred.
Final Asynchronous XrResult: This is found in the returned struct and
indicates the internal operational status. Ideally it should provide
informative, actionable details, such as whether the API call needs to be
retried.
Note
Warnings are > `XR_SUCCESS` == 0. A warning is a qualified success, and may provide informative information about the operation.
Known Issues
Shared Spatial Anchor Querying and Alignment
This document outlines two known issues that may occur when querying or aligning shared spatial anchor. It provides repro steps and mitigation strategies to help resolve these issues.
Host device: Calls xrShareSpacesMETA to share an Spatial Anchor to a group, or calls xrShareSpacesFB to share an Spatial Anchor to a user.
Guest device: Calls xrQuerySpacesFB to query the shared Spatial Anchor.
Guest device: May observe that xrQuerySpacesFB does not return the Spatial Anchor shared from the host
Mitigation
To increase the chances of the guest device being able to query the shared Spatial Anchor, follow these steps:
On the host device, before calling xrShareSpacesMETA or xrShareSpacesFB, try to have the device move around more in the area where the Spatial Anchor is created.
On the guest device, before calling xrQuerySpacesFB, also try to have the device move around more in the area where the host device created the Spatial Anchor.
By doing so, both devices will map a more complete and accurate spatial data around the same physical area where the Spatial Anchor is created, which can improve the chances of successful Spatial Anchor querying.
Issue 2 - Misaligned Spatial Anchor on guest device
Repro Steps
Host device: Calls xrShareSpacesMETA to share an Spatial Anchor to a group, or calls xrShareSpacesFB to share an Spatial Anchor to a user.
Guest device: Calls xrQuerySpacesFB to query the shared Spatial Anchor.
Guest device: Observes that the orinetation or location of the Spatial Anchor is shifted compared to the one created by the host.
Mitigation
To resolve the misalignment issue, follow these steps on the guest device:
On the guest device, go to Settings > Privacy > Device Permissions > Clear Physical Space History
On the guest device, restart the app and call xrQuerySpacesFB again. If the Spatial Anchor cannot be queryed in this step, try to restart the guest device, start the app and call xrQuerySpacesFB again.
By clearing the physical space history and restarting device, you can ensure that the guest device reloads the shared Spatial Anchor with the correct alignment.