XR_EXT_spatial_anchor

Name (String)

XR_EXT_spatial_anchor

Erweiterungstyp

Instanzerweiterung

Registrierte Erweiterungsnummer

763

Revision

1

Ratifizierungsstatus

Ratifiziert

Abhängigkeiten von Erweiterungen und Versionen

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 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 in einem XrSpatialContextEXT verfolgt, wird als räumliche Entität mit der XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT Komponente dargestellt.

Vorteile der Verwendung von Ankern

Da das Verständnis der Laufzeit für die physische Umgebung des Nutzers während der Lebensdauer eines XrSpatialContextEXT aktualisiert wird , können sich virtuelle Objekte von der Stelle entfernen, an der sie von der Anwendung platziert wurden. Das wirkt sich auf den Realismus der Anwendung und die Qualität der Nutzererfahrung aus. Wenn Sie einen Anker in der Nähe eines virtuellen Objekts erstellen und dieses virtuelle Objekt immer relativ zu seinem Anker rendern, kann eine Anwendung dafür sorgen, dass jedes virtuelle Objekt an derselben Position und Ausrichtung in der physischen Umgebung bleibt. Im Gegensatz zu bestimmten Referenzräumen werden Anker auch nicht durch die Neuzentrierung auf Systemebene beeinflusst.

Laufzeitunterstützung

Wenn die Laufzeit räumliche Anker unterstützt, muss sie dies angeben, indem sie XR_SPATIAL_CAPABILITY_ANCHOR_EXT in xrEnumerateSpatialCapabilitiesEXT auflistet .

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

  • type ist der XrStructureType dieser Struktur.
  • next ist NULL oder ein Zeiger auf die nächste Struktur in einer Strukturkette.
  • capability ist ein XrSpatialCapabilityEXT .
  • enabledComponentCount ist ein uint32_t-Wert, der die Anzahl der Elemente im Array enabledComponents beschreibt.
  • enabledComponents ist ein Zeiger auf ein Array von XrSpatialComponentTypeEXT .

Anwendungen können die XR_SPATIAL_CAPABILITY_ANCHOR_EXT räumliche Funktion 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)

Garantierte Komponenten

Eine Laufzeit, die XR_SPATIAL_CAPABILITY_ANCHOR_EXT muss die folgenden räumlichen Komponenten als garantierte Komponenten aller Entitäten bereitstellen, die mit dieser Funktion erstellt oder erkannt wurden, und muss sie in xrEnumerateSpatialCapabilityComponentTypesEXT auflisten :

  • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT

Ankerkomponente

Komponentendaten

Die XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT verwendet XrPosef für ihre Daten, die die Position und Ausrichtung des Ankers angeben.

Struktur der Komponentenliste zum Abfragen von Daten

Die Struktur XrSpatialComponentAnchorListEXT ist so definiert:

typedef struct XrSpatialComponentAnchorListEXT {
    XrStructureType    type;
    void*              next;
    uint32_t           locationCount;
    XrPosef*           locations;
} XrSpatialComponentAnchorListEXT;

Mitgliederbeschreibungen

  • type ist der XrStructureType dieser Struktur.
  • next ist NULL oder ein Zeiger auf die nächste Struktur in einer Strukturkette.
  • locationCount ist ein uint32_t-Wert, der die Anzahl der Elemente im Array locations beschreibt.
  • locations ist ein Array von XrPosef .

Die Laufzeit muss XR_ERROR_VALIDATION_FAILURE von xrQuerySpatialComponentDataEXT zurückgeben, wenn XrSpatialComponentAnchorListEXT in der Kette XrSpatialComponentDataQueryResultEXT :: 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_anchor muss aktiviert sein, bevor XrSpatialComponentAnchorListEXT verwendet wird.
  • type muss sein XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
  • next muss NULL oder ein gültiger Zeiger auf die nächste Struktur in einer Strukturkette sein.
  • locations muss ein Zeiger auf ein Array von locationCount XrPosef-Strukturen sein.
  • Der locationCount Parameter muss größer als 0 sein.
Konfiguration

Wenn XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT in XrSpatialCapabilityComponentTypesEXT :: componentTypes für eine bestimmte Funktion aufgelistet ist, kann eine Anwendung sie aktivieren, indem sie den Enumerator in die Liste XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents der von XrSpatialCapabilityConfigurationBaseHeaderEXT abgeleiteten Struktur der Funktion einfügt, die diese Komponente unterstützt.

Für diese Komponente ist keine spezielle Konfiguration erforderlich, um sie in die Kette XrSpatialCapabilityConfigurationBaseHeaderEXT :: next aufzunehmen.

Räumlichen Anker erstellen

Die Funktion xrCreateSpatialAnchorEXT ist so definiert:

XrResult xrCreateSpatialAnchorEXT(
    XrSpatialContextEXT                         spatialContext,
    const XrSpatialAnchorCreateInfoEXT*         createInfo,
    XrSpatialEntityIdEXT*                       anchorEntityId,
    XrSpatialEntityEXT*                         anchorEntity);

Parameterbeschreibungen

Die Anwendung kann mit xrCreateSpatialAnchorEXT einen räumlichen Anker erstellen .

Wenn Sie aktualisierte Komponentendaten für einen Anker abrufen möchten, übergeben Sie den in anchorEntity eingefügten Wert an XrSpatialUpdateSnapshotCreateInfoEXT :: entities, wenn Sie einen Snapshot erstellen. Die Anwendung kann verwenden, um diesen Anker eindeutig im Array XrSpatialComponentDataQueryResultEXT :: entityIds zu identifizieren, wenn xrQuerySpatialComponentDataEXT verwendet wird.anchorEntityId

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 erfahren Sie, wie Sie ein XrSpatialContextEXT für die XR_SPATIAL_CAPABILITY_ANCHOR_EXT Funktion konfigurieren.

