XR_EXT_spatial_anchor

Name String

XR_EXT_spatial_anchor

Type d'extension

Extension d'instance

Numéro d'extension enregistré

763

Révision

1

État de la ratification

Ratifié

Dépendances d'extension et de version

XR_EXT_spatial_entity

Participants

Nihav Jain, Google
Natalie Fleury, Meta
Yuichi Taguchi, Meta
Ron Bessems, Meta
Yin Li, Microsoft
Jimmy Alamparambil, ByteDance
Zhipeng Liu, ByteDance
Jun Yan, ByteDance

Présentation

Cette extension s'appuie sur XR_EXT_spatial_entity et permet aux applications de créer des ancres spatiales, qui sont des points arbitraires dans l'environnement physique de l'utilisateur qui seront ensuite suivis par l'environnement d'exécution. L'environnement d'exécution doit ensuite ajuster la position et l'orientation de l'origine de l'ancrage au fil du temps, si nécessaire, indépendamment de tous les autres espaces et ancrages, afin de s'assurer qu'il conserve son mappage d'origine avec le monde réel.

Une ancre qui suit une position et une orientation données dans un XrSpatialContextEXT est représentée sous la forme d'une entité spatiale avec (ou "qui possède") le composant XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT.

Avantage de l'utilisation d'ancres

À mesure que l'environnement physique de l'utilisateur est mis à jour pendant la durée de vie d'un XrSpatialContextEXT , les objets virtuels peuvent sembler s'éloigner de l'endroit où ils ont été placés par l'application, ce qui a un impact sur le réalisme de l'application et la qualité de l'expérience utilisateur. En créant une ancre à proximité de l'emplacement d'un objet virtuel, puis en affichant toujours cet objet virtuel par rapport à son ancre, une application peut s'assurer que chaque objet virtuel semble rester à la même position et à la même orientation dans l'environnement physique. De plus, contrairement à certains espaces de référence, les ancres ne sont pas affectées par le recentrage au niveau du système.

Prise en charge des environnements d'exécution

Si l'environnement d'exécution est compatible avec les ancres spatiales, il doit l'indiquer en énumérant XR_SPATIAL_CAPABILITY_ANCHOR_EXT dans xrEnumerateSpatialCapabilitiesEXT .

Configuration

La structure XrSpatialCapabilityConfigurationAnchorEXT est définie comme suit :

typedef struct XrSpatialCapabilityConfigurationAnchorEXT {
    XrStructureType                     type;
    const void*                         next;
    XrSpatialCapabilityEXT              capability;
    uint32_t                            enabledComponentCount;
    const XrSpatialComponentTypeEXT*    enabledComponents;
} XrSpatialCapabilityConfigurationAnchorEXT;

Descriptions des membres

  • type est le XrStructureType de cette structure.
  • next est NULL ou un pointeur vers la structure suivante dans une chaîne de structures.
  • capability est un XrSpatialCapabilityEXT .
  • enabledComponentCount est un uint32_t décrivant le nombre d'éléments dans le tableau enabledComponents.
  • enabledComponents est un pointeur vers un tableau de XrSpatialComponentTypeEXT .

Les applications peuvent activer la fonctionnalité spatiale XR_SPATIAL_CAPABILITY_ANCHOR_EXT en incluant un pointeur vers une structure XrSpatialCapabilityConfigurationAnchorEXT dans XrSpatialContextCreateInfoEXT :: capabilityConfigs .

L'environnement d'exécution doit renvoyer XR_ERROR_VALIDATION_FAILURE si capability n'est pas XR_SPATIAL_CAPABILITY_ANCHOR_EXT .

Utilisation valide (implicite)

Composants garantis

Un environnement d'exécution compatible avec XR_SPATIAL_CAPABILITY_ANCHOR_EXT doit fournir les composants spatiaux suivants en tant que composants garantis de toutes les entités créées ou découvertes par cette fonctionnalité, et doit les énumérer dans xrEnumerateSpatialCapabilityComponentTypesEXT :

  • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT

Composant d'ancrage

Données du composant

XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT utilise XrPosef pour ses données, qui fournissent la position et l'orientation de l'ancrage.

