XR_ANDROID_spatial_component_subsumed_by
名称字符串
XR_ANDROID_spatial_component_subsumed_by
扩展程序类型
实例扩展程序
已注册的扩展程序编号
792
修订版本
1
批准状态
未批准
扩展程序和版本依赖项
XR_EXT_spatial_entity
和
XR_EXT_spatial_plane_tracking
上次修改日期
2025-08-19
IP 状态
没有已知的 IP 权利主张。
创作贡献者
Brian Chen,Google
Kyle Chen,Google
Levana Chen,Google
Nihav Jain,Google
Spencer Quin,Google
概览
此扩展程序以 XR_EXT_spatial_entity 为基础,并为 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 提供了一个新组件,以公开 subsumed_by 属性。
当运行时获取足够的环境信息来检测 2 个被跟踪的平面实际上是同一个平面时,系统会将包含其中一个平面的 ID 的 subsumed_by 组件附加到另一个平面。
此扩展程序还引入了一个新过滤器,应用可以 将其链接到 XrSpatialDiscoverySnapshotCreateInfoEXT,以过滤掉附加了 subsumed_by 组件的所有实体。
权限
Android 应用必须 在其清单中列出 android.permission.SCENE_UNDERSTANDING_COARSE 权限,因为此扩展程序会跟踪环境中的平面。android.permission.SCENE_UNDERSTANDING_COARSE 权限被视为危险权限。
(保护级别:危险)
运行时支持
如果运行时支持 subsumed_by,则必须 支持平面跟踪功能,并通过在 xrEnumerateSpatialCapabilitiesEXT 中枚举 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 来指明这一点。
如果运行时提供 subsumed_by,则必须 通过在 xrEnumerateSpatialCapabilityComponentTypesEXT 中将 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 枚举为 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 功能的受支持组件来指明这一点。
附加实体的 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 的所有组件数据必须 与 subsume 它的实体相同。
Subsumed By 组件
组件数据
XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 使用 XrSpatialEntityIdEXT 结构作为其数据,该结构表示 subsuming 实体的 ID。
用于查询数据的组件列表结构体
XrSpatialComponentSubsumedByListANDROID 结构的定义如下:
typedef struct XrSpatialComponentSubsumedByListANDROID {
XrStructureType type;
void* next;
uint32_t subsumedUniqueIdCount;
XrSpatialEntityIdEXT* subsumedUniqueIds;
} XrSpatialComponentSubsumedByListANDROID;
成员说明
type是此结构的 XrStructureType。next是NULL或指向结构链中下一个结构的指针。subsumedUniqueIdCount是一个uint32_t,用于描述subsumedUniqueIds数组中的元素数量。subsumedUniqueIds是XrSpatialEntityIdEXT的数组。
应用可以 通过将 XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID 添加到 XrSpatialComponentDataQueryResultEXT 的下一个链中,查询 XrSpatialSnapshotEXT 中空间实体的 subsumed_by 组件。
如果 XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID 位于 XrSpatialComponentDataQueryResultEXT :: next 的下一个链中,但 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 未包含在 XrSpatialComponentDataQueryConditionEXT :: componentTypes 中,则运行时 必须 从 xrQuerySpatialComponentDataEXT 返回 XR_ERROR_VALIDATION_FAILURE。
如果 subsumedUniqueIdCount 小于 XrSpatialComponentDataQueryResultEXT :: entityIdCountOutput,则运行时 必须 从 xrQuerySpatialComponentDataEXT 返回 XR_ERROR_SIZE_INSUFFICIENT。
有效用法(隐式)
- 必须先启用
XR_ANDROID_spatial_component_subsumed_by扩展程序,然后才能使用 XrSpatialComponentSubsumedByListANDROID -
type必须 为XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID -
next必须 为NULL或指向结构链中下一个结构的有效指针 -
subsumedUniqueIds必须 是指向subsumedUniqueIdCountXrSpatialEntityIdEXT值数组的指针 -
subsumedUniqueIdCount参数 必须 大于0
配置
如果为 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 功能在 XrSpatialCapabilityComponentTypesEXT :: componentTypes 中枚举了 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID,则应用可以 通过在支持此组件的功能的 XrSpatialCapabilityConfigurationBaseHeaderEXT 派生结构的 XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents 列表中添加枚举来启用它。
过滤 subsumed 实体
XrSpatialDiscoveryUniqueEntitiesFilterANDROID 结构的定义如下:
typedef struct XrSpatialDiscoveryUniqueEntitiesFilterANDROID {
XrStructureType type;
const void* next;
} XrSpatialDiscoveryUniqueEntitiesFilterANDROID;
成员说明
type是此结构的 XrStructureType。next是NULL或指向结构链中下一个结构的指针。
应用可以 在 XrSpatialDiscoverySnapshotCreateInfoEXT 的下一个链中添加 XrSpatialDiscoveryUniqueEntitiesFilterANDROID,以获取包含未被其他实体 subsumed 的实体的快照。
如果应用将 XrSpatialDiscoveryUniqueEntitiesFilterANDROID 链接到 XrSpatialDiscoverySnapshotCreateInfoEXT,同时在 XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes 中添加 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 组件,则运行时 必须 返回 XR_ERROR_VALIDATION_FAILURE。
如果应用将 XrSpatialDiscoveryUniqueEntitiesFilterANDROID 链接到 XrSpatialDiscoverySnapshotCreateInfoEXT,但未在 XrSpatialDiscoverySnapshotCreateInfoEXT :: componentTypes 中列出任何组件,则运行时必须在快照中添加所有空间实体,这些实体具有为 spatialContext 配置的功能的 XrSpatialCapabilityConfigurationBaseHeaderEXT :: enabledComponents 中枚举的组件集,但具有 XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID 组件的实体除外。
有效用法(隐式)
- 必须先启用
XR_ANDROID_spatial_component_subsumed_by扩展程序,然后才能使用 XrSpatialDiscoveryUniqueEntitiesFilterANDROID -
type必须 为XR_TYPE_SPATIAL_DISCOVERY_UNIQUE_ENTITIES_FILTER_ANDROID -
next必须 为NULL或指向结构链中下一个结构的有效指针
示例代码
配置平面跟踪功能
以下示例代码演示了如何创建具有 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 功能的空间上下文,该功能支持 subsumed_by。
// Check runtime supported capabilities
uint32_t capabilityCount;
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, 0, &capabilityCount, nullptr));
std::vector<XrSpatialCapabilityEXT> capabilities(capabilityCount);
CHK_XR(xrEnumerateSpatialCapabilitiesEXT(instance, systemId, capabilityCount, &capabilityCount, capabilities.data()));
if (std::find(capabilities.begin(), capabilities.end(), XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT) == capabilities.end()) {
return;
}
std::vector<XrSpatialComponentTypeEXT> planeTrackingComponents {
XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
XR_SPATIAL_COMPONENT_TYPE_PLANE_ALIGNMENT_EXT,
XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID,
};
// Create capability config for plane tracking
XrSpatialCapabilityConfigurationPlaneTrackingEXT planeTrackingConfig {
.type = XR_TYPE_SPATIAL_CAPABILITY_CONFIGURATION_PLANE_TRACKING_EXT,
.next = nullptr,
.capability = XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT,
.enabledComponentCount = (uint32_t)planeTrackingComponents.size(),
.enabledComponents = planeTrackingComponents.data(),
};
// Create spatial context
std::vector<const XrSpatialCapabilityConfigurationBaseHeaderEXT*> capabilityConfigs;
capabilityConfigs.push_back(reinterpret_cast<const XrSpatialCapabilityConfigurationBaseHeaderEXT*>(&planeTrackingConfig));
XrSpatialContextCreateInfoEXT contextCreateInfo{
.type = XR_TYPE_SPATIAL_CONTEXT_CREATE_INFO_EXT,
.next = nullptr,
.capabilityConfigCount = (uint32_t)capabilityConfigs.size(),
.capabilityConfigs = capabilityConfigs.data(),
};
CHK_XR(xrCreateSpatialContextAsyncEXT(session, &contextCreateInfo, &future))
// Completes creating spatial context
XrCreateSpatialContextCompletionEXT contextCompletion{
XR_TYPE_CREATE_SPATIAL_CONTEXT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialContextCompleteEXT(session, future, &contextCompletion))
查询组件数据
以下示例代码演示了如何从使用 XR_SPATIAL_CAPABILITY_PLANE_TRACKING_EXT 配置的上下文中查询 subsumed_by 组件数据。
// Create Discovery Snapshot
XrSpatialDiscoverySnapshotCreateInfoEXT discoverySnapshotCreateInfo {
.type = XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT,
};
CHK_XR(xrCreateSpatialDiscoverySnapshotAsyncEXT (
spatialContext, &discoverySnapshotCreateInfo, &future));
// Poll the state till snapshot it's ready.
waitUntilReady(future);
// Complete async operation.
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT
createSnapshotCompletionInfo {
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT,
.baseSpace = space,
.time = updateTime,
.future = future,
};
XrCreateSpatialDiscoverySnapshotCompletionEXT completion {
XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(
spatialContext, &createSnapshotCompletionInfo,
&completion));
if(completion.futureResult != XR_SUCCESS) return;
// Query subsumed_by components
std::array<XrSpatialComponentTypeEXT, 1> enabledComponents = {
XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID
};
XrSpatialComponentDataQueryConditionEXT queryCond {
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = 1,
.componentTypes = enabledComponents.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult {
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};
CHK_XR(xrQuerySpatialComponentDataEXT(
completion.snapshot, &queryCond, &queryResult));
// Query again with allocated memory
std::vector<XrSpatialEntityIdEXT> subsumedUniqueIds;
subsumedUniqueIds.resize(queryResult.entityIdCountOutput);
XrSpatialComponentSubsumedByListANDROID subsumedByList {
.type = XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROID,
.subsumedUniqueIdCount = static_cast<uint32_t>(subsumedUniqueIds.size()),
.subsumedUniqueIds = subsumedUniqueIds.data(),
};
queryResult.next = &subsumedByList;
CHK_XR(xrQuerySpatialComponentDataEXT(
completion.snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityEXT> subsumedEntities;
for(uint32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
// access planes[i] for merged plane id
XrSpatialEntityIdEXT entityId = queryResult.entityIds[i];
XrSpatialEntityIdEXT subsumedUniqueId = subsumedUniqueIds[i];
// create handle via entityId
XrSpatialEntityFromIdCreateInfoEXT entityCreateInfo {
.type = XR_TYPE_SPATIAL_ENTITY_FROM_ID_CREATE_INFO_EXT,
.entityId = entityId,
};
XrSpatialEntityEXT entity = XR_NULL_HANDLE;
xrCreateSpatialEntityFromIdEXT(spatialContext, &entityCreateInfo, &entity);
subsumedEntities.push_back(entity);
}
// Cleanup
xrDestroySpatialSnapshotEXT(completion.snapshot);
过滤掉 subsumed 实体
以下示例代码演示了如何使用过滤器从发现快照中过滤掉附加了 subsumed_by 组件的实体,以及如何查询 subsuming 实体的实体 ID。
// Init filter
XrSpatialDiscoveryUniqueEntitiesFilterANDROID filter {
.type = XR_TYPE_SPATIAL_DISCOVERY_UNIQUE_ENTITIES_FILTER_ANDROID,
};
// Chain filter to the snapshot create info
// WARNING: Chain the filter while include subsumed_by component in the
// componentTypes is invalid
XrSpatialDiscoverySnapshotCreateInfoEXT discoverySnapshotCreateInfo {
.type = XR_TYPE_SPATIAL_DISCOVERY_SNAPSHOT_CREATE_INFO_EXT,
.next = &filter
};
waitUntilReady(future);
// Complete async operation.
XrCreateSpatialDiscoverySnapshotCompletionInfoEXT
createSnapshotCompletionInfo {
.type = XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_INFO_EXT,
.baseSpace = space,
.time = updateTime,
.future = future,
};
XrCreateSpatialDiscoverySnapshotCompletionEXT completion {
XR_TYPE_CREATE_SPATIAL_DISCOVERY_SNAPSHOT_COMPLETION_EXT};
CHK_XR(xrCreateSpatialDiscoverySnapshotCompleteEXT(
spatialContext, &createSnapshotCompletionInfo,
&completion));
if(completion.futureResult != XR_SUCCESS) return;
// Subsumed entities has already been filtered out in this snapshot,now query
// Bounded2D to render subsuming planes
std::vector<XrSpatialComponentTypeEXT> queryComponents {
XR_SPATIAL_COMPONENT_TYPE_BOUNDED_2D_EXT,
};
XrSpatialComponentDataQueryConditionEXT queryCond {
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_CONDITION_EXT,
.componentTypeCount = 1,
.componentTypes = queryComponents.data(),
};
XrSpatialComponentDataQueryResultEXT queryResult {
.type = XR_TYPE_SPATIAL_COMPONENT_DATA_QUERY_RESULT_EXT,
};
CHK_XR(xrQuerySpatialComponentDataEXT(
completion.snapshot, &queryCond, &queryResult));
// Chain Bounded2D list
std::vector<XrSpatialBounded2DDataEXT> bounded2dData;
bounded2dData.resize(queryResult.entityIdCountOutput);
XrSpatialComponentBounded2DListEXT bounded2dList {
.type = XR_TYPE_SPATIAL_COMPONENT_BOUNDED_2D_LIST_EXT,
.boundCount = static_cast<uint32_t>(bounded2dData.size()),
.bounds = bounded2dData.data(),
};
// Query again
queryResult.next = &bounded2dList;
CHK_XR(xrQuerySpatialComponentDataEXT(
completion.snapshot, &queryCond, &queryResult));
std::vector<XrSpatialEntityEXT> subsumingPlanes;
for(uint32_t i = 0; i < queryResult.entityIdCountOutput; ++i) {
// access planes[i] for merged plane id
XrSpatialEntityIdEXT entityId = queryResult.entityIds[i];
// create handle via entityId.
XrSpatialEntityFromIdCreateInfoEXT entityCreateInfo {
.type = XR_TYPE_SPATIAL_ENTITY_FROM_ID_CREATE_INFO_EXT,
.entityId = entityId,
};
XrSpatialEntityEXT entity = XR_NULL_HANDLE;
xrCreateSpatialEntityFromIdEXT(spatialContext, &entityCreateInfo, &entity);
subsumingPlanes.push_back(entity);
}
// Cleanup
xrDestroySpatialSnapshotEXT(completion.snapshot);
新结构
新枚举常量
XR_ANDROID_SPATIAL_COMPONENT_SUBSUMED_BY_EXTENSION_NAMEXR_ANDROID_spatial_component_subsumed_by_SPEC_VERSION-
XR_SPATIAL_COMPONENT_TYPE_SUBSUMED_BY_ANDROID
扩展 XrStructureType:
XR_TYPE_SPATIAL_COMPONENT_SUBSUMED_BY_LIST_ANDROIDXR_TYPE_SPATIAL_DISCOVERY_UNIQUE_ENTITIES_FILTER_ANDROID
问题
版本记录
修订版 1,2025-11-19(Brian Chen)
- 初始扩展程序说明。