XR_EXT_spatial_anchor

Name String

XR_EXT_spatial_anchor

Тип расширения

Расширение экземпляра

Зарегистрированный добавочный номер

763

Revision

1

Статус ратификации

Ратифицировано

Зависимости расширений и версий

XR_EXT_spatial_entity

Авторы

Нихав Джайн (Nihav Jain), Google
Натали Флери (Natalie Fleury), Meta
Юичи Тагучи (Yuichi Taguchi), Meta
Рон Бессемс (Ron Bessems), Meta
Инь Ли (Yin Li), Microsoft
Джимми Алампарамбил (Jimmy Alamparambil), ByteDance
Чжипэн Лю (Zhipeng Liu), ByteDance
Цзюнь Янь (Jun Yan), ByteDance

Обзор

Это расширение основано на XR_EXT_spatial_entity и позволяет приложениям создавать пространственные привязки – произвольные точки в физической среде пользователя, которые затем будут отслеживаться средой выполнения. Затем среда выполнения должна при необходимости корректировать положение и ориентацию начала координат якоря с течением времени, независимо от всех других пространств и якорей, чтобы обеспечить сохранение его исходного сопоставления с реальным миром.

Якорь, который отслеживает заданное положение и ориентацию в XrSpatialContextEXT, представлен как пространственный объект с компонентом XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT.

Преимущества использования фиксированных объявлений

По мере того как среда выполнения обновляет информацию о физическом окружении пользователя в течение жизненного цикла XrSpatialContextEXT , виртуальные объекты могут смещаться относительно места, где они были размещены приложением. Это влияет на реалистичность приложения и качество взаимодействия с пользователем. Если создать якорь рядом с виртуальным объектом и всегда отрисовывать этот объект относительно якоря, приложение сможет гарантировать, что каждый виртуальный объект будет оставаться в одном и том же положении и ориентации в физической среде. Кроме того, в отличие от некоторых опорных пространств, на якоря не влияет повторное центрирование на уровне системы.

Поддержка среды выполнения

Если среда выполнения поддерживает пространственные привязки, она должна указывать на это, перечисляя XR_SPATIAL_CAPABILITY_ANCHOR_EXT в xrEnumerateSpatialCapabilitiesEXT .

Конфигурация

Структура XrSpatialCapabilityConfigurationAnchorEXT определяется следующим образом:

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

Описания участников

  • type – это XrStructureType этой структуры.
  • next – это NULL или указатель на следующую структуру в цепочке.
  • capability – это XrSpatialCapabilityEXT .
  • enabledComponentCount – это uint32_t, описывающий количество элементов в массиве enabledComponents.
  • enabledComponents – указатель на массив XrSpatialComponentTypeEXT .

Приложения могут включить пространственную функцию XR_SPATIAL_CAPABILITY_ANCHOR_EXT, добавив указатель на структуру XrSpatialCapabilityConfigurationAnchorEXT в XrSpatialContextCreateInfoEXT :: capabilityConfigs .

Среда выполнения должна возвращать XR_ERROR_VALIDATION_FAILURE, если capability не равно XR_SPATIAL_CAPABILITY_ANCHOR_EXT .

Допустимое использование (неявное)

Гарантированные компоненты

Среда выполнения, поддерживающая XR_SPATIAL_CAPABILITY_ANCHOR_EXT, должна предоставлять следующие пространственные компоненты в качестве гарантированных компонентов всех объектов, созданных или обнаруженных этой функцией, и должна перечислять их в xrEnumerateSpatialCapabilityComponentTypesEXT :

  • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT

Компонент Anchor

Данные компонента

XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT использует XrPosef для своих данных, которые предоставляют положение и ориентацию якоря.

Структура списка компонентов для запроса данных

Структура XrSpatialComponentAnchorListEXT определяется следующим образом:

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

Описания участников

  • type – это XrStructureType этой структуры.
  • next – это NULL или указатель на следующую структуру в цепочке.
  • locationCount – это uint32_t, описывающий количество элементов в массиве locations.
  • locations – массив XrPosef .

Среда выполнения должна возвращать XR_ERROR_VALIDATION_FAILURE из xrQuerySpatialComponentDataEXT, если XrSpatialComponentAnchorListEXT находится в цепочке XrSpatialComponentDataQueryResultEXT :: next, но XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT не включен в XrSpatialComponentDataQueryConditionEXT :: componentTypes .