Der durch anchorEntity dargestellte Anker ist nur für die Lebensdauer von spatialContext gültig oder bis die Anwendung xrDestroySpatialEntityEXT darauf aufruft , je nachdem, was zuerst eintritt. Andere Erweiterungen können Funktionen bieten, um diesen neu erstellten Anker über mehrere XrSession hinweg beizubehalten oder ihn über Prozessgrenzen hinweg für andere Anwendungen freizugeben.

Ein neu erstellter Anker muss bis zu seiner Zerstörung im übergeordneten räumlichen Kontext auffindbar sein. Das bedeutet, dass die Laufzeit muss in den Snapshot einfügen anchorEntityId , der mit xrCreateSpatialDiscoverySnapshotAsyncEXT für spatialContext erstellt wurde, wenn der Anker den in XrSpatialDiscoverySnapshotCreateInfoEXT festgelegten Suchkriterien entspricht . Der neu erstellte Anker kann auch in anderen räumlichen Kontexten auffindbar sein, die mit XR_SPATIAL_CAPABILITY_ANCHOR_EXT konfiguriert wurden, allerdings mit einer anderen XrSpatialEntityIdEXT, da eine bestimmte XrSpatialEntityIdEXT für den jeweiligen XrSpatialContextEXT eindeutig ist .

Gültige Verwendung (implizit)

Rückgabecodes

Erfolg

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Fehler

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_POSE_INVALID
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_TIME_INVALID
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_SPATIAL_ANCHOR_ATTACHABLE_COMPONENT_NOT_FOUND_ANDROID (wenn XR_ANDROID_spatial_entity_bound_anchor aktiviert ist)
  • XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT (wenn XR_ANDROID_spatial_entity_bound_anchor aktiviert ist)

Die Struktur XrSpatialAnchorCreateInfoEXT ist so definiert:

typedef struct XrSpatialAnchorCreateInfoEXT {
    XrStructureType    type;
    const void*        next;
    XrSpace            baseSpace;
    XrTime             time;
    XrPosef            pose;
} XrSpatialAnchorCreateInfoEXT;

Mitgliederbeschreibungen

  • type ist der XrStructureType dieser Struktur.
  • next ist NULL oder ein Zeiger auf die nächste Struktur in einer Strukturkette.
  • baseSpace ist der XrSpace, in dem pose angewendet wird.
  • time ist die XrTime, zu der sich baseSpace befindet (und pose angewendet wird).
  • pose ist der Speicherort für die Ankerentität.

Gültige Verwendung (implizit)

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 seine ursprüngliche Position in der realen Welt beizubehalten. Das kann auch die Beziehung des Ankers zum ursprünglichen XrSpatialAnchorCreateInfoEXT :: baseSpace ändern, mit dem er initialisiert 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 abfragen . Die Anwendung kann XrSpatialComponentAnchorListEXT zu XrSpatialComponentDataQueryResultEXT :: next hinzufügen, um die neuesten Standortdaten für die Anker abzurufen.

Die Laufzeit kann den Trackingstatus eines neu erstellten Ankers auf XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT setzen . Die Anwendung darf den Status der Ankerentität nur in XrSpatialComponentDataQueryResultEXT :: entityStates und die Ankerkomponentendaten der Entität lesen, wenn der Trackingstatus 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 Räumen angepasst. Getrennt verankerte virtuelle Objekte können sich relativ zueinander verschieben oder drehen, wodurch die räumliche Hierarchie in Fällen unterbrochen wird, in denen diese virtuellen Objekte relativ zueinander an derselben Stelle bleiben sollen. In solchen Fällen sollte die Anwendung denselben Anker für alle virtuellen Objekte verwenden, die sich nicht relativ zueinander bewegen.
  • Die Anwendung sollte alle XrSpatialEntityEXT-Handles für Anker zerstören, die nicht mehr verwendet werden, um die Ressourcen freizugeben, die die Laufzeit möglicherweise zum Verfolgen dieser Anker verwendet.

Beispiel-Code

Ankerfunktion konfigurieren

Im folgenden Beispiel wird gezeigt, wie Sie die Ankerfunktion konfigurieren, wenn Sie einen räumlichen Kontext erstellen.

// 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 Position 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 Strukturen

Neue Enum-Konstanten

  • XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAME
  • XR_EXT_spatial_anchor_SPEC_VERSION
  • Erweiterung 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_EXT
    • XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT
    • XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT

Probleme

  • Warum gibt xrCreateSpatialAnchorEXT sowohl eine Entitäts-ID als auch ein Entitäts-Handle aus?

    • Geklärt
    • Antwort: Die Funktion xrCreateSpatialAnchorEXT hätte auch nur die Entitäts-ID als Ausgabe liefern können. Anwendungen könnten dann mit xrCreateSpatialEntityFromIdEXT ein Entitäts-Handle für diese ID erstellen. 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 „Snapshot aktualisieren“, für das Entitäts-Handles als Eingabe erforderlich sind. In Erwartung dieses typischen Anwendungsfalls führt xrCreateSpatialAnchorEXT xrCreateSpatialEntityFromIdEXT im Namen der Anwendung aus und stellt ihr das Entitäts-Handle zur Verfügung, das mit xrCreateSpatialUpdateSnapshotEXT verwendet werden kann .

Versionsverlauf

  • Revision 1, 10.07.2024 (Nihav Jain, Google)

    • Erste Beschreibung der Erweiterung