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);
参数说明
session是一个 XrSession,空间持久性上下文将在其中处于活跃状态。createInfo是用于指定空间持久性上下文参数的 XrSpatialPersistenceContextCreateInfoEXT。future是一个指向XrFutureEXT的指针。
应用可以使用 xrCreateSpatialPersistenceContextAsyncEXT 函数创建 XrSpatialPersistenceContextEXT 句柄,并在 createInfo 中配置持久化上下文的范围。
如果 XrSpatialPersistenceContextCreateInfoEXT :: scope 未由 xrEnumerateSpatialPersistenceScopesEXT 枚举,则运行时必须返回 XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT。
如果运行时强制执行权限系统来控制应用对 XrSpatialPersistenceContextEXT 表示的持久性存储空间的访问,那么当这些权限尚未授予此应用时,运行时必须返回 XR_ERROR_PERMISSION_INSUFFICIENT。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能调用 xrCreateSpatialPersistenceContextAsyncEXT -
session必须是有效的 XrSession 句柄 -
createInfo必须是指向有效 XrSpatialPersistenceContextCreateInfoEXT 结构的指针 -
future必须是指向XrFutureEXT值的指针
返回代码
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXTXR_ERROR_VALIDATION_FAILURE
XrSpatialPersistenceContextCreateInfoEXT 结构的定义如下:
typedef struct XrSpatialPersistenceContextCreateInfoEXT {
XrStructureType type;
const void* next;
XrSpatialPersistenceScopeEXT scope;
} XrSpatialPersistenceContextCreateInfoEXT;
成员说明
type是此结构的 XrStructureType。next是NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展程序中未定义任何此类结构。scope是一个 XrSpatialPersistenceScopeEXT,用于定义持久化上下文的存储范围。
XrSpatialPersistenceContextCreateInfoEXT 结构描述了用于创建 XrSpatialPersistenceContextEXT 句柄的信息。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能使用 XrSpatialPersistenceContextCreateInfoEXT -
type必须为XR_TYPE_SPATIAL_PERSISTENCE_CONTEXT_CREATE_INFO_EXT -
next必须为NULL或指向结构链中下一个结构的有效指针 -
scope必须是有效的 XrSpatialPersistenceScopeEXT 值
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必须是指向persistenceScopeCapacityInputXrSpatialPersistenceScopeEXT 值数组的指针
返回代码
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_RUNTIME_FAILUREXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_SYSTEM_INVALIDXR_ERROR_VALIDATION_FAILURE
xrCreateSpatialPersistenceContextCompleteEXT 函数定义如下:
XrResult xrCreateSpatialPersistenceContextCompleteEXT(
XrSession session,
XrFutureEXT future,
XrCreateSpatialPersistenceContextCompletionEXT* completion);
参数说明
session是之前传递给 xrCreateSpatialPersistenceContextAsyncEXT ::session的 XrSession。future是从 xrCreateSpatialPersistenceContextAsyncEXT 接收的XrFutureEXT。completion是一个指向 XrCreateSpatialPersistenceContextCompletionEXT 的指针。
xrCreateSpatialPersistenceContextCompleteEXT 会完成由 xrCreateSpatialPersistenceContextAsyncEXT 启动的异步操作。如果 future 未处于就绪状态,则运行时必须返回 XR_ERROR_FUTURE_PENDING_EXT。如果 future 已完成或已取消,则运行时必须返回 XR_ERROR_FUTURE_INVALID_EXT。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能调用 xrCreateSpatialPersistenceContextCompleteEXT -
session必须是有效的 XrSession 句柄 -
completion必须是指向 XrCreateSpatialPersistenceContextCompletionEXT 结构的指针
返回代码
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_FUTURE_INVALID_EXTXR_ERROR_FUTURE_PENDING_EXTXR_ERROR_HANDLE_INVALIDXR_ERROR_INSTANCE_LOSTXR_ERROR_LIMIT_REACHEDXR_ERROR_OUT_OF_MEMORYXR_ERROR_RUNTIME_FAILUREXR_ERROR_SESSION_LOSTXR_ERROR_VALIDATION_FAILURE
XrCreateSpatialPersistenceContextCompletionEXT 结构定义如下:
typedef struct XrCreateSpatialPersistenceContextCompletionEXT {
XrStructureType type;
void* next;
XrResult futureResult;
XrSpatialPersistenceContextResultEXT createResult;
XrSpatialPersistenceContextEXT persistenceContext;
} XrCreateSpatialPersistenceContextCompletionEXT;
成员说明
type是此结构的 XrStructureType。next是NULL或指向结构链中下一个结构的指针。futureResult是空间持久性上下文创建操作的 XrResult。createResult是空间持久性上下文创建操作的 XrSpatialPersistenceContextResultEXT。persistenceContext是一个 XrSpatialPersistenceContextEXT,使用 xrCreateSpatialPersistenceContextAsyncEXT ::createInfo中的数据和配置创建。
未来返回代码
futureResult 个值:
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_RUNTIME_FAILUREXR_ERROR_INSTANCE_LOSTXR_ERROR_SESSION_LOSTXR_ERROR_OUT_OF_MEMORYXR_ERROR_LIMIT_REACHEDXR_ERROR_PERMISSION_INSUFFICIENT
如果 futureResult 和 createResult 都是成功代码,则 persistenceContext 必须有效。如果 persistenceContext 有效,则在 xrCreateSpatialPersistenceContextAsyncEXT :: session 的生命周期内,或在应用将 xrDestroySpatialPersistenceContextEXT 与 persistenceContext 搭配使用之前(以先发生者为准),它必须保持有效。
仅当 futureResult 是成功代码时,运行时才必须设置 createResult。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能使用 XrCreateSpatialPersistenceContextCompletionEXT -
type必须为XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXT -
next必须为NULL或指向结构链中下一个结构的有效指针 -
futureResult必须是有效的 XrResult 值 -
createResult必须是有效的 XrSpatialPersistenceContextResultEXT 值 -
persistenceContext必须是有效的 XrSpatialPersistenceContextEXT 句柄
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);
参数说明
persistenceContext是一个先前由 xrCreateSpatialPersistenceContextAsyncEXT 创建的 XrSpatialPersistenceContextEXT。
应用在完成空间持久性任务后,可以使用 xrDestroySpatialPersistenceContextEXT 释放 persistenceContext 句柄。
如果存在任何有效的 XrSpatialContextEXT 句柄,且 persistenceContext 已通过 XrSpatialContextPersistenceConfigEXT 与这些句柄关联,则在调用 xrDestroySpatialPersistenceContextEXT 时,运行时不得销毁 persistenceContext 的底层资源。这是因为空间上下文仍在使用持久性上下文的资源来发现持久性实体。在这种情况下,销毁持久性上下文句柄只会移除应用对这些资源的访问权限。
当与持久化上下文关联的所有 XrSpatialContextEXT 句柄都被销毁时,被销毁的 XrSpatialPersistenceContextEXT 的资源必须被释放。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能调用 xrDestroySpatialPersistenceContextEXT -
persistenceContext必须是有效的 XrSpatialPersistenceContextEXT 句柄
线程安全
- 对
persistenceContext及其任何子句柄的访问都必须在外部进行同步
返回代码
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALIDXR_ERROR_RUNTIME_FAILURE
发现持久化实体
持久化组件
持久化空间实体具有持久化组件,如果 XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT 在创建 XrSpatialContextEXT 期间启用,并包含在 XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes 或 XrSpatialUpdateSnapshotCreateInfoEXT :: componentTypes 中,则运行时必须将该组件包含在发现和更新快照中。
组件数据
XrSpatialPersistenceDataEXT 结构的定义如下:
typedef struct XrSpatialPersistenceDataEXT {
XrUuid persistUuid;
XrSpatialPersistenceStateEXT persistState;
} XrSpatialPersistenceDataEXT;
成员说明
persistUuid是 XrUuid。persistState是一个 XrSpatialPersistenceStateEXT,表示persistUuid的持久性状态
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能使用 XrSpatialPersistenceDataEXT -
persistState必须是有效的 XrSpatialPersistenceStateEXT 值
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_EXT_spatial_persistence扩展程序,然后才能使用 XrSpatialComponentPersistenceListEXT -
type必须为XR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXT -
next必须为NULL或指向结构链中下一个结构的有效指针 -
persistData必须是指向persistDataCountXrSpatialPersistenceDataEXT 结构数组的指针 -
persistDataCount参数必须大于0
配置
如果 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 句柄表示的存储空间中保留的空间实体。
有效用法(隐式)
- 必须先启用
XR_EXT_spatial_persistence扩展程序,然后才能使用 XrSpatialContextPersistenceConfigEXT -
type必须为XR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXT -
next必须为NULL或指向结构链中下一个结构的有效指针 -
persistenceContexts必须是指向包含persistenceContextCount个有效 XrSpatialPersistenceContextEXT 句柄的数组的指针 -
persistenceContextCount参数必须大于0
创建发现快照
发现具有特定 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,则:
- 运行时必须将此实体的 XrSpatialPersistenceDataEXT 中的 XrSpatialPersistenceStateEXT 设置为
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT。 - 运行时必须在创建的快照中为此实体添加有效的
XrSpatialEntityIdEXT。 - 如果运行时正在主动跟踪该实体,并且其组件具有有效数据,则必须将该实体的 XrSpatialEntityTrackingStateEXT 设置为
XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT。否则,运行时必须将 XrSpatialEntityTrackingStateEXT 设置为XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT。
- 运行时必须将此实体的 XrSpatialPersistenceDataEXT 中的 XrSpatialPersistenceStateEXT 设置为
如果运行时确定其存储空间中不存在该 UUID(无论该 UUID 是从未存在于存储空间中,还是曾经存在但后来被取消持久化),则:
- 运行时必须将此实体的 XrSpatialPersistenceDataEXT 中的 XrSpatialPersistenceStateEXT 设置为
XR_SPATIAL_PERSISTENCE_STATE_NOT_FOUND_EXT,以向应用表明此 UUID 已不再存在于存储空间中。 - 运行时必须在创建的快照中将此实体的
XrSpatialEntityIdEXT设置为 XR_NULL_SPATIAL_ENTITY_ID_EXT。 - 运行时必须将该实体的 XrSpatialEntityTrackingStateEXT 设置为
XR_SPATIAL_ENTITY_TRACKING_STATE_STOPPED_EXT,以向应用表明该实体永远不会被跟踪。
- 运行时必须将此实体的 XrSpatialPersistenceDataEXT 中的 XrSpatialPersistenceStateEXT 设置为
如果运行时无法确定 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必须是指向persistedUuidCountXrUuid 结构数组的指针 -
persistedUuidCount参数必须大于0
发现所有持久化实体
如果应用使用 xrCreateSpatialDiscoverySnapshotAsyncEXT,不使用 XrSpatialDiscoveryPersistenceUuidFilterEXT,但使用已配置 XrSpatialPersistenceContextEXT 的 XrSpatialContextEXT,则运行时必须在创建的快照中包含以下实体:这些实体持久保存在由 XrSpatialPersistenceContextEXT 表示的存储空间中,并且满足 XrSpatialDiscoverySnapshotCreateInfoEXT 中提供的过滤条件。对于这些实体,
- 运行时必须将此实体的 XrSpatialPersistenceDataEXT 中的 XrSpatialPersistenceStateEXT 设置为
XR_SPATIAL_PERSISTENCE_STATE_LOADED_EXT。 - 运行时必须在创建的快照中为此实体添加有效的
XrSpatialEntityIdEXT。 - 如果运行时正在主动跟踪该实体,并且其组件具有有效数据,则必须将该实体的 XrSpatialEntityTrackingStateEXT 设置为
XR_SPATIAL_ENTITY_TRACKING_STATE_TRACKING_EXT。否则,运行时必须将 XrSpatialEntityTrackingStateEXT 设置为XR_SPATIAL_ENTITY_TRACKING_STATE_PAUSED_EXT。
新对象类型
新增命令
- xrCreateSpatialPersistenceContextAsyncEXT
- xrCreateSpatialPersistenceContextCompleteEXT
- xrDestroySpatialPersistenceContextEXT
- xrEnumerateSpatialPersistenceScopesEXT
新结构
- XrCreateSpatialPersistenceContextCompletionEXT
- XrSpatialPersistenceContextCreateInfoEXT
- XrSpatialPersistenceDataEXT
扩展 XrSpatialDiscoverySnapshotCreateInfoEXT、XrSpatialComponentDataQueryConditionEXT:
新枚举
新枚举常量
XR_EXT_SPATIAL_PERSISTENCE_EXTENSION_NAMEXR_EXT_spatial_persistence_SPEC_VERSION扩展 XrObjectType:
XR_OBJECT_TYPE_SPATIAL_PERSISTENCE_CONTEXT_EXT
扩展 XrResult:
XR_ERROR_SPATIAL_PERSISTENCE_SCOPE_UNSUPPORTED_EXT
-
XR_SPATIAL_COMPONENT_TYPE_PERSISTENCE_EXT
扩展 XrStructureType:
XR_TYPE_CREATE_SPATIAL_PERSISTENCE_CONTEXT_COMPLETION_EXTXR_TYPE_SPATIAL_COMPONENT_PERSISTENCE_LIST_EXTXR_TYPE_SPATIAL_CONTEXT_PERSISTENCE_CONFIG_EXTXR_TYPE_SPATIAL_DISCOVERY_PERSISTENCE_UUID_FILTER_EXTXR_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)
- 初始扩展程序说明