Среда выполнения должна возвращать XR_ERROR_SIZE_INSUFFICIENT из xrQuerySpatialComponentDataEXT, если locationCount меньше XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput .

Допустимое использование (неявное)

  • Расширение XR_EXT_spatial_anchor должно быть включено до использования XrSpatialComponentAnchorListEXT.
  • type должно быть XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT
  • next должно быть NULL или действительным указателем на следующую структуру в цепочке структур.
  • locations должен быть указателем на массив из locationCount структур XrPosef.
  • Значение параметра locationCount должно быть больше 0.
Конфигурация

Если XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT перечисляется в XrSpatialCapabilityComponentTypesEXT :: componentTypes для определенной функции, приложение может включить ее, добавив перечисляемый тип в список XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents производной структуры XrSpatialCapabilityConfigurationBaseHeaderEXT функции, которая поддерживает этот компонент.

Для включения этого компонента в цепочку XrSpatialCapabilityConfigurationBaseHeaderEXT :: next не требуется специальная конфигурация.

Создание пространственного якоря

Функция xrCreateSpatialAnchorEXT определяется следующим образом:

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

Описание параметров

  • spatialContext – это XrSpatialContextEXT, ранее созданный с помощью xrCreateSpatialContextAsyncEXT .
  • createInfo – указатель на XrSpatialAnchorCreateInfoEXT .
  • anchorEntityId – указатель на XrSpatialEntityIdEXT, в котором возвращается идентификатор объекта привязки.
  • anchorEntity – указатель на XrSpatialEntityEXT, в котором возвращается дескриптор объекта привязки.

Приложение может создать пространственный якорь с помощью xrCreateSpatialAnchorEXT .

Чтобы получить обновленные данные компонента для привязки, передайте значение, указанное в anchorEntity, в XrSpatialUpdateSnapshotCreateInfoEXT :: entities при создании снимка. Приложение может использовать anchorEntityId, чтобы идентифицировать этот якорь в массиве XrSpatialComponentDataQueryResultEXT :: entityIds при использовании xrQuerySpatialComponentDataEXT .

Среда выполнения должна возвращать XR_ERROR_VALIDATION_FAILURE из xrCreateSpatialAnchorEXT, если XR_SPATIAL_CAPABILITY_ANCHOR_EXT не настроен для spatialContext . Инструкции по настройке XrSpatialContextEXT для функции XR_SPATIAL_CAPABILITY_ANCHOR_EXT приведены в разделе Конфигурация.

Якорь, представленный anchorEntity, действителен только в течение времени существования spatialContext или до тех пор, пока приложение не вызовет для него xrDestroySpatialEntityEXT, в зависимости от того, что произойдет раньше. Другие расширения могут предлагать функции для сохранения этого нового якоря в нескольких XrSession или для его совместного использования в разных процессах с другими приложениями.

Новый якорь должен быть доступен для обнаружения в родительском пространственном контексте, пока не будет удален. Это означает, что среда выполнения должна включить anchorEntityId в снимок, созданный с помощью xrCreateSpatialDiscoverySnapshotAsyncEXT для spatialContext, если привязка соответствует критериям обнаружения, заданным в XrSpatialDiscoverySnapshotCreateInfoEXT . Новый привязанный объект может также обнаруживаться в других пространственных контекстах, настроенных с помощью XR_SPATIAL_CAPABILITY_ANCHOR_EXT, но с другим XrSpatialEntityIdEXT, поскольку определенный XrSpatialEntityIdEXT уникален для своего XrSpatialContextEXT .

Допустимое использование (неявное)

  • Расширение XR_EXT_spatial_anchor должно быть включено до вызова xrCreateSpatialAnchorEXT.
  • spatialContext должен быть действительным дескриптором XrSpatialContextEXT.
  • createInfo должен быть указателем на действительную структуру XrSpatialAnchorCreateInfoEXT.
  • anchorEntityId должен быть указателем на значение XrSpatialEntityIdEXT.
  • anchorEntity должен быть указателем на дескриптор XrSpatialEntityEXT.

Коды возврата