Structure de liste de composants pour interroger des données

La structure XrSpatialComponentAnchorListEXT est définie comme suit :

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

Descriptions des membres

  • type est le XrStructureType de cette structure.
  • next est NULL ou un pointeur vers la structure suivante dans une chaîne de structures.
  • locationCount est un uint32_t décrivant le nombre d'éléments dans le tableau locations.
  • locations est un tableau de XrPosef .

L'environnement d'exécution doit renvoyer XR_ERROR_VALIDATION_FAILURE à partir de xrQuerySpatialComponentDataEXT si XrSpatialComponentAnchorListEXT se trouve dans la chaîne XrSpatialComponentDataQueryResultEXT :: next, mais que XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT n'est pas inclus dans XrSpatialComponentDataQueryConditionEXT :: componentTypes .

L'environnement d'exécution doit renvoyer XR_ERROR_SIZE_INSUFFICIENT à partir de xrQuerySpatialComponentDataEXT si locationCount est inférieur à XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .

Utilisation valide (implicite)

Configuration

Si XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT est énuméré dans XrSpatialCapabilityComponentTypesEXT :: componentTypes pour une fonctionnalité, une application peut l'activer en incluant l'énumérant dans la liste XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents de la structure dérivée XrSpatialCapabilityConfigurationBaseHeaderEXT de la fonctionnalité qui prend en charge ce composant.

Ce composant ne nécessite aucune configuration spéciale pour être inclus dans la chaîne XrSpatialCapabilityConfigurationBaseHeaderEXT :: next.

Créer une ancre spatiale

La fonction xrCreateSpatialAnchorEXT est définie comme suit :

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

Description des paramètres

L'application peut créer une ancre spatiale à l'aide de xrCreateSpatialAnchorEXT .

Pour obtenir les données de composant mises à jour pour une ancre, transmettez la valeur renseignée dans anchorEntity à XrSpatialUpdateSnapshotCreateInfoEXT :: entities lors de la création d'un instantané. L'application peut utiliser anchorEntityId pour identifier de manière unique cette ancre dans le tableau XrSpatialComponentDataQueryResultEXT :: entityIds lors de l'utilisation de xrQuerySpatialComponentDataEXT .

L'environnement d'exécution doit renvoyer XR_ERROR_VALIDATION_FAILURE à partir de xrCreateSpatialAnchorEXT si XR_SPATIAL_CAPABILITY_ANCHOR_EXT n'a pas été configuré pour spatialContext . Consultez la section Configuration pour savoir comment configurer un XrSpatialContextEXT pour la fonctionnalité XR_SPATIAL_CAPABILITY_ANCHOR_EXT.

L'ancrage représenté par anchorEntity n'est valide que pendant la durée de vie de spatialContext ou jusqu'à ce que l'application appelle xrDestroySpatialEntityEXT, selon la première échéance atteinte. D'autres extensions peuvent proposer des fonctions permettant de conserver cette nouvelle ancre dans plusieurs XrSession ou de la partager avec d'autres applications au-delà des limites du processus.

Une ancre nouvellement créée doit être détectable dans son contexte spatial parent jusqu'à ce qu'elle soit détruite. Cela signifie que l'environnement d'exécution doit inclure anchorEntityId dans l'instantané créé à l'aide de xrCreateSpatialDiscoverySnapshotAsyncEXT pour spatialContext si l'ancrage correspond aux critères de découverte définis dans XrSpatialDiscoverySnapshotCreateInfoEXT . L'ancrage nouvellement créé peut également être visible dans d'autres contextes spatiaux configurés avec XR_SPATIAL_CAPABILITY_ANCHOR_EXT, mais avec un XrSpatialEntityIdEXT différent, car un XrSpatialEntityIdEXT particulier est unique à son XrSpatialContextEXT .

Utilisation valide (implicite)

Codes renvoyés

Opération réussie

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Échec

  • 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 (si XR_ANDROID_spatial_entity_bound_anchor est activé)
  • XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT (si XR_ANDROID_spatial_entity_bound_anchor est activé)

La structure XrSpatialAnchorCreateInfoEXT est définie comme suit :

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

