XR_EXT_spatial_anchor

名稱字串

XR_EXT_spatial_anchor

擴充功能類型

執行個體擴充功能

擴充功能註冊編號

763

修訂版本

1

批准狀態

批准

擴充功能和版本依附元件

XR_EXT_spatial_entity

著作人

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

總覽

這項擴充功能以 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
  • nextNULL,或是結構鏈中下一個結構的指標。
  • capabilityXrSpatialCapabilityEXT
  • enabledComponentCountuint32_t,說明 enabledComponents 陣列中的元素數量。
  • enabledComponents 是指向 XrSpatialComponentTypeEXT 陣列的指標。

應用程式可以XrSpatialContextCreateInfoEXT :: capabilityConfigs 中加入 XrSpatialCapabilityConfigurationAnchorEXT 結構的指標,啟用 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 空間功能。

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

有效使用 (隱含)

  • XR_EXT_spatial_anchor 擴充功能必須先啟用,才能使用 XrSpatialCapabilityConfigurationAnchorEXT
  • type 必須XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_ANCHOR_EXT
  • next 必須NULL,或是結構體鏈結中下一個結構體的有效指標
  • capability 必須是有效的 XrSpatialCapabilityEXT
  • enabledComponents 必須是指向 enabledComponentCount 個有效 XrSpatialComponentTypeEXT 值的陣列的指標
  • enabledComponentCount 參數必須大於 0

保證元件

支援 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
  • nextNULL,或是結構鏈中下一個結構的指標。
  • locationCountuint32_t,說明 locations 陣列中的元素數量。
  • locationsXrPosef 的陣列。

如果 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 衍生結構體中,將列舉值納入 XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents 清單,藉此啟用該功能。

如要將這個元件納入 XrSpatialCapabilityConfigurationBaseHeaderEXT :: next 鏈結,不需要進行任何特殊設定。

建立空間錨點

xrCreateSpatialAnchorEXT 函式定義如下:

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

參數說明

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

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

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

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

新建立的錨點必須可在父項空間環境中探索,直到遭到毀損為止。也就是說,如果錨點符合 XrSpatialDiscoverySnapshotCreateInfoEXT 中設定的探索條件,執行階段必須在透過 xrCreateSpatialDiscoverySnapshotAsyncEXTspatialContext 建立的快照中加入 anchorEntityId。新建立的錨點可能也會在以 XR_SPATIAL_CAPABILITY_ANCHOR_EXT 設定的其他空間環境中探索到,但由於特定 XrSpatialEntityIdEXTXrSpatialContextEXT 專屬的,因此會使用不同的 XrSpatialEntityIdEXT

有效使用 (隱含)

傳回代碼

成功

  • 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
  • nextNULL,或是結構鏈中下一個結構的指標。
  • baseSpace 是套用 poseXrSpace
  • timebaseSpace 所在的XrTime (以及 pose 適用的) 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 (Google 的 Nihav Jain)

    • 擴充功能初始說明