XR_ANDROID_spatial_entity_bound_anchor
Name String
XR_ANDROID_spatial_entity_bound_anchor
Tipo di estensione
Estensione dell'istanza
Numero di interno registrato
791
Revisione
2
Stato della ratifica
Non ratificato
Dipendenze di estensioni e versioni
XR_EXT_spatial_anchor
Data ultima modifica
2025-08-18
Stato IP
Nessuna rivendicazione di PI nota.
Collaboratori
YuSheng Chang, Google
Kyle Chen, Google
Nihav Jain, Google
Levana Chen, Google
Spencer Quin, Google
Panoramica
Questa estensione consente alle applicazioni di creare e collegare ancoraggi a entità spaziali, chiamati "ancoraggi associati a entità" in questa estensione.
Un ancoraggio associato a un'entità è rappresentato come un'entità spaziale con (o "che ha") il componente XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT e il componente XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT. Il componente XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT memorizza l'XrSpatialEntityIdEXT dell'entità padre a cui è collegata l'ancora.
La posa di un ancoraggio associato a un'entità è sempre rappresentata da un offset fisso rispetto all'entità principale, che è considerata la "base" dell'ancoraggio. Ad esempio, immagina che un utente abbia una cornice virtuale appesa a una parete, utilizzi un ancoraggio associato all'entità per rappresentare la cornice virtuale e lo colleghi all'entità della parete. In questo modo, il posizionamento relativo tra la parete e la cornice è sempre coerente man mano che le stime di tracciamento della parete fisica migliorano.
Supporto di runtime
Un runtime deve supportare almeno un'estensione di tracciamento spaziale, ad esempio XR_EXT_spatial_plane_tracking. Se il runtime supporta l'ancoraggio associato all'entità spaziale, deve fornire almeno un componente collegabile enumerando la funzione xrEnumerateSpatialAnchorAttachableComponentsANDROID. L'applicazione può enumerare i componenti collegabili utilizzando xrEnumerateSpatialAnchorAttachableComponentsANDROID .
La funzione xrEnumerateSpatialAnchorAttachableComponentsANDROID è definita come:
XrResult xrEnumerateSpatialAnchorAttachableComponentsANDROID(
XrInstance instance,
XrSystemId systemId,
uint32_t attachableComponentCapacityInput,
uint32_t* attachableComponentCountOutput,
XrSpatialComponentTypeEXT* attachableComponents);
Descrizioni dei parametri
instanceè un handle per un XrInstance .systemIdè l'XrSystemIdi cui archivi di persistenza spaziale verranno enumerati.attachableComponentCapacityInputè la capacità dell'arrayattachableComponentso 0 per indicare una richiesta di recupero della capacità richiesta.attachableComponentCountOutputè il numero di componenti collegabili o la capacità richiesta nel caso in cuiattachableComponentCapacityInputnon sia sufficiente.attachableComponentsè un array di XrSpatialComponentTypeEXT . Può essereNULLseattachableComponentCapacityInputè 0.- Consulta il capitolo Parametri delle dimensioni del buffer per una descrizione dettagliata del recupero della dimensione
attachableComponentsrichiesta.
I runtime devono sempre restituire contenuti del buffer identici da questa enumerazione per l'systemId specificato per la durata dell'istanza.
Utilizzo valido (implicito)
- L'estensione
XR_ANDROID_spatial_entity_bound_anchordeve essere attivata prima di chiamare xrEnumerateSpatialAnchorAttachableComponentsANDROID -
instancedeve essere un handle XrInstance valido -
attachableComponentCountOutputdeve essere un puntatore a un valoreuint32_t - Se
attachableComponentCapacityInputnon è0,attachableComponentsdeve essere un puntatore a un array di valoriattachableComponentCapacityInputXrSpatialComponentTypeEXT
Codici di risposta
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
Creazione di un'ancora associata a un'entità spaziale
Le applicazioni utilizzano la funzione xrCreateSpatialAnchorEXT per creare un'ancora. Se un'applicazione vuole creare un'ancora associata a un'entità spaziale, può concatenare una struttura XrSpatialAnchorParentANDROID al puntatore successivo della struttura XrSpatialAnchorCreateInfoEXT quando chiama la funzione xrCreateSpatialAnchorEXT.
La struttura XrSpatialAnchorParentANDROID è definita come:
typedef struct XrSpatialAnchorParentANDROID {
XrStructureType type;
const void* next;
XrSpatialEntityIdEXT parentId;
} XrSpatialAnchorParentANDROID;
Descrizioni dei membri
typeè l'XrStructureType di questa struttura.nextèNULLo un puntatore alla struttura successiva in una catena di strutture.parentIdè ilXrSpatialEntityIdEXTdell'entità a cui verrà collegata l'ancora.
Il runtime deve garantire che la distanza tra l'entità principale e l'ancoraggio sia sempre coerente, dove la distanza è la posizione dell'ancoraggio rispetto alla superficie più vicina dell'entità principale lungo la normale della superficie. La posa dell'ancoraggio viene aggiornata in base alla posizione dell'entità padre e alla distanza dalla superficie dell'entità padre, indipendentemente dal numero di componenti collegabili dell'entità padre.
Il runtime deve restituire XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT da xrCreateSpatialAnchorEXT se XrSpatialAnchorParentANDROID ::parentId non è un ID valido per xrCreateSpatialAnchorEXT :: spatialContext .
Il runtime deve restituire XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID da xrCreateSpatialAnchorEXT se nessuno dei componenti enumerati da xrEnumerateSpatialAnchorAttachableComponentsANDROID si trova nell'entità principale.
Utilizzo valido (implicito)
- L'estensione
XR_ANDROID_spatial_entity_bound_anchordeve essere abilitata prima di utilizzare XrSpatialAnchorParentANDROID -
typedeve essereXR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID -
nextdeve essereNULLo un puntatore valido alla struttura successiva in una catena di strutture
Esempio di codice
Crea un'ancora associata a un'entità spaziale
Il seguente codice di esempio mostra come creare un'ancora associata a un'entità e collegarla a un'entità di tracciamento del piano spaziale.
XrFutureEXT future {XR_NULL_FUTURE_EXT};
std::vector<XrSpatialEntityEXT> entityBoundAnchorEntities;
// We want to look for entities that have the plane tracking components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT,
};
auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{
.type = XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT,
.componentTypeCount = static_cast<uint32_t>(snapshotComponents.size()),
.componentTypes = snapshotComponents.data(),
};
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));
waitUntilReady(future);
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT,
.baseSpace = localSpace,
.time = time,
.future = future,
};
XrCreateSpatialDiscoverySnapshotCompletionEXT completion{
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT,
};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
if (completion.futureResult == XR_SUCCESS) {
XrSpatialComponentDataQueryConditionEXT queryCond{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = static_cast<uint32_t>(snapshotComponents.size()),
.componentTypes = snapshotComponents.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityIdEXT> entityIds(queryResult.entityIdCountOutput);
std::vector<XrSpatialEntityTrackingStateEXT> entityStates(queryResult.entityIdCountOutput);
queryResult.entityIdCapacityInput = entityIds.size();
queryResult.entityIds = entityIds.data();
queryResult.entityStateCapacityInput = entityStates.size();
queryResult.entityStates = entityStates.data();
std::vector<XrSpatialBounded2DDataEXT> bounded2D(queryResult.entityIdCountOutput);
XrSpatialComponentBounded2DListEXT bounded2DList{
.type = XR_TYPE_SPATIAL_COMPONENT_BOUNDED_2D_LIST_EXT,
.boundCount = static_cast<uint32_t>(bounded2D.size()),
.bounds = bounded2D.data(),
};
queryResult.next = &bounded2DList;
CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));
entityBoundAnchorEntities.reserve(queryResult.entityIdCountOutput);
// Create anchors attached to the plane entities
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
if (entityStates[i] != XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
continue;
}
// Parent ID info the chained to spatial anchor create info next
XrSpatialAnchorParentANDROID parentIdCreateInfo{
.type = XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID,
.parentId = entityIds[i],
};
// spatial anchor create info
XrSpatialAnchorCreateInfoEXT createInfo{
.type = XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT,
// assign Parent ID to anchor create info next, and the pose to the bounded2D center
.next = &parentIdCreateInfo,
.baseSpace = localSpace,
.time = time,
.pose = bounded2D[i].center,
};
XrSpatialEntityIdEXT entityBoundAnchorEntityId {XR_NULL_SPATIAL_ENTITY_ID_EXT};
XrSpatialEntityEXT entityBoundAnchorEntity {XR_NULL_HANDLE};
CHK_XR(xrCreateSpatialAnchorEXT(spatialContext, &createInfo, &entityBoundAnchorEntityId, &entityBoundAnchorEntity));
entityBoundAnchorEntities.push_back(entityBoundAnchorEntity);
}
CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
}
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
// Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
XrEventDataBuffer event = {
.type = XR_TYPE_EVENT_DATA_BUFFER,
};
XrResult result = xrPollEvent(instance, &event);
if (result == XR_SUCCESS) {
if (event.type == XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT) {
const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
*reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
// Discover spatial entities for the context that we received the "discovery
// recommended" event for.
discoverSpatialEntities(eventdata.spatialContext, time);
break;
}
}
// ...
// Finish frame loop
// ...
}
Ottieni la posa dell'ancoraggio associato all'entità e l'ID entità padre
Il seguente codice di esempio mostra come ottenere la posa di un'ancora associata a un'entità e l'ID della relativa entità padre.
std::vector<XrSpatialEntityEXT> entities;
auto updateEntityBoundAnchorInfo = [&](XrSpatialContextEXT spatialContext, XrTime time) {
// We want to get updated data for all components of the entities, so skip specifying componentTypes.
XrSpatialUpdateSnapshotCreateInfoEXT snapshotCreateInfo{
.type = XR_TYPE_SPATIAL_UPDATE_SNAPSHOT_CREATE_INFO_EXT,
.entityCount = static_cast<uint32_t>(entities.size()),
.entities = entities.data(),
.baseSpace = localSpace,
.time = time,
};
XrSpatialSnapshotEXT snapshot {XR_NULL_HANDLE};
CHK_XR(xrCreateSpatialUpdateSnapshotEXT(spatialContext, &snapshotCreateInfo, &snapshot));
// Query for the entities that have the anchor component and parent component on them.
std::array<XrSpatialComponentTypeEXT, 2> componentsToQuery {XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT, XR_SPATIAL_COMPONENT_TYPE_PARENT_EXT};
XrSpatialComponentDataQueryConditionEXT queryCond{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = componentsToQuery.size(),
.componentTypes = componentsToQuery.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult{
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};
CHK_XR(xrQuerySpatialComponentDataEXT(snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityIdEXT> entityIds(queryResult.entityIdCountOutput);
std::vector<XrSpatialEntityTrackingStateEXT> entityStates(queryResult.entityIdCountOutput);
queryResult.entityIdCapacityInput = entityIds.size();
queryResult.entityIds = entityIds.data();
queryResult.entityStateCapacityInput = entityStates.size();
queryResult.entityStates = entityStates.data();
// query for the pose data
std::vector<XrPosef> locations(queryResult.entityIdCountOutput);
XrSpatialComponentAnchorListEXT locationList{
.type = XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT,
.locationCount = static_cast<uint32_t>(locations.size()),
.locations = locations.data(),
};
queryResult.next = &locationList;
// query for the parent entity ID data
std::vector<XrSpatialEntityIdEXT> parentIds(queryResult.entityIdCountOutput);
XrSpatialComponentParentListEXT parentList{
.type = XR_TYPE_SPATIAL_COMPONENT_PARENT_LIST_EXT,
.parentCount = static_cast<uint32_t>(parentIds.size()),
.parents = parentIds.data(),
};
queryResult.next = &parentList;
CHK_XR(xrQuerySpatialComponentDataEXT(snapshot, &queryCond, &queryResult));
for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
if (entityStates[i] == XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT) {
// Pose for entity entityIds[i] is locations[i].
// Parent entity ID for entity entityIds[i] is parentIds[i].
}
}
CHK_XR(xrDestroySpatialSnapshotEXT(snapshot));
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
updateEntityBoundAnchorInfo(spatialContext, time);
// ...
// Finish frame loop
// ...
}
Enumera i componenti collegabili e controlla la funzionalità di ancoraggio associata all'entità
Il seguente codice di esempio mostra come enumerare i componenti collegabili e verificare se il runtime supporta la funzionalità di ancoraggio associato all'entità.
// Check spatial capability
uint32_t capabilityCount = 0;
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, 0, &capabilityCount, nullptr));
std::vector<XrSpatialCapabilityEXT> capabilities(capabilityCount);
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, capabilityCount, &capabilityCount, capabilities.data()));
// Check if anchor capability is supported
if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_ANCHOR_EXT) == capabilities.end()) {
return;
}
// Check if plane tracking capability is supported
if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT) == capabilities.end()) {
return;
}
// The supported spatial tracking components
std::vector<XrSpatialComponentTypeEXT> spatialTrackingCapabilityComponents;
// Enumerate supported components for plane tracking capability
XrSpatialCapabilityComponentTypesEXT planeComponents{
.type = XR_TYPE_SPATIAL_CAPABILITY_COMPONENT_TYPES_EXT,
};
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));
std::vector<XrSpatialComponentTypeEXT> planeCapabilityComponents(planeComponents.componentTypeCountOutput);
planeComponents.componentTypes = planeCapabilityComponents.data();
CHK_XR(xrEnumerateSpatialCapabilityComponentTypesEXT(instance, systemId, XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT, &planeComponents));
// Add plane supported components to spatial tracking supported components
spatialTrackingCapabilityComponents.insert(spatialTrackingCapabilityComponents.end(), planeCapabilityComponents.begin(), planeCapabilityComponents.end());
// Enumerate supported attachable components for anchor
uint32_t attachableComponentCount = 0;
CHK_XR(xrEnumerateSpatialAnchorAttachableComponentsANDROID(instance, systemId, 0, &attachableComponentCount, nullptr));
std::vector<XrSpatialComponentTypeEXT> attachableComponents(attachableComponentCount);
CHK_XR(xrEnumerateSpatialAnchorAttachableComponentsANDROID(instance, systemId, attachableComponentCount, &attachableComponentCount, attachableComponents.data()));
// Check if at least one spatial tracking component is supported
const auto supportsComponent = [&spatialTrackingCapabilityComponents](XrSpatialComponentTypeEXT component) {
return std::find(spatialTrackingCapabilityComponents.begin(), spatialTrackingCapabilityComponents.end(), component) != spatialTrackingCapabilityComponents.end();
};
bool atLeastOneComponentSupported = false;
for (int32_t i = 0; i < attachableComponentCount; ++i) {
if(supportsComponent(attachableComponents[i])) {
atLeastOneComponentSupported = true;
break;
}
}
// No spatial tracking component supported for anchor attachment
if(!atLeastOneComponentSupported) return;
// ...
// Create spatial entity anchors and get their latest pose in the frame loop.
// ...
Nuovi comandi
Nuove strutture
Estensione di XrSpatialAnchorCreateInfoEXT :
Nuove costanti enum
XR_ANDROID_SPATIAL_ENTITY_BOUND_ANCHOR_EXTENSION_NAMEXR_ANDROID_spatial_entity_bound_anchor_SPEC_VERSIONEstensione di XrResult :
XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID
Estensione di XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_PARENT_ANDROID
Problemi
Cronologia delle versioni
Revisione 1, 18/08/2025 (YuSheng Chang)
- Descrizione iniziale dell'estensione.
Revisione 2, 16/12/2025 (Kyle Chen)
- Aggiungere un linguaggio più prescrittivo a determinati comportamenti dell'API.
- Aggiungi il codice di esempio di xrEnumerateSpatialAnchorAttachableComponentsANDROID .