XR_EXT_spatial_persistence

Name String

XR_EXT_spatial_persistence

擴充功能類型

執行個體擴充功能

擴充功能註冊編號

764

修訂版本

1

批准狀態

已批准

擴充功能和版本依附元件

XR_EXT_spatial_entity
和
XR_EXT_future

著作人

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

總覽

這項擴充功能可讓應用程式在應用程式工作階段、OpenXR 工作階段,以及工作階段內的多個 OpenXR 空間情境中,探索及關聯空間實體。XR_EXT_spatial_entity 擴充功能規定,XrSpatialContextEXT 中的實體會以 XrSpatialEntityIdEXT 表示。這項擴充功能延伸了這個概念,規定實體如果持續存在,就會在應用程式和 OpenXR 工作階段中以 XrUuid 表示,也就是說,應用程式可以使用這項擴充功能提供的 XrUuid,在不同工作階段中識別實體。這項擴充功能也與 XR_EXT_spatial_entity 擴充功能有實用的重疊,可探索使用者環境中的持續實體,並查詢其元件資料。

空間持續性背景資訊

建立空間持續性內容

XR_DEFINE_HANDLE(XrSpatialPersistenceContextEXT)

XrSpatialPersistenceContextEXT 控制代碼代表與永久空間實體儲存空間的連線。

xrCreateSpatialPersistenceContextAsyncEXT 函式的定義如下:

XrResult xrCreateSpatialPersistenceContextAsyncEXT(
    XrSession                                   session,
    const XrSpatialPersistenceContextCreateInfoEXT* createInfo,
    XrFutureEXT*                                future);

參數說明

應用程式可以使用 xrCreateSpatialPersistenceContextAsyncEXT 函式建立 XrSpatialPersistenceContextEXT 控制代碼,並在 createInfo 中設定持續性內容的範圍。

如果 xrEnumerateSpatialPersistenceScopesEXT 未列舉 XrSpatialPersistenceContextCreateInfoEXT :: scope,執行階段必須傳回 XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT。

如果執行階段強制執行權限系統,控管應用程式對 XrSpatialPersistenceContextEXT 所代表永久儲存空間的存取權,則在未授予應用程式這些權限時,執行階段必須傳回 XR_ERROR_PERMISSION_INSUFFICIENT。

有效用途 (隱含)

傳回代碼

成功

  • 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_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT
  • XR_ERROR_VALIDATION_FAILURE

XrSpatialPersistenceContextCreateInfoEXT 結構定義如下:

typedef struct XrSpatialPersistenceContextCreateInfoEXT {
    XrStructureType                 type;
    const void*                     next;
    XrSpatialPersistenceScopeEXT    scope;
} XrSpatialPersistenceContextCreateInfoEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。核心 OpenXR 或這個擴充功能中未定義這類結構。
  • scope 是 XrSpatialPersistenceScopeEXT,用於定義持續性內容的儲存範圍。

XrSpatialPersistenceContextCreateInfoEXT 結構說明建立 XrSpatialPersistenceContextEXT 控制代碼所需的資訊。

有效用途 (隱含)

