XR_EXT_spatial_anchor

Chaîne de nom

XR_EXT_spatial_anchor

Type d'extension

Extension d'instance

Numéro d'extension enregistré

763

Révision

1

État de 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, puis 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'ancre au fil du temps, selon les besoins, indépendamment de tous les autres espaces et ancres, afin de s'assurer qu'elle conserve son mappage d'origine dans le monde réel.

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

Avantage de l'utilisation d'ancres

Comme la compréhension de l'environnement physique de l'utilisateur par l'environnement d'exécution est mise à jour tout au long du cycle 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 correspond au 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

Le XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT utilise XrPosef pour ses données, qui fournit la position et l'orientation de l'ancre.

Structure de la liste des composants pour interroger les 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 correspond au 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 des 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 . Pour savoir comment configurer un XrSpatialContextEXT pour la fonctionnalité XR_SPATIAL_CAPABILITY_ANCHOR_EXT, consultez la section Configuration.

L'ancre représentée par anchorEntity n'est valide que pendant la durée de vie de spatialContext , ou jusqu'à ce que l'application appelle xrDestroySpatialEntityEXT sur celle-ci, selon la première de ces deux options. D'autres extensions peuvent proposer des fonctions permettant de rendre persistante cette ancre nouvellement créée sur plusieurs XrSession ou de la partager entre les limites de processus avec d'autres applications.

Une ancre nouvellement créée, jusqu'à sa destruction, doit être détectable dans son contexte spatial parent. Cela signifie que l'environnement d'exécution doit inclure anchorEntityId dans l'instantané créé à l'aide de xrCreateSpatialDiscoverySnapshotAsyncEXT pour spatialContext si l'ancre correspond aux critères de découverte définis dans XrSpatialDiscoverySnapshotCreateInfoEXT . L'ancre nouvellement créée peut également être détectable dans d'autres contextes spatiaux configurés avec XR_SPATIAL_CAPABILITY_ANCHOR_EXT, bien qu'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 correspond au XrStructureType de cette structure.
  • next est NULL ou un pointeur vers la structure suivante dans une chaîne de structures.
  • baseSpace est le XrSpace dans lequel pose est appliqué.
  • time correspond au XrTime auquel baseSpace est situé (et pose est appliqué).
  • pose correspond à l'emplacement de l'entité d'ancrage.

Utilisation valide (implicite)

Interroger la pose de l'ancre

Une fois l'ancre créée, 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 d'origine dans le monde réel, même si cela modifie la relation de l'ancre avec le XrSpatialAnchorCreateInfoEXT d'origine :: baseSpace utilisé pour l'initialiser.

L'application peut utiliser xrCreateSpatialUpdateSnapshotEXT avec le XrSpatialEntityEXT de l'ancre 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 ne doit lire l'état de l'entité d'ancrage fourni dans XrSpatialComponentDataQueryResultEXT :: entityStates et les données du composant d'ancrage de l'entité que si l'état de suivi est XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .

Consignes d'utilisation des ancres

  • La pose de chaque ancre s'ajuste indépendamment de toute autre ancre 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 descripteurs XrSpatialEntityEXT pour les 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 son emplacement

L'exemple suivant montre comment créer une ancre spatiale et obtenir sa pose à 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 descripteur 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 descripteur d'entité pour cet ID à l'aide de xrCreateSpatialEntityFromIdEXT . Toutefois, é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 descripteurs d'entité en entrée. En prévision de ce cas d'utilisation typique, xrCreateSpatialAnchorEXT effectue xrCreateSpatialEntityFromIdEXT au nom de l'application et lui fournit le descripteur d'entité à utiliser avec xrCreateSpatialUpdateSnapshotEXT .

Historique des versions

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

    • Description initiale de l'extension