XR_EXT_spatial_persistence

名称字符串

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 中配置持久化上下文的范围。

如果 XrSpatialPersistenceContextCreateInfoEXT :: scope 未由 xrEnumerateSpatialPersistenceScopesEXT 枚举,则运行时必须返回 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 的生命周期内,或在应用将 xrDestroySpatialPersistenceContextEXT 与 persistenceContext 搭配使用之前(以先发生者为准),它必须保持有效。

仅当 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 句柄。

如果存在任何有效的 XrSpatialContextEXT 句柄,且 persistenceContext 已通过 XrSpatialContextPersistenceConfigEXT 与这些句柄关联,则在调用 xrDestroySpatialPersistenceContextEXT 时,运行时不得销毁 persistenceContext 的底层资源。这是因为空间上下文仍在使用持久性上下文的资源来发现持久性实体。在这种情况下,销毁持久性上下文句柄只会移除应用对这些资源的访问权限。

当与持久化上下文关联的所有 XrSpatialContextEXT 句柄都被销毁时,被销毁的 XrSpatialPersistenceContextEXT 的资源必须被释放。

有效用法(隐式)

线程安全

  • 对 persistenceContext 及其任何子句柄的访问都必须在外部进行同步

返回代码

成功

  • XR_SUCCESS

失败

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_RUNTIME_FAILURE

发现持久化实体

持久化组件

持久化空间实体具有持久化组件,如果 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT 在创建 XrSpatialContextEXT 期间启用,并包含在 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 中此时能够确定 XrSpatialPersistenceStateEXT 状态的每个 UUID,运行时必须在创建的快照中包含一个条目。

  • 如果运行时在其存储空间中成功找到 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));

将持久性上下文连接到空间上下文

// 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 年 8 月 29 日(Nihav Jain,Google)

    • 初始扩展程序说明