typedef enum XrSpatialPersistenceScopeEXT {
    XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT = 1,
    XR_SPATIAL_PERSISTENCE_SCOPE_LOCAL_ANCHORS_EXT = 1000781000,
    XR_SPATIAL_PERSISTENCE_SCOPE_ANCHORS_FOR_CLOUD_SHARING_ANDROIDX1 = 1000808000,
    XR_SPATIAL_PERSISTENCE_SCOPE_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceScopeEXT;

XrSpatialPersistenceScopeEXT 列舉會識別不同類型的持續性背景範圍。

列舉的意義如下:

列舉說明

XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT

為應用程式提供唯讀存取權 (即應用程式無法修改與此範圍相關聯的儲存空間),可存取系統保存及管理的空間實體。應用程式可以使用這個範圍的持續性元件中的 UUID,在空間情境和裝置重新啟動時建立實體關聯。

XR_SPATIAL_PERSISTENCE_SCOPE_LOCAL_ANCHORS_EXT

持久性作業和資料存取權僅限於同一裝置、同一使用者和同一應用程式的空間錨點 (由 XR_EXT_spatial_persistence_operations 擴充功能新增)

XR_SPATIAL_PERSISTENCE_SCOPE_ANCHORS_FOR_CLOUD_SHARING_ANDROIDX1

持久性作業和資料存取權僅限於空間錨點,由同一個雲端專案擁有及管理。(由 XR_ANDROIDX1_spatial_anchor_cloud_sharing 擴充功能新增)

xrEnumerateSpatialPersistenceScopesEXT 函式的定義如下:

XrResult xrEnumerateSpatialPersistenceScopesEXT(
    XrInstance                                  instance,
    XrSystemId                                  systemId,
    uint32_t                                    persistenceScopeCapacityInput,
    uint32_t*                                   persistenceScopeCountOutput,
    XrSpatialPersistenceScopeEXT*               persistenceScopes);

參數說明

  • instance 是 XrInstance 的控制代碼。
  • systemId 是要列舉空間持續性範圍的 XrSystemId。
  • persistenceScopeCapacityInput 是 persistenceScopes 陣列的容量,或 0 表示要求擷取所需容量。
  • persistenceScopeCountOutput 是永久範圍的數量,或 persistenceScopeCapacityInput 不足時所需的容量。
  • persistenceScopes 是 XrSpatialPersistenceScopeEXT 的陣列。如果 persistenceScopeCapacityInput 為 0,則可以是 NULL。
  • 如要進一步瞭解如何擷取必要的 persistenceScopes 大小,請參閱「緩衝區空間參數」一章。

應用程式可以使用 xrEnumerateSpatialPersistenceScopesEXT 列舉特定 XrSystemId 支援的空間持久性範圍清單。

有效用途 (隱含)

  • 必須先啟用 XR_EXT_spatial_persistence 擴充功能,才能呼叫 xrEnumerateSpatialPersistenceScopesEXT
  • instance「必須」是有效的 XrInstance 控制代碼
  • persistenceScopeCountOutput「必須」是指向 uint32_t 值的指標
  • 如果 persistenceScopeCapacityInput 不是 0,persistenceScopes 必須是指向 persistenceScopeCapacityInput XrSpatialPersistenceScopeEXT 值陣列的指標

傳回代碼

成功

  • XR_SUCCESS

失敗

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SIZE_INSUFFICIENT
  • XR_ERROR_SYSTEM_INVALID
  • XR_ERROR_VALIDATION_FAILURE

xrCreateSpatialPersistenceContextCompleteEXT 函式的定義如下:

XrResult xrCreateSpatialPersistenceContextCompleteEXT(
    XrSession                                   session,
    XrFutureEXT                                 future,
    XrCreateSpatialPersistenceContextCompletionEXT* completion);

參數說明

xrCreateSpatialPersistenceContextCompleteEXT 會完成由 xrCreateSpatialPersistenceContextAsyncEXT 啟動的非同步作業。如果 future 未處於就緒狀態,執行階段必須傳回 XR_ERROR_FUTURE_PENDING_EXT。如果 future 已完成或取消,執行階段必須傳回 XR_ERROR_FUTURE_INVALID_EXT。

有效用途 (隱含)

傳回代碼

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失敗

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_FUTURE_INVALID_EXT
  • XR_ERROR_FUTURE_PENDING_EXT
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_VALIDATION_FAILURE

XrCreateSpatialPersistenceContextCompletionEXT 結構定義如下:

typedef struct XrCreateSpatialPersistenceContextCompletionEXT {
    XrStructureType                         type;
    void*                                   next;
    XrResult                                futureResult;
    XrSpatialPersistenceContextResultEXT    createResult;
    XrSpatialPersistenceContextEXT          persistenceContext;
} XrCreateSpatialPersistenceContextCompletionEXT;

成員說明

未來退貨代碼

futureResult 值:

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失敗

  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_PERMISSION_INSUFFICIENT

如果 futureResult 和 createResult 都是成功代碼,則 persistenceContext「必須」有效。如果 persistenceContext 有效,則在 xrCreateSpatialPersistenceContextAsyncEXT :: session 的生命週期內,或在應用程式搭配 persistenceContext 使用 xrDestroySpatialPersistenceContextEXT 之前 (以先發生者為準),必須保持有效。

只有在 futureResult 為成功代碼時,執行階段才必須設定 createResult。

有效用途 (隱含)

typedef enum XrSpatialPersistenceContextResultEXT {
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT = 0,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_ENTITY_NOT_TRACKING_EXT = -1000781001,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_PERSIST_UUID_NOT_FOUND_EXT = -1000781002,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_LOCALIZATION_FAILURE_ANDROIDX1 = -1000808000,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_MAP_FEATURE_INSUFFICIENT_ANDROIDX1 = -1000808001,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_NETWORK_FAILURE_ANDROIDX1 = -1000808002,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_NETWORK_TIMEOUT_ANDROIDX1 = -1000808003,
    XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceContextResultEXT;

XrSpatialPersistenceContextResultEXT 列舉會識別持續性作業的不同結果代碼類型。應用程式不一定能控制持續性作業期間的失敗,而這個列舉用於傳達這類情況。與 XrResult 類似,XrSpatialPersistenceContextResultEXT 列舉中的成功代碼為非負值,失敗代碼則為負值。

列舉的意義如下:

列舉說明

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT

持續性內容作業已成功。

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_ENTITY_NOT_TRACKING_EXT

執行階段無法追蹤實體,因此持續性作業失敗。(由 XR_EXT_spatial_persistence_operations 擴充功能新增)

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_PERSIST_UUID_NOT_FOUND_EXT

儲存空間中找不到提供的永久 UUID。(由 XR_EXT_spatial_persistence_operations 擴充功能新增)

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_LOCALIZATION_FAILURE_ANDROIDX1

定位失敗,因此無法執行持續性作業。(由 XR_ANDROIDX1_spatial_anchor_cloud_sharing 擴充功能新增)

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_MAP_FEATURE_INSUFFICIENT_ANDROIDX1

本地化地圖功能不足,因此無法執行持續性作業。(由 XR_ANDROIDX1_spatial_anchor_cloud_sharing 擴充功能新增)

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_NETWORK_FAILURE_ANDROIDX1

網路連線失敗,因此無法執行持續性作業。(由 XR_ANDROIDX1_spatial_anchor_cloud_sharing 擴充功能新增)

XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_NETWORK_TIMEOUT_ANDROIDX1

網路逾時,因此持續性作業失敗。(由 XR_ANDROIDX1_spatial_anchor_cloud_sharing 擴充功能新增)

刪除空間持續性背景資訊

xrDestroySpatialPersistenceContextEXT 函式的定義如下:

XrResult xrDestroySpatialPersistenceContextEXT(
    XrSpatialPersistenceContextEXT              persistenceContext);

參數說明

應用程式完成空間持續性工作後,可以使用 xrDestroySpatialPersistenceContextEXT 釋放 persistenceContext 控制代碼。

如果 persistenceContext 透過 XrSpatialContextPersistenceConfigEXT 連結至任何有效的 XrSpatialContextEXT 控制代碼,則執行階段在呼叫 xrDestroySpatialPersistenceContextEXT 時,不得刪除 persistenceContext 的基礎資源。這是因為空間結構定義仍會使用永久性結構定義的資源,來探索永久性實體。在這種情況下,刪除持續性結構定義控制代碼只會移除應用程式對這些資源的存取權。

當與持久性內容連結的所有 XrSpatialContextEXT 控制代碼都遭到刪除時,必須釋出已刪除 XrSpatialPersistenceContextEXT 的資源。

有效用途 (隱含)

執行緒安全

  • 存取 persistenceContext 和任何子項控制代碼時,必須從外部同步

傳回代碼

成功

  • XR_SUCCESS

失敗

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_RUNTIME_FAILURE

探索持續性實體

持續性元件

持續性空間實體具有持續性元件,如果建立 XrSpatialContextEXT 時啟用 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,且包含在 XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes 或 XrSpatialUpdateSnapshotCreateInfoEXT :: componentTypes 中,執行階段必須在探索和更新快照中包含該元件。

元件資料

XrSpatialPersistenceDataEXT 結構定義如下:

typedef struct XrSpatialPersistenceDataEXT {
    XrUuid                          persistUuid;
    XrSpatialPersistenceStateEXT    persistState;
} XrSpatialPersistenceDataEXT;

成員說明

有效用途 (隱含)

typedef enum XrSpatialPersistenceStateEXT {
    XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT = 1,
    XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT = 2,
    XR_SPATIAL_PERSISTENCE_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
} XrSpatialPersistenceStateEXT;

XrSpatialPersistenceStateEXT 列舉會識別永久 UUID 的不同狀態。

列舉的意義如下:

列舉說明

XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT

已成功從儲存空間載入永久 UUID。

XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT

在儲存空間中找不到永久 UUID,可能是已從儲存空間中移除,或從未存在於儲存空間中。

用於查詢資料的元件清單結構

XrSpatialComponentPersistenceListEXT 結構定義如下:

typedef struct XrSpatialComponentPersistenceListEXT {
    XrStructureType                 type;
    void*                           next;
    uint32_t                        persistDataCount;
    XrSpatialPersistenceDataEXT*    persistData;
} XrSpatialComponentPersistenceListEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。核心 OpenXR 或這個擴充功能中未定義這類結構。
  • persistDataCount 是 uint32_t,用於描述 persistData 陣列中的元素數量。
  • persistData 是 XrSpatialPersistenceDataEXT 的陣列。

如果 XrSpatialComponentPersistenceListEXT 位於 XrSpatialComponentDataQueryResultEXT :: next 的下一個鏈結中,但 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT 未包含在 XrSpatialComponentDataQueryConditionEXT :: componentTypes 中,執行階段必須從 xrQuerySpatialComponentDataEXT 傳回 XR_ERROR_VALIDATION_FAILURE。

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

與其他元件不同,無論 XrSpatialEntityTrackingStateEXT 為何,執行階段都必須設定 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT 的資料。

有效用途 (隱含)

設定

如果 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT 在 XrSpatialCapabilityComponentTypesEXT :: componentTypes 中列舉,應用程式可以在 XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents 清單中加入列舉,啟用該功能。這個元件不需要任何特殊設定,即可納入 XrSpatialCapabilityConfigurationBaseHeaderEXT 的下一個鏈結。如果應用程式在啟用的元件清單中加入 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,則必須在 XrSpatialContextCreateInfoEXT 的下一個鏈結中加入 XrSpatialContextPersistenceConfigEXT,否則執行階段必須從 xrCreateSpatialContextAsyncEXT 傳回 XR_ERROR_SPATIAL_CAPABILITY_CONFIGURATION_INVALID_EXT。

使用持續性背景資訊設定空間背景資訊

XrSpatialContextPersistenceConfigEXT 結構定義如下:

typedef struct XrSpatialContextPersistenceConfigEXT {
    XrStructureType                          type;
    const void*                              next;
    uint32_t                                 persistenceContextCount;
    const XrSpatialPersistenceContextEXT*    persistenceContexts;
} XrSpatialContextPersistenceConfigEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。核心 OpenXR 或這個擴充功能中未定義這類結構。
  • persistenceContextCount 是 uint32_t,用於描述 persistenceContexts 陣列中的元素數量。
  • persistenceContexts 是 XrSpatialPersistenceContextEXT 的陣列。

應用程式可以將 XrSpatialContextPersistenceConfigEXT 新增至 XrSpatialContextCreateInfoEXT 的下一個鏈結。這項設定會使用 persistenceContexts 設定建立的 XrSpatialContextEXT,並允許應用程式探索 persistenceContexts 中 XrSpatialPersistenceContextEXT 控制代碼所代表的儲存空間中,保存的空間實體。

有效用途 (隱含)

建立探索快照

探索具有特定 UUID 的實體

XrSpatialDiscoveryPersistenceUuidFilterEXT 結構定義如下:

typedef struct XrSpatialDiscoveryPersistenceUuidFilterEXT {
    XrStructureType    type;
    const void*        next;
    uint32_t           persistedUuidCount;
    const XrUuid*      persistedUuids;
} XrSpatialDiscoveryPersistenceUuidFilterEXT;

成員說明

  • type 是這個結構的 XrStructureType。
  • next 是 NULL,或指向結構鏈中下一個結構的指標。核心 OpenXR 或這個擴充功能中未定義這類結構。
  • persistedUuidCount 是 uint32_t,用於描述 persistedUuids 陣列中的元素數量
  • persistedUuids 是 XrUuid 陣列。

應用程式可以在 XrSpatialDiscoverySnapshotCreateInfoEXT 的下一個鏈結中使用 XrSpatialDiscoveryPersistenceUuidFilterEXT,將探索作業範圍限定在實體,且這些實體的永久 UUID 位於 persistedUuids 中提供的 UUID 集合。

如果應用程式在 XrSpatialDiscoverySnapshotCreateInfoEXT 的下一個鏈結中新增 XrSpatialDiscoveryPersistenceUuidFilterEXT,但 xrCreateSpatialDiscoverySnapshotAsyncEXT :: spatialContext 未使用 XrSpatialContextPersistenceConfigEXT 設定任何 XrSpatialPersistenceContextEXT,則執行階段必須從 xrCreateSpatialDiscoverySnapshotAsyncEXT 傳回 XR_ERROR_VALIDATION_FAILURE。

執行階段必須將 XrSpatialDiscoveryPersistenceUuidFilterEXT 篩選器視為「AND」條件,並與 XrSpatialDiscoverySnapshotCreateInfoEXT 或其下一個鏈結中提供的任何其他篩選器搭配使用。執行階段必須將 persistedUuids 陣列本身視為「OR」條件,也就是篩選出含有該陣列中任何 UUID 的實體。

執行階段必須在建立的快照中,為 persistedUuids 內每個 UUID 加入一個項目,以便判斷目前的 XrSpatialPersistenceStateEXT 狀態。

  • 如果執行階段成功在儲存空間中找到 UUID,則:

  • 如果執行階段判定 UUID 不存在於儲存空間 (無論 UUID 從未存在於儲存空間,或曾存在但已取消保留),則:

  • 如果執行階段無法判斷 UUID 是否存在於儲存空間中,則不得將其納入快照。

應用程式也可以在 XrSpatialComponentDataQueryConditionEXT 的下一個鏈結中使用 XrSpatialDiscoveryPersistenceUuidFilterEXT,查詢現有快照中特定 UUID 的實體。與 XrSpatialComponentDataQueryConditionEXT 搭配使用時,如果 XrSpatialDiscoveryPersistenceUuidFilterEXT :: persistedUuids 包含任何不在 XrSpatialSnapshotEXT 中的 XrUuid,執行階段不得在查詢結果中加入該 XrUuid 的項目。此外,查詢結果中的實體順序 (序列) 可能與 XrSpatialDiscoveryPersistenceUuidFilterEXT :: persistedUuids 中提供的 UUID 順序不符。應用程式應在 XrSpatialComponentDataQueryConditionEXT :: componentTypes 中加入 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,並在 XrSpatialComponentDataQueryResultEXT 的下一個鏈結中加入 XrSpatialComponentPersistenceListEXT,然後檢查每個查詢結果索引的 XrSpatialPersistenceDataEXT :: persistUuid,瞭解目前結果索引對應的 UUID。

有效用途 (隱含)

  • 必須先啟用 XR_EXT_spatial_persistence 擴充功能,才能使用 XrSpatialDiscoveryPersistenceUuidFilterEXT
  • type「必須」為 XR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXT
  • next「必須」為 NULL,或指向結構鏈中下一個結構的有效指標
  • persistedUuids「必須」是指向 persistedUuidCount XrUuid 結構陣列的指標
  • persistedUuidCount 參數必須大於 0
探索所有持續性實體

如果應用程式使用 xrCreateSpatialDiscoverySnapshotAsyncEXT,但不使用 XrSpatialDiscoveryPersistenceUuidFilterEXT,且使用已設定 XrSpatialPersistenceContextEXT 的 XrSpatialContextEXT,則執行階段必須在建立的快照中,納入保留在 XrSpatialPersistenceContextEXT 所代表儲存空間中的實體,且這些實體必須符合 XrSpatialDiscoverySnapshotCreateInfoEXT 中提供的篩選器。對於這些實體:

新物件類型

新指令

新結構

新列舉

新列舉常數

  • XR_EXT_SPATIAL_PERSISTENCE_EXTENSION_NAME
  • XR_EXT_spatial_persistence_SPEC_VERSION
  • 擴充 XrObjectType:

    • XR_OBJECT_TYPE_SPATIAL_PERSISTENCE_CONTEXT_EXT
  • 擴充 XrResult:

    • XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT
  • 擴充 XrSpatialComponentTypeEXT:

    • XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT
  • 擴充 XrStructureType:

    • XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXT
    • XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT
    • XR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT
    • XR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXT
    • XR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT

範例程式碼

建立持續性脈絡

// Check if the required persistence scope supported
uint32_t scopeCount;
CHK_XR(xrEnumerateSpatialPersistenceScopesEXT(instance, systemId, 0, &scopeCount, nullptr));
std::vector<XrSpatialPersistenceScopeEXT> persistenceScopes(scopeCount);
CHK_XR(xrEnumerateSpatialPersistenceScopesEXT(instance, systemId, scopeCount, &scopeCount, persistenceScopes.data()));

if (std::find(persistenceScopes.begin(), persistenceScopes.end(), XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT) == persistenceScopes.end()) {
  return;
}

XrSpatialPersistenceContextEXT persistenceContext{};

XrSpatialPersistenceContextCreateInfoEXT persistenceContextCreateInfo{XR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT};
persistenceContextCreateInfo.scope = XR_SPATIAL_PERSISTENCE_SCOPE_SYSTEM_MANAGED_EXT;
XrFutureEXT createContextFuture;
CHK_XR(xrCreateSpatialPersistenceContextAsyncEXT(session, &persistenceContextCreateInfo, &createContextFuture));

waitUntilReady(createContextFuture);

XrCreateSpatialPersistenceContextCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialPersistenceContextCompleteEXT(session, createContextFuture, &completion));
if (completion.futureResult != XR_SUCCESS || completion.createResult != XR_SPATIAL_PERSISTENCE_CONTEXT_RESULT_SUCCESS_EXT) {
  return;
}

persistenceContext = completion.persistenceContext;

// ...
// Connect persistence context to a spatial context and discover persisted entities.
// ...

CHK_XR(xrDestroySpatialPersistenceContextEXT(persistenceContext));

將 Persistence Context 連結至 Spatial Context

// Note: Anchor capability is just used as an example here. Persistence can be
// supported by other capabilities too. xrEnumerateSpatialCapabilityComponentTypesEXT() can
// be used to check if a certain capability supports persistence.
if (!isSpatialCapabilitySupported(instance, systemId, XR_SPATIAL_CAPABILITY_ANCHOR_EXT)) {
  return;
}

const bool supportsPersistenceComponent = isSpatialComponentSupported(instance, systemId, XR_SPATIAL_CAPABILITY_ANCHOR_EXT, XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT);

// Create a spatial spatial context
XrSpatialContextEXT spatialContext{};
{

  std::vector<XrSpatialComponentTypeEXT> enabledComponents = {
    XR_SPATIAL_COMPONENT_TYPE_ANCHOR_EXT,
  };

  if (supportsPersistenceComponent) {
    enabledComponents.push_back(XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_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();

  XrSpatialContextPersistenceConfigEXT persistenceConfig{XR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT};
  persistenceConfig.persistenceContextCount = 1;
  persistenceConfig.persistenceContexts = &persistenceContext;

  if (supportsPersistenceComponent) {
    spatialContextCreateInfo.next = &persistenceConfig;
  }

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

// ...
// Discover persisted anchors.
// ...

CHK_XR(xrDestroySpatialContextEXT(spatialContext));

探索所有持續性實體

XrFutureEXT future = XR_NULL_FUTURE_EXT;

// We want to look for entities that have the following components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
  XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,
};

auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
  XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT};
  snapshotCreateInfo.componentTypeCount = snapshotComponents.size();
  snapshotCreateInfo.componentTypes = snapshotComponents.data();
  CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));

  waitUntilReady(future);

  XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT};
  completionInfo.baseSpace = localSpace;
  completionInfo.time = time;
  completionInfo.future = future;

  XrCreateSpatialDiscoverySnapshotCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
  CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
  if (completion.futureResult == XR_SUCCESS) {

    // Query for the semantic label component data
    XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
    queryCond.componentTypeCount = snapshotComponents.size();
    queryCond.componentTypes = snapshotComponents.data();

    XrSpatialComponentDataQueryResultEXT queryResult{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT};
    CHK_XR(xrQuerySpatialComponentDataEXT(completion.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();

    std::vector<XrSpatialPersistenceDataEXT> persistenceData(queryResult.entityIdCountOutput);
    XrSpatialComponentPersistenceListEXT persistenceDataList{XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT};
    persistenceDataList.persistDataCount = persistenceData.size();
    persistenceDataList.persistData = persistenceData.data();
    queryResult.next = &persistenceDataList;

    CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));

    for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
      // persistenceData[i].persistUuid is the UUID of the persisted entity whose entity ID is entityIds[i].
      // The persistenceData array is essentially the uuids persisted in the scope that the current
      // XrSpatialPersistenceContextEXT is configured with.
    }

    CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
  }
};

