XR_EXT_spatial_anchor
Name String
XR_EXT_spatial_anchor
Erweiterungstyp
Instanzerweiterung
Registrierte Durchwahl
763
Revision
1
Ratification Status
Ratified
Erweiterungs- und Versionsabhängigkeiten
XR_EXT_spatial_entity
Mitwirkende
Nihav Jain, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance
Übersicht
Diese Erweiterung baut auf XR_EXT_spatial_entity auf und ermöglicht es Anwendungen, räumliche Anker zu erstellen. Das sind beliebige Punkte in der physischen Umgebung des Nutzers, die dann von der Laufzeit verfolgt werden. Die Laufzeit sollte dann die Position und Ausrichtung des Ursprungs des Ankers im Laufe der Zeit nach Bedarf anpassen, unabhängig von allen anderen Räumen und Ankern, um sicherzustellen, dass die ursprüngliche Zuordnung zur realen Welt beibehalten wird.
Ein Anker, der eine bestimmte Position und Ausrichtung innerhalb eines XrSpatialContextEXT verfolgt, wird als räumliche Entität mit der Komponente XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT dargestellt.
Vorteile von Ankern
Da sich das Verständnis der Laufzeit für die physische Umgebung des Nutzers während der Lebensdauer eines XrSpatialContextEXT ändert, können virtuelle Objekte von der Stelle abdriften, an der sie von der Anwendung platziert wurden. Das wirkt sich auf den Realismus der Anwendung und die Qualität der Nutzererfahrung aus. Wenn eine Anwendung einen Anker in der Nähe der Position eines virtuellen Objekts erstellt und dieses virtuelle Objekt dann immer relativ zu seinem Anker rendert, kann sie dafür sorgen, dass jedes virtuelle Objekt an derselben Position und Ausrichtung in der physischen Umgebung bleibt. Im Gegensatz zu bestimmten Referenzräumen sind Anker nicht von einer Neuzentrierung auf Systemebene betroffen.
Laufzeitunterstützung
Wenn die Laufzeitumgebung räumliche Anker unterstützt, muss sie dies durch Aufzählen von XR_SPATIAL_CAPABILITY_ANCHOR_EXT in xrEnumerateSpatialCapabilitiesEXT angeben.
Konfiguration
Die Struktur XrSpatialCapabilityConfigurationAnchorEXT ist so definiert:
typedef struct XrSpatialCapabilityConfigurationAnchorEXT {
XrStructureType type;
const void* next;
XrSpatialCapabilityEXT capability;
uint32_t enabledComponentCount;
const XrSpatialComponentTypeEXT* enabledComponents;
} XrSpatialCapabilityConfigurationAnchorEXT;
Mitgliederbeschreibungen
typeist der XrStructureType dieser Struktur.nextistNULLoder ein Zeiger auf die nächste Struktur in einer Strukturkette.capabilityist ein XrSpatialCapabilityEXT .enabledComponentCountist einuint32_t, der die Anzahl der Elemente im ArrayenabledComponentsbeschreibt.enabledComponentsist ein Zeiger auf ein Array von XrSpatialComponentTypeEXT .
Anwendungen können die räumliche Funktion XR_SPATIAL_CAPABILITY_ANCHOR_EXT aktivieren, indem sie einen Zeiger auf eine XrSpatialCapabilityConfigurationAnchorEXT-Struktur in XrSpatialContextCreateInfoEXT :: capabilityConfigs einfügen.
Die Laufzeit muss XR_ERROR_VALIDATION_FAILURE zurückgeben, wenn capability nicht XR_SPATIAL_CAPABILITY_ANCHOR_EXT ist.
Gültige Verwendung (implizit)
- Die Erweiterung
XR_EXT_spatial_anchormuss aktiviert sein, bevor XrSpatialCapabilityConfigurationAnchorEXT verwendet werden kann. -
typemussXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTsein -
nextmussNULLoder ein gültiger Zeiger auf die nächste Struktur in einer Strukturkette sein. -
capabilitymuss ein gültiger XrSpatialCapabilityEXT-Wert sein -
enabledComponentsmuss ein Zeiger auf ein Array mitenabledComponentCountgültigen XrSpatialComponentTypeEXT-Werten sein. - Der Parameter
enabledComponentCountmuss größer als0sein.
Garantierte Komponenten
Eine Laufzeit, die XR_SPATIAL_CAPABILITY_ANCHOR_EXT unterstützt, muss die folgenden räumlichen Komponenten als garantierte Komponenten aller Entitäten bereitstellen, die von dieser Funktion erstellt oder erkannt werden, und sie muss sie in xrEnumerateSpatialCapabilityComponentTypesEXT auflisten:
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Ankerkomponente
Komponentendaten
Der XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT verwendet XrPosef für seine Daten, die die Position und Ausrichtung des Ankers angeben.
Komponentenlistenstruktur zum Abfragen von Daten
Die Struktur XrSpatialComponentAnchorListEXT ist so definiert:
typedef struct XrSpatialComponentAnchorListEXT {
XrStructureType type;
void* next;
uint32_t locationCount;
XrPosef* locations;
} XrSpatialComponentAnchorListEXT;
Mitgliederbeschreibungen
typeist der XrStructureType dieser Struktur.nextistNULLoder ein Zeiger auf die nächste Struktur in einer Strukturkette.locationCountist einuint32_t, der die Anzahl der Elemente im Arraylocationsbeschreibt.locationsist ein Array von XrPosef .
Die Laufzeit muss XR_ERROR_VALIDATION_FAILURE von xrQuerySpatialComponentDataEXT zurückgeben, wenn XrSpatialComponentAnchorListEXT in der XrSpatialComponentDataQueryResultEXT-Kette :: next enthalten ist, aber XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT nicht in XrSpatialComponentDataQueryConditionEXT :: componentTypes enthalten ist.
Die Laufzeit muss XR_ERROR_SIZE_INSUFFICIENT von xrQuerySpatialComponentDataEXT zurückgeben, wenn locationCount kleiner als XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput ist.
Gültige Verwendung (implizit)
- Die Erweiterung
XR_EXT_spatial_anchormuss aktiviert sein, bevor XrSpatialComponentAnchorListEXT verwendet werden kann. -
typemussXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXTsein -
nextmussNULLoder ein gültiger Zeiger auf die nächste Struktur in einer Strukturkette sein. -
locationsmuss ein Zeiger auf ein Array vonlocationCountXrPosef-Strukturen sein. - Der Parameter
locationCountmuss größer als0sein.
Konfiguration
Wenn XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT in XrSpatialCapabilityComponentTypesEXT :: componentTypes für eine bestimmte Funktion aufgeführt ist, kann eine Anwendung sie aktivieren, indem sie den Enumeranten in die Liste XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents der abgeleiteten Struktur XrSpatialCapabilityConfigurationBaseHeaderEXT der Funktion aufnimmt, die diese Komponente unterstützt.
Für diese Komponente ist keine spezielle Konfiguration erforderlich, um sie in die XrSpatialCapabilityConfigurationBaseHeaderEXT-Kette (next) aufzunehmen.
Räumlichen Anker erstellen
Die Funktion xrCreateSpatialAnchorEXT ist so definiert:
XrResult xrCreateSpatialAnchorEXT(
XrSpatialContextEXT spatialContext,
const XrSpatialAnchorCreateInfoEXT* createInfo,
XrSpatialEntityIdEXT* anchorEntityId,
XrSpatialEntityEXT* anchorEntity);
Parameterbeschreibungen
spatialContextist ein XrSpatialContextEXT, der zuvor mit xrCreateSpatialContextAsyncEXT erstellt wurde.createInfoist ein Zeiger auf ein XrSpatialAnchorCreateInfoEXT .anchorEntityIdist ein Verweis auf einXrSpatialEntityIdEXT, in dem die ID der Ankerentität zurückgegeben wird.anchorEntityist ein Zeiger auf eine XrSpatialEntityEXT, in der das Handle der Ankerentität zurückgegeben wird.
Die Anwendung kann einen räumlichen Anker mit xrCreateSpatialAnchorEXT erstellen.
Wenn Sie aktualisierte Komponentendaten für einen Anker abrufen möchten, übergeben Sie den in anchorEntity ausgefüllten Wert an XrSpatialUpdateSnapshotCreateInfoEXT :: entities, wenn Sie einen Snapshot erstellen. Die Anwendung kann anchorEntityId verwenden, um diesen Anker im Array XrSpatialComponentDataQueryResultEXT :: entityIds eindeutig zu identifizieren, wenn xrQuerySpatialComponentDataEXT verwendet wird.
Die Laufzeit muss XR_ERROR_VALIDATION_FAILURE von xrCreateSpatialAnchorEXT zurückgeben, wenn XR_SPATIAL_CAPABILITY_ANCHOR_EXT nicht für spatialContext konfiguriert wurde. Unter Konfiguration finden Sie Informationen zum Konfigurieren eines XrSpatialContextEXT für die XR_SPATIAL_CAPABILITY_ANCHOR_EXT-Funktion.
Der durch anchorEntity dargestellte Anker ist nur für die Lebensdauer von spatialContext gültig oder bis die Anwendung xrDestroySpatialEntityEXT dafür aufruft, je nachdem, was zuerst eintritt. Andere Erweiterungen bieten möglicherweise Funktionen, um diesen neu erstellten Anker über mehrere XrSession-Sitzungen hinweg beizubehalten oder ihn über Prozessgrenzen hinweg mit anderen Anwendungen zu teilen.
Ein neu erstellter Anker muss bis zu seiner Zerstörung im übergeordneten räumlichen Kontext auffindbar sein. Das bedeutet, dass die Laufzeit anchorEntityId im Snapshot, der mit xrCreateSpatialDiscoverySnapshotAsyncEXT für spatialContext erstellt wurde, enthalten muss, wenn der Anker den in XrSpatialDiscoverySnapshotCreateInfoEXT festgelegten Erkennungskriterien entspricht. Der neu erstellte Anker kann auch in anderen räumlichen Kontexten gefunden werden, die mit XR_SPATIAL_CAPABILITY_ANCHOR_EXT konfiguriert sind, allerdings mit einer anderen XrSpatialEntityIdEXT, da eine bestimmte XrSpatialEntityIdEXT für ihren XrSpatialContextEXT eindeutig ist.
Gültige Verwendung (implizit)
- Die Erweiterung
XR_EXT_spatial_anchormuss aktiviert werden, bevor xrCreateSpatialAnchorEXT aufgerufen wird. -
spatialContextmuss ein gültiges XrSpatialContextEXT-Handle sein -
createInfomuss ein Zeiger auf eine gültige XrSpatialAnchorCreateInfoEXT-Struktur sein. -
anchorEntityIdmuss ein Zeiger auf einenXrSpatialEntityIdEXT-Wert sein -
anchorEntitymuss ein Zeiger auf ein XrSpatialEntityEXT-Handle sein.
Rückgabecodes
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_POSE_INVALIDXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_TIME_INVALIDXR_ERROR_VALIDATION_FAILUREXR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID(wennXR_ANDROID_spatial_entity_bound_anchoraktiviert ist)XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT(wennXR_ANDROID_spatial_entity_bound_anchoraktiviert ist)
Die Struktur XrSpatialAnchorCreateInfoEXT ist so definiert:
typedef struct XrSpatialAnchorCreateInfoEXT {
XrStructureType type;
const void* next;
XrSpace baseSpace;
XrTime time;
XrPosef pose;
} XrSpatialAnchorCreateInfoEXT;
Mitgliederbeschreibungen
typeist der XrStructureType dieser Struktur.nextistNULLoder ein Zeiger auf die nächste Struktur in einer Strukturkette.baseSpaceist der XrSpace, in demposeangewendet wird.timeist dieXrTime, an der sichbaseSpacebefindet (und auf dieposeangewendet wird).poseist der Standort für die Ankerentität.
Gültige Verwendung (implizit)
- Die Erweiterung
XR_EXT_spatial_anchormuss aktiviert werden, bevor XrSpatialAnchorCreateInfoEXT verwendet werden kann. -
typemussXR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXTsein -
nextmussNULLoder ein gültiger Zeiger auf die nächste Struktur in einer Strukturkette sein. Siehe auch: XrSpatialAnchorParentANDROID -
baseSpacemuss ein gültiger XrSpace-Alias sein
Ankerposition abfragen
Nachdem der Anker erstellt wurde, sollte die Laufzeit seine Position und Ausrichtung im Laufe der Zeit relativ zu anderen Räumen anpassen, um die bestmögliche Ausrichtung auf seinen ursprünglichen realen Standort beizubehalten, auch wenn sich dadurch die Beziehung des Ankers zum ursprünglichen XrSpatialAnchorCreateInfoEXT :: baseSpace ändert, der zur Initialisierung verwendet wurde.
Die Anwendung kann xrCreateSpatialUpdateSnapshotEXT mit dem XrSpatialEntityEXT des Ankers verwenden, um einen neuen XrSpatialSnapshotEXT zu erstellen und dann die Komponente XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT aus diesem Snapshot mit xrQuerySpatialComponentDataEXT abzufragen. Die Anwendung kann XrSpatialComponentAnchorListEXT zu XrSpatialComponentDataQueryResultEXT :: next hinzufügen, um die neuesten Standortdaten für die Anker abzurufen.
Die Laufzeit kann den Tracking-Status eines neu erstellten Ankers auf XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT setzen. Die Anwendung darf den Status der Ankerentität, der in XrSpatialComponentDataQueryResultEXT :: entityStates angegeben ist, und die Ankerkomponentendaten der Entität nur lesen, wenn der Tracking-Status XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT ist.
Richtlinien für die Verwendung von Ankern
- Die Position jedes Ankers wird unabhängig von anderen Ankern oder Bereichen angepasst. Separat verankerte virtuelle Objekte können sich relativ zueinander verschieben oder drehen, wodurch die räumliche Hierarchie unterbrochen wird, wenn diese virtuellen Objekte relativ zueinander an Ort und Stelle bleiben sollen. In solchen Fällen sollte die Anwendung denselben Anker für alle virtuellen Objekte wiederverwenden, die sich nicht relativ zueinander bewegen.
- Die Anwendung sollte alle XrSpatialEntityEXT-Handles für nicht mehr verwendete Anker löschen, um die Ressourcen freizugeben, die die Laufzeit möglicherweise zum Verfolgen dieser Anker verwendet.
Beispiel-Code
Ankerfunktion konfigurieren
Im folgenden Beispiel wird gezeigt, wie die Ankerfunktion beim Erstellen eines räumlichen Kontexts konfiguriert wird.
// Create a spatial spatial context
XrSpatialContextEXT spatialContext{};
{
std::vector<XrSpatialComponentTypeEXT> enabledComponents = {
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
};
XrSpatialCapabilityConfigurationAnchorEXT anchorConfig{XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT};
anchorConfig.capability = XR_SPATIAL_CAPABILITY_ANCHOR_EXT;
anchorConfig.enabledComponentCount = enabledComponents.size();
anchorConfig.enabledComponents = enabledComponents.data();
std::array<XrSpatialCapabilityConfigurationBaseHeaderEXT*, 1> capabilityConfigs = {
reinterpret_cast<XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&anchorConfig),
};
XrSpatialContextCreateInfoEXT spatialContextCreateInfo{XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT};
spatialContextCreateInfo.capabilityConfigCount = capabilityConfigs.size();
spatialContextCreateInfo.capabilityConfigs = capabilityConfigs.data();
XrFutureEXT createContextFuture;
CHK_XR(xrCreateSpatialContextAsyncEXT(session, &spatialContextCreateInfo, &createContextFuture));
waitUntilReady(createContextFuture);
XrCreateSpatialContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialContextCompleteEXT(session, createContextFuture, &completion));
if (completion.futureResult != XR_SUCCESS) {
return;
}
spatialContext = completion.spatialContext;
}
// ...
// Create spatial anchors and get their latest pose in the frame loop.
// ...
CHK_XR(xrDestroySpatialContextEXT(spatialContext));
Räumlichen Anker erstellen und seinen Standort abrufen
Im folgenden Beispiel wird gezeigt, wie Sie einen räumlichen Anker erstellen und seine Position in jedem Frame abrufen.
XrSpatialAnchorCreateInfoEXT createInfo{XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT};
createInfo.baseSpace = localSpace;
createInfo.time = predictedDisplayTime;
createInfo.pose = {{0, 0, 0, 1}, {1, 1, 1}};
XrSpatialEntityIdEXT spatialAnchorEntityId;
XrSpatialEntityEXT spatialAnchorEntity;
CHK_XR(xrCreateSpatialAnchorEXT(spatialContext, &createInfo, &spatialAnchorEntityId, &spatialAnchorEntity));
auto updateAnchorLocation = [&](XrTime time) {
// We want to get updated data for all components of the entities, so skip specifying componentTypes.
XrSpatialUpdateSnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_UPDATE_SNAPSHOT_CREATE_INFO_EXT};
snapshotCreateInfo.entityCount = 1;
snapshotCreateInfo.entities = &spatialAnchorEntity;
snapshotCreateInfo.baseSpace = localSpace;
snapshotCreateInfo.time = time;
XrSpatialSnapshotEXT snapshot;
CHK_XR(xrCreateSpatialUpdateSnapshotEXT(spatialContext, &snapshotCreateInfo, &snapshot));
// Query for the entities that have the anchor component on them.
std::array<XrSpatialComponentTypeEXT, 1> componentsToQuery {XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT};
XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
queryCond.componentTypeCount = componentsToQuery.size();
queryCond.componentTypes = componentsToQuery.data();
XrSpatialComponentDataQueryResultEXT queryResult{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{XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT};
locationList.locationCount = locations.size();
locationList.locations = locations.data();
queryResult.next = &locationList;
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].
}
}
CHK_XR(xrDestroySpatialSnapshotEXT(snapshot));
};
while (1) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
updateAnchorLocation(time);
// ...
// Finish frame loop
// ...
}
CHK_XR(xrDestroySpatialEntityEXT(spatialAnchorEntity));
Neue Befehle
Neue Gebäude
- XrSpatialAnchorCreateInfoEXT
- XrSpatialCapabilityConfigurationAnchorEXT
Erweiterung von XrSpatialComponentDataQueryResultEXT :
Neue Enum-Konstanten
XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAMEXR_EXT_spatial_anchor_SPEC_VERSIONErweiterung von XrSpatialCapabilityEXT :
XR_SPATIAL_CAPABILITY_ANCHOR_EXT
Erweiterung von XrSpatialComponentTypeEXT :
XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
Erweiterung von XrStructureType :
XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXTXR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXTXR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
Probleme
Warum gibt xrCreateSpatialAnchorEXT sowohl eine Entitäts-ID als auch ein Entitäts-Handle aus?
- Behoben
- Antwort: Die Funktion xrCreateSpatialAnchorEXT hätte sehr wohl nur die Entitäts-ID als Ausgabe bereitstellen können und Anwendungen hätten mit xrCreateSpatialEntityFromIdEXT ein Entitäts-Handle für diese ID erstellen können. Angesichts der typischen Verwendung eines Ankers, bei der Anwendungen die Ankerposition in jedem Frame abfragen, ist er jedoch ein guter Kandidat für die Verwendung in einem „Update-Snapshot“, für den Entitäts-Handles als Eingabe erforderlich sind. In Erwartung dieses typischen Anwendungsfalls führt xrCreateSpatialAnchorEXT im Namen der Anwendung xrCreateSpatialEntityFromIdEXT aus und stellt ihr das Entitätshandle zur Verwendung mit xrCreateSpatialUpdateSnapshotEXT zur Verfügung.
Versionsverlauf
Version 1, 10.07.2024 (Nihav Jain, Google)
- Anfängliche Beschreibung der Erweiterung