XR_EXT_spatial_anchor

Name String

XR_EXT_spatial_anchor

擴充功能類型

執行個體擴充功能

擴充功能註冊編號

763

修訂版本

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 的生命週期中,執行階段對使用者實體環境的理解會不斷更新,因此虛擬物件可能會偏離應用程式放置的位置,進而影響應用程式的真實感和使用者體驗品質。應用程式可以在虛擬物件放置位置附近建立錨點,然後一律根據錨點算繪虛擬物件,確保每個虛擬物件在實體環境中都保持相同的位置和方向。此外,與某些參考空間不同,錨點不受系統層級重新置中的影響。

執行階段支援

如果執行階段支援空間錨點,則必須在 xrEnumerateSpatialCapabilitiesEXT 中列舉 XR_SPATIAL_CAPABILITY_ANCHOR_EXT,以表示支援。

設定

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 空間功能,方法是在 XrSpatialContextCreateInfoEXT :: capabilityConfigs 中加入指向 XrSpatialCapabilityConfigurationAnchorEXT 結構的指標。

如果 capability 不是 XR_SPATIAL_CAPABILITY_ANCHOR_EXT,執行階段「必須」傳回 XR_ERROR_VALIDATION_FAILURE。

有效用途 (隱含)

保證元件

支援 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 的執行階段「必須」提供下列空間元件,做為這項功能建立或探索的所有實體的保證元件,且「必須」在 xrEnumerateSpatialCapabilityComponentTypesEXT 中列舉這些元件:

  • XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT

錨定元件

元件資料

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 陣列。

如果 XrSpatialComponentAnchorListEXT 位於 XrSpatialComponentDataQueryResultEXT :: next 鏈結中,但 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT 未包含在 XrSpatialComponentDataQueryConditionEXT :: componentTypes 中,執行階段必須從 xrQuerySpatialComponentDataEXT 傳回 XR_ERROR_VALIDATION_FAILURE。

如果 locationCount 小於 XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput,執行階段必須從 xrQuerySpatialComponentDataEXT 傳回 XR_ERROR_SIZE_INSUFFICIENT。

有效用途 (隱含)

  • 必須先啟用 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);

參數說明

應用程式可以使用 xrCreateSpatialAnchorEXT 建立空間錨點。

如要取得錨點的更新元件資料,請在建立快照時,將 anchorEntity 中填入的值傳遞至 XrSpatialUpdateSnapshotCreateInfoEXT :: entities。使用 xrQuerySpatialComponentDataEXT 時,應用程式可以使用 anchorEntityId,在 XrSpatialComponentDataQueryResultEXT :: entityIds 陣列中,明確識別這個錨點。

如果未針對 spatialContext 設定 XR_SPATIAL_CAPABILITY_ANCHOR_EXT,執行階段必須從 xrCreateSpatialAnchorEXT 傳回 XR_ERROR_VALIDATION_FAILURE。請參閱「設定」一節,瞭解如何為 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 功能設定 XrSpatialContextEXT。

anchorEntity 代表的錨點僅在 spatialContext 的生命週期內有效,或直到應用程式對其呼叫 xrDestroySpatialEntityEXT 為止,以先發生者為準。其他擴充功能可能提供函式,在多個 XrSession 中保留這個新建立的錨點,或與其他應用程式跨程序邊界共用。

新建立的錨點在刪除前,必須可在其父項空間情境中找到。也就是說,如果錨點符合 XrSpatialDiscoverySnapshotCreateInfoEXT 中設定的探索條件,執行階段必須在 spatialContext 的 xrCreateSpatialDiscoverySnapshotAsyncEXT 建立的快照中加入 anchorEntityId。新建立的錨點可能也會在其他使用 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 設定的空間情境中被偵測到,但 XrSpatialEntityIdEXT 會不同,因為特定 XrSpatialEntityIdEXT 是其 XrSpatialContextEXT 專屬。

有效用途 (隱含)

傳回代碼

成功

  • 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 是套用 pose 的 XrSpace。
  • time 是 baseSpace 所在的 XrTime (且 pose 已套用)。
  • pose 是錨定實體的位置。

有效用途 (隱含)

查詢錨點姿勢

建立錨點後,執行階段應隨著時間調整其位置和方向 (相對於其他空間),盡可能與原始真實世界位置保持一致,即使這會改變錨點與用於初始化錨點的原始 XrSpatialAnchorCreateInfoEXT :: baseSpace 之間的關係。

應用程式可以搭配錨點的 XrSpatialEntityEXT 使用 xrCreateSpatialUpdateSnapshotEXT,建立新的 XrSpatialSnapshotEXT,然後使用 xrQuerySpatialComponentDataEXT 從該快照查詢 XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT 元件。應用程式可以將 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

問題

版本記錄

  • 修訂版本 1,2024-07-10 (Nihav Jain,Google)

    • 初始擴充功能說明