while (1) {
  // ...
  // For every frame in frame loop
  // ...

  XrFrameState frameState;  // previously returned from xrWaitFrame
  const XrTime time = frameState.predictedDisplayTime;

  // Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
  XrEventDataBuffer event = {XR_TYPE_EVENT_DATA_BUFFER};
  XrResult result = xrPollEvent(instance, &event);
  if (result == XR_SUCCESS) {
      switch (event.type) {
          case XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT: {
              const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
                  *reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
              // Discover spatial entities for the context that we received the "discovery
              // recommended" event for.
              discoverSpatialEntities(eventdata.spatialContext, time);
              break;
          }
      }
  }

  // ...
  // Finish frame loop
  // ...
}

探索具有特定 UUID 的實體

XrFutureEXT future = XR_NULL_FUTURE_EXT;

// Load up the uuids that the app has stored on its own i.e. the uuids it is interested in.
std::vector<XrUuid> uuidsStoredByApp = loadPersistedUuids();

// We want to look for entities that have the following components.
std::vector<XrSpatialComponentTypeEXT> snapshotComponents = {
  XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT,
};

auto discoverSpatialEntities = [&](XrSpatialContextEXT spatialContext, XrTime time) {
  XrSpatialDiscoveryPersistenceUuidFilterEXT persistenceFilter{XR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXT};
  persistenceFilter.persistedUuidCount = uuidsStoredByApp.size();
  persistenceFilter.persistedUuids = uuidsStoredByApp.data();

  XrSpatialDiscoverySnapshotCreateInfoEXT snapshotCreateInfo{XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT};
  snapshotCreateInfo.componentTypeCount = snapshotComponents.size();
  snapshotCreateInfo.componentTypes = snapshotComponents.data();
  snapshotCreateInfo.next = &persistenceFilter;

  CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT(spatialContext, &snapshotCreateInfo, &future));

  waitUntilReady(future);

  XrCreateSpatialDiscoverySnapshotCompletionInfoEXT completionInfo{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT};
  completionInfo.baseSpace = localSpace;
  completionInfo.time = time;
  completionInfo.future = future;

  XrCreateSpatialDiscoverySnapshotCompletionEXT completion{XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
  CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(spatialContext, &completionInfo, &completion));
  if (completion.futureResult == XR_SUCCESS) {

    // Query for the semantic label component data
    XrSpatialComponentDataQueryConditionEXT queryCond{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT};
    queryCond.componentTypeCount = snapshotComponents.size();
    queryCond.componentTypes = snapshotComponents.data();

    XrSpatialComponentDataQueryResultEXT queryResult{XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT};
    CHK_XR(xrQuerySpatialComponentDataEXT(completion.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();

    std::vector<XrSpatialPersistenceDataEXT> persistenceData(queryResult.entityIdCountOutput);
    XrSpatialComponentPersistenceListEXT persistenceDataList{XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT};
    persistenceDataList.persistDataCount = persistenceData.size();
    persistenceDataList.persistData = persistenceData.data();
    queryResult.next = &persistenceDataList;

    CHK_XR(xrQuerySpatialComponentDataEXT(completion.snapshot, &queryCond, &queryResult));

    for (int32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
      if (persistenceData[i].persistState == XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT) {
        // persistenceData[i].persistUuid, requested by the app, is present in the persistence scope
        // and its corresponding entity ID and state are entityIds[i] & entityStates[i] respectively.
      } else if (persistenceData[i].persistState == XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT) {
        // persistenceData[i].persistUuid, requested by the app, is NOT present in the persistence scope
        // and its corresponding entity ID (entityIds[i]) would be XR_NULL_SPATIAL_ENTITY_ID_EXT
        // and tracking state (entityStates[i]) would be XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT.
      }
    }

    CHK_XR(xrDestroySpatialSnapshotEXT(completion.snapshot));
  }
};

while (1) {
  // ...
  // For every frame in frame loop
  // ...

  XrFrameState frameState;  // previously returned from xrWaitFrame
  const XrTime time = frameState.predictedDisplayTime;

  // Poll for the XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT event
  XrEventDataBuffer event = {XR_TYPE_EVENT_DATA_BUFFER};
  XrResult result = xrPollEvent(instance, &event);
  if (result == XR_SUCCESS) {
      switch (event.type) {
          case XR_TYPE_EVENT_DATA_SPATIAL_DISCOVERY_RECOMMENDED_EXT: {
              const XrEventDataSpatialDiscoveryRecommendedEXT& eventdata =
                  *reinterpret_cast<XrEventDataSpatialDiscoveryRecommendedEXT*>(&event);
              // Discover spatial entities for the context that we received the "discovery
              // recommended" event for.
              discoverSpatialEntities(eventdata.spatialContext, time);
              break;
          }
      }
  }

  // ...
  // Finish frame loop
  // ...
}

問題

版本記錄

  • 修訂版本 1,2024-08-29 (Nihav Jain,Google)

    • 初始擴充功能說明