Descriptions des membres

  • type est le XrStructureType de cette structure.
  • next est NULL ou un pointeur vers la structure suivante dans une chaîne de structures.
  • baseSpace est l'XrSpace dans lequel pose est appliqué.
  • time est l'XrTime où se trouve baseSpace (et où pose est appliqué).
  • pose est l'emplacement de l'entité d'ancrage.

Utilisation valide (implicite)

Interroger la pose d'ancrage

Une fois l'ancrage créé, l'environnement d'exécution doit ajuster sa position et son orientation au fil du temps par rapport aux autres espaces afin de maintenir le meilleur alignement possible avec son emplacement réel d'origine, même si cela modifie la relation de l'ancrage avec l'élément XrSpatialAnchorCreateInfoEXT :: baseSpace d'origine utilisé pour l'initialiser.

L'application peut utiliser xrCreateSpatialUpdateSnapshotEXT avec l'XrSpatialEntityEXT de l'ancrage pour créer un XrSpatialSnapshotEXT, puis interroger le composant XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT à partir de cet instantané à l'aide de xrQuerySpatialComponentDataEXT . L'application peut ajouter XrSpatialComponentAnchorListEXT à XrSpatialComponentDataQueryResultEXT :: next pour récupérer les dernières données de localisation des ancres.

L'environnement d'exécution peut définir l'état de suivi d'une ancre nouvellement créée sur XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT . L'application doit uniquement lire l'état de l'entité d'ancrage fourni dans XrSpatialComponentDataQueryResultEXT :: entityStates et les données du composant d'ancrage de l'entité si l'état de suivi est XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .

Consignes d'utilisation des ancres

  • La pose de chaque ancrage s'ajuste indépendamment de tout autre ancrage ou espace. Les objets virtuels ancrés séparément peuvent se déplacer ou pivoter les uns par rapport aux autres, ce qui rompt la hiérarchie spatiale dans les cas où ces objets virtuels sont censés rester en place les uns par rapport aux autres. Dans ce cas, l'application doit réutiliser la même ancre pour tous les objets virtuels qui ne se déplacent pas les uns par rapport aux autres.
  • L'application doit détruire tous les handles XrSpatialEntityEXT des ancres qui ne sont plus utilisées afin de libérer les ressources que l'environnement d'exécution peut utiliser pour suivre ces ancres.

Exemple de code

Configurer la fonctionnalité d'ancrage

L'exemple suivant montre comment configurer la fonctionnalité d'ancrage lors de la création d'un contexte spatial.

// 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));

Créer une ancre spatiale et obtenir sa position

L'exemple suivant montre comment créer une ancre spatiale et obtenir sa position à chaque frame.

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));

Nouvelles commandes

Nouvelles structures

Nouvelles constantes d'énumération

  • XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAME
  • XR_EXT_spatial_anchor_SPEC_VERSION
  • Extension de XrSpatialCapabilityEXT :

    • XR_SPATIAL_CAPABILITY_ANCHOR_EXT
  • Extension de XrSpatialComponentTypeEXT :

    • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
  • Extension de XrStructureType :

    • XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT
    • XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT
    • XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT

Problèmes

  • Pourquoi xrCreateSpatialAnchorEXT génère-t-il un ID d'entité ainsi qu'un handle d'entité ?

    • Résolu
    • Réponse : La fonction xrCreateSpatialAnchorEXT aurait très bien pu fournir uniquement l'ID d'entité en tant que sortie, et les applications auraient pu créer un handle d'entité pour cet ID à l'aide de xrCreateSpatialEntityFromIdEXT . Cependant, étant donné l'utilisation typique d'une ancre où les applications interrogent la pose de l'ancre à chaque frame, elle devient un bon candidat pour être utilisée dans un "instantané de mise à jour", qui nécessite des poignées d'entité en entrée. En anticipant ce cas d'utilisation typique, xrCreateSpatialAnchorEXT effectue xrCreateSpatialEntityFromIdEXT au nom de l'application et lui fournit le handle d'entité à utiliser avec xrCreateSpatialUpdateSnapshotEXT .

Historique des versions

  • Révision 1, 10/07/2024 (Nihav Jain, Google)

    • Description initiale de l'extension