Выполнено

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Сбой

  • 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 (если включен параметр XR_ANDROID_spatial_entity_bound_anchor)
  • XR_ERROR_SPATIAL_ENTITY_ID_INVALID_EXT (если включен параметр XR_ANDROID_spatial_entity_bound_anchor)

Структура XrSpatialAnchorCreateInfoEXT определяется следующим образом:

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

Описания участников

  • type – это XrStructureType этой структуры.
  • next – это NULL или указатель на следующую структуру в цепочке.
  • baseSpace – это XrSpace, в котором применяется pose.
  • time – XrTime, в котором находится baseSpace (и применяется pose).
  • pose – местоположение объекта привязки.

Допустимое использование (неявное)

Запросить позу якоря

После создания якоря среда выполнения должна со временем корректировать его положение и ориентацию относительно других пространств, чтобы поддерживать наилучшее выравнивание по отношению к его исходному местоположению в реальном мире, даже если это изменяет отношение якоря к исходному XrSpatialAnchorCreateInfoEXT :: baseSpace, используемому для его инициализации.

Приложение может использовать xrCreateSpatialUpdateSnapshotEXT с XrSpatialEntityEXT привязки, чтобы создать новый XrSpatialSnapshotEXT, а затем запросить компонент XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT из этого снимка с помощью xrQuerySpatialComponentDataEXT . Приложение может добавить XrSpatialComponentAnchorListEXT в XrSpatialComponentDataQueryResultEXT :: next, чтобы получить последние данные о местоположении для привязок.

Среда выполнения может установить статус отслеживания для нового якоря на XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT . Приложение должно считывать только состояние объекта привязки, указанное в XrSpatialComponentDataQueryResultEXT :: entityStates, и данные компонента привязки объекта, если состояние отслеживания – XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT .

Рекомендации по использованию якорей

  • Положение каждой привязки корректируется независимо от других привязок и пространств. Виртуальные объекты с отдельными привязками могут смещаться или поворачиваться относительно друг друга, нарушая пространственную иерархию в случаях, когда эти виртуальные объекты должны оставаться на месте относительно друг друга. В таких случаях приложение должно использовать один и тот же якорь для всех виртуальных объектов, которые не перемещаются относительно друг друга.
  • Приложение должно уничтожать все дескрипторы XrSpatialEntityEXT для якорей, которые больше не используются, чтобы освободить ресурсы, которые среда выполнения может использовать для отслеживания этих якорей.

Пример кода

Настройка функции привязки

В следующем примере показано, как настроить функцию привязки при создании пространственного контекста.

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

Создание пространственного якоря и получение его местоположения

В примере ниже показано, как создать пространственный якорь и получать его положение в каждом кадре.

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

Новые команды

Новые структуры

Новые константы перечисления

  • XR_EXT_SPATIAL_ANCHOR_EXTENSION_NAME
  • XR_EXT_spatial_anchor_SPEC_VERSION
  • Расширение XrSpatialCapabilityEXT :

    • XR_SPATIAL_CAPABILITY_ANCHOR_EXT
  • Расширение XrSpatialComponentTypeEXT :

    • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT
  • Расширение XrStructureType :

    • XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_EXT
    • XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT
    • XR_TYPE_SPATIAL_COMPONENT_ANCHOR_LIST_EXT

Проблемы

  • Почему xrCreateSpatialAnchorEXT выводит идентификатор объекта и дескриптор объекта?

    • Вопрос решен
    • Ответ. Функция xrCreateSpatialAnchorEXT могла бы просто предоставить идентификатор объекта в качестве выходных данных, а приложения могли бы создать дескриптор объекта для этого идентификатора с помощью xrCreateSpatialEntityFromIdEXT. Однако, учитывая типичное использование привязки, когда приложения запрашивают позу привязки для каждого кадра, она становится хорошим кандидатом для использования в «снимке обновления», для которого в качестве входных данных требуются дескрипторы сущностей. Чтобы упростить этот процесс, xrCreateSpatialAnchorEXT выполняет xrCreateSpatialEntityFromIdEXT от имени приложения и предоставляет ему дескриптор объекта для использования с xrCreateSpatialUpdateSnapshotEXT .

История версий

  • Версия 1, 10 июля 2024 г. (Нихав Джайн, Google)

    • Описание расширения