名称字符串
XR_ANDROID_hand_mesh
扩展类型
实例扩展
注册扩展号
704
修订版本
1
扩展和版本依赖项
最后修改日期
2024-09-10
知识产权状态
无已知知识产权声明。
贡献者
Nihav Jain, Google
Cairn Overturf, Google
Spencer Quin, Google
Levana Chen, Google
概览
此扩展支持以动态手部网格形式表示的手部追踪。
此扩展旨在为用户手部的个性化表示网格提供顶点和索引缓冲区。它可以用于遮挡和可视化。
此扩展不应用于其他手部追踪目的。
- 对于交互,可以使用
XR_EXT_hand_interaction。 - 对于骨骼关节,可以使用
XR_EXT_hand_tracking。
手部追踪数据可能是敏感的个人信息,与个人隐私和完整性密切相关。强烈建议存储或传输手部追踪数据的应用始终主动征得用户的明确同意。
检查系统功能
应用可以在调用 xrGetSystemProperties 时,通过将 XrSystemHandMeshTrackingPropertiesANDROID 结构链接到 XrSystemProperties 来检查系统是否支持手部网格追踪。
typedef struct XrSystemHandMeshTrackingPropertiesANDROID {
XrStructureType type;
void* next;
XrBool32 supportsHandMeshTracking;
XrBool32 supportsTextureUV;
XrBool32 supportsVertexNormal;
} XrSystemHandMeshTrackingPropertiesANDROID;
成员说明
type是此结构的 XrStructureType。next为NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。supportsHandMeshTracking是一个XrBool32,指示所选的XrSystemId是否支持手部网格追踪。supportsTextureUV是一个XrBool32,指示所选的XrSystemId是否支持网格顶点的纹理 UV。supportsVertexNormal是一个XrBool32,指示所选的XrSystemId是否支持网格顶点的顶点法线。
当 supportsHandMeshTracking 为 XR_FALSE 时,应用应避免使用手部网格功能,因为这意味着系统不支持手部网格追踪。在这种情况下,xrCreateHandMeshTrackerANDROID 将返回 XR_ERROR_FEATURE_UNSUPPORTED。
如果 supportsHandMeshTracking 返回 XR_TRUE,则系统支持手部网格追踪。应用应使用 XrHandMeshANDROID::indexCount 和 XrHandMeshANDROID::vertexCount 来访问手部网格缓冲区,并在每次调用 xrGetHandMeshANDROID 时在渲染循环中重用它们。
如果 supportsTextureUV 返回 XR_FALSE,则系统不支持网格顶点的纹理 UV,因此在调用 xrGetHandMeshANDROID 时,应用将收到 XrHandMeshANDROID::textureUVs 为 NULL。
如果 supportsVertexNormal 返回 XR_FALSE,则系统不支持网格顶点的顶点法线,因此在调用 xrGetHandMeshANDROID 时,应用将收到 XrHandMeshANDROID::normals 为 NULL。
有效用法(隐式)
- 在使用 XrSystemHandMeshTrackingPropertiesANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 type必须是XR_TYPE_SYSTEM_HAND_MESH_TRACKING_PROPERTIES_ANDROIDnext必须为NULL或指向结构链中下一个结构的有效指针
创建手部网格追踪器句柄
XR_DEFINE_HANDLE(XrHandMeshTrackerANDROID)
XrHandMeshTrackerANDROID 句柄表示用于手部网格追踪和管理相关资源的手部网格追踪器。
此句柄可以用于使用此扩展中的其他函数访问手部网格缓冲区。
应用可以使用 xrCreateHandMeshTrackerANDROID 函数创建 XrHandMeshTrackerANDROID 句柄。
XrResult xrCreateHandMeshTrackerANDROID(
XrSession session,
const XrHandMeshTrackerCreateInfoANDROID* createInfo,
XrHandMeshTrackerANDROID* handMeshTracker);
参数说明
session是手部网格追踪器将处于活动状态的 XrSession。createInfo是用于指定手部网格追踪器的 XrHandMeshTrackerCreateInfoANDROID。handMeshTracker是返回的 XrHandMeshTrackerANDROID 句柄。
如果系统不支持手部网格追踪,xrCreateHandMeshTrackerANDROID 将返回 XR_ERROR_FEATURE_UNSUPPORTED。
XrHandMeshTrackerANDROID 句柄拥有手部网格追踪的所有资源。在完成手部网格追踪体验后,应用必须使用 xrDestroyHandMeshTrackerANDROID 函数销毁该句柄。
有效用法(隐式)
- 在调用 xrCreateHandMeshTrackerANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 session必须是有效的 XrSession 句柄createInfo必须是指向有效的 XrHandMeshTrackerCreateInfoANDROID 结构的指针handMeshTracker必须是指向 XrHandMeshTrackerANDROID 句柄的指针
返回代码
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FEATURE_UNSUPPORTEDXR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_RUNTIME_FAILUREXR_ERROR_INSTANCE_LOSTXR_ERROR_SESSION_LOSTXR_ERROR_OUT_OF_MEMORYXR_ERROR_HANDLE_INVALIDXR_ERROR_LIMIT_REACHED
XrHandMeshTrackerCreateInfoANDROID 结构描述了创建 XrHandMeshTrackerANDROID 句柄所需的信息。
typedef struct XrHandMeshTrackerCreateInfoANDROID {
XrStructureType type;
const void* next;
} XrHandMeshTrackerCreateInfoANDROID;
成员说明
type是此结构的 XrStructureType。next为NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。
有效用法(隐式)
- 在使用 XrHandMeshTrackerCreateInfoANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 type必须是XR_TYPE_HAND_MESH_TRACKER_CREATE_INFO_ANDROIDnext必须为NULL或指向结构链中下一个结构的有效指针
xrDestroyHandMeshTrackerANDROID 函数在完成手部网格追踪体验后,释放 handMeshTracker 和底层资源。
XrResult xrDestroyHandMeshTrackerANDROID(
XrHandMeshTrackerANDROID handMeshTracker);
参数说明
handMeshTracker是先前由 xrCreateHandMeshTrackerANDROID 创建的 XrHandMeshTrackerANDROID。
有效用法(隐式)
- 在调用 xrDestroyHandMeshTrackerANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 handMeshTracker必须是有效的 XrHandMeshTrackerANDROID 句柄
线程安全
- 对
handMeshTracker和任何子句柄的访问必须进行外部同步
返回代码
XR_SUCCESS
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_HANDLE_INVALID
定位手部网格
应用可以使用 xrGetHandMeshANDROID 函数在给定时间戳检索手部网格。调用 xrGetHandMeshANDROID 时,手部网格的顶点位置和法线以 XrHandMeshGetInfoANDROID::baseSpace 指定的空间表示。
XrResult xrGetHandMeshANDROID(
XrHandMeshTrackerANDROID handMeshTracker,
const XrHandMeshGetInfoANDROID* getInfo,
XrHandTrackingMeshesANDROID* handMeshes);
参数说明
handMeshTracker是先前使用 xrCreateHandMeshTrackerANDROID 创建的 XrHandMeshTrackerANDROID 句柄。getInfo是一个 XrHandMeshGetInfoANDROID 结构,其中包含查询手部网格数据的信息。handMeshes是指向 XrHandTrackingMeshesANDROID 结构的指针,该结构将填充手部网格数据。
应用可以使用 xrGetHandMeshANDROID 函数访问运行时生成的手部网格缓冲区。
应用应在会话期间至少调用一次 xrBeginFrame,然后才能首次调用 xrGetHandMeshANDROID。
应用应使用 XrHandMeshANDROID::indexCount 和 XrHandMeshANDROID::vertexCount 来访问手部网格缓冲区,并在每次调用 xrGetHandMeshANDROID 时在渲染循环中重用它们。
有效用法(隐式)
- 在调用 xrGetHandMeshANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 handMeshTracker必须是有效的 XrHandMeshTrackerANDROID 句柄getInfo必须是指向有效的 XrHandMeshGetInfoANDROID 结构的指针handMeshes必须是指向 XrHandTrackingMeshesANDROID 结构的指针
返回代码
XR_SUCCESSXR_SESSION_LOSS_PENDING
XR_ERROR_FUNCTION_UNSUPPORTEDXR_ERROR_RUNTIME_FAILUREXR_ERROR_INSTANCE_LOSTXR_ERROR_SESSION_LOSTXR_ERROR_HANDLE_INVALIDXR_ERROR_SIZE_INSUFFICIENTXR_ERROR_TIME_INVALID
XrHandMeshGetInfoANDROID 描述了获取手部网格数据所需的信息。
typedef struct XrHandMeshGetInfoANDROID {
XrStructureType type;
const void* next;
XrSpace baseSpace;
XrTime time;
} XrHandMeshGetInfoANDROID;
成员说明
type是此结构的 XrStructureType。next为NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。baseSpace是一个 XrSpace,定义了用于定位time处顶点变换的参考空间。time是一个XrTime,描述了应用希望查询手部网格的时间。
有效用法(隐式)
- 在使用 XrHandMeshGetInfoANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 type必须是XR_TYPE_HAND_MESH_GET_INFO_ANDROIDnext必须为NULL或指向结构链中下一个结构的有效指针baseSpace必须是有效的 XrSpace 句柄
XrHandTrackingMeshesANDROID 结构包含双手网格数据。
typedef struct XrHandTrackingMeshesANDROID {
XrStructureType type;
void* next;
XrHandMeshANDROID leftHandMesh;
XrHandMeshANDROID rightHandMesh;
} XrHandTrackingMeshesANDROID;
成员说明
type是此结构的 XrStructureType。next为NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。leftHandMesh是左手的 XrHandMeshANDROID。rightHandMesh是右手的 XrHandMeshANDROID。
有效用法(隐式)
- 在使用 XrHandTrackingMeshesANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 type必须是XR_TYPE_HAND_TRACKING_MESHES_ANDROIDnext必须为NULL或指向结构链中下一个结构的有效指针leftHandMesh必须是有效的 XrHandMeshANDROID 结构rightHandMesh必须是有效的 XrHandMeshANDROID 结构
XrHandMeshANDROID 结构包含数据和缓冲区,用于从 xrGetHandMeshANDROID 函数接收单手的手部网格追踪数据。
typedef struct XrHandMeshANDROID {
XrBool32 isActive;
XrTime dynamicLastUpdateTime;
uint32_t indexCount;
uint32_t vertexCount;
const uint32_t* indices;
const XrVector2f* textureUVs;
const XrVector3f* positions;
const XrVector3f* normals;
XrPosef baseSpaceFromVertexSpace;
} XrHandMeshANDROID;
成员说明
type是此结构的 XrStructureType。next为NULL或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。isActive是一个XrBool32,指示当前手部网格追踪器是否处于活动状态以及网格数据是否有效。dynamicLastUpdateTime是一个XrTime,指定动态缓冲区最后一次更新的时间。indexCount是一个uint32_t,表示手部网格的索引数量。vertexCount是一个uint32_t,表示手部网格的位置数量。当系统支持时,它也可用作textureUVs或normals的数量。indices是一个uint32_t数组,表示逆时针卷绕顺序的三角形网格索引。指向的值数量为indexCount。textureUVs为NULL或一个XrVector2f数组,表示顶点纹理坐标。指向的值数量为vertexCount。positions是一个XrVector3f数组,表示baseSpaceFromVertexSpace中的顶点位置。指向的值数量为vertexCount。normals为NULL或一个XrVector3f数组,表示baseSpaceFromVertexSpace中的顶点法线。指向的值数量为vertexCount。baseSpaceFromVertexSpace是调用 xrGetHandMeshANDROID 时位于 XrHandMeshGetInfoANDROID::baseSpace 中的顶点 XrSpace。应用可以使用它在渲染期间转换网格顶点和法线的坐标空间。
手部网格以三角形列表表示,每个三角形的顶点从手部外部观察时按逆时针顺序排列。
当返回的 isActive 值为 XR_FALSE 时,表示手部未被主动追踪;例如,手部超出传感器的范围,输入焦点已从应用中移开,或者应用没有访问手部追踪数据的权限。
当返回的 isActive 值为 XR_TRUE 时,indices 和 positions 中表示的手部追踪网格(如果系统支持,包括 textureUVs 和 normals)将更新为提供给 xrGetHandMeshANDROID 函数的 XrHandMeshGetInfoANDROID::time 的最新数据。
XrHandMeshANDROID 中返回的手部网格缓冲区所指向的内存由运行时拥有并与应用共享。只要 XrHandMeshTrackerANDROID 句柄有效,从任何线程访问该内存都是安全的,直到下一次调用 xrBeginFrame。
indices和textureUVs指向的值不是动态的positions和normals指向的指针和值是动态的,它们在调用 xrBeginFrame 之间都可能发生变化。应用可以使用dynamicLastUpdateTime来检查自上一帧以来值是否已更改,并在没有更改时避免不必要的数据处理。
有效用法(隐式)
- 在使用 XrHandMeshANDROID 之前,必须启用
XR_ANDROID_hand_mesh扩展 indices必须是指向有效的uint32_t值的指针textureUVs必须是指向有效的 XrVector2f 结构的指针positions必须是指向有效的 XrVector3f 结构的指针normals必须是指向有效的 XrVector3f 结构的指针
手部网格追踪示例代码
以下示例代码演示了如何访问手部网格缓冲区进行渲染。
XrInstance instance; // Created at app startup
XrSystemId systemId; // Received from xrGetSystem() at app startup
XrSession session; // Created at app startup.
XrSpace appPlaySpace; // Created at app startup.
// The function pointers are previously initialized using xrGetInstanceProcAddr.
PFN_xrCreateHandMeshTrackerANDROID xrCreateHandMeshTrackerANDROID; // previously initialized
PFN_xrDestroyHandMeshTrackerANDROID xrDestroyHandMeshTrackerANDROID; // previously initialized
PFN_xrGetHandMeshANDROID xrGetHandMeshANDROID; // previously initialized
// Inspect system capability
XrSystemHandMeshTrackingPropertiesANDROID handMeshTrackingProps = {
.type = XR_TYPE_SYSTEM_HAND_MESH_TRACKING_PROPERTIES_ANDROID,
};
XrSystemProperties sysProps = {
.type = XR_TYPE_SYSTEM_PROPERTIES,
.next = &handMeshTrackingProps
};
CHK_XR(xrGetSystemProperties(instance, systemId, &sysProps));
if (!handMeshTrackingProps.supportsHandMeshTracking) {
// hand mesh tracking is not supported.
return;
}
XrHandMeshTrackerCreateInfoANDROID trackerCreateInfo = {
.type = XR_TYPE_HAND_MESH_TRACKER_CREATE_INFO_ANDROID
};
XrHandMeshTrackerANDROID handMeshTracker = XR_NULL_HANDLE;
CHK_XR(xrCreateHandMeshTrackerANDROID(
session, &trackerCreateInfo, &handMeshTracker));
// app update loop
while (true) {
// ...
// For every frame in frame loop
// ...
XrFrameState frameState; // previously returned from xrWaitFrame
const XrTime time = frameState.predictedDisplayTime;
// ...
XrHandMeshGetInfoANDROID getInfo = {
.type = XR_TYPE_HAND_MESH_GET_INFO_ANDROID,
.baseSpace = appPlaySpace,
.time = time,
};
XrHandTrackingMeshesANDROID handMeshes = {
.type = XR_TYPE_HAND_TRACKING_MESHES_ANDROID
};
CHK_XR(xrGetHandMeshANDROID(handMeshTracker, &getInfo, &handMeshes));
if (handMeshes.leftHandMesh.isActive) {
// access vertex/index buffers for rendering.
}
// ...
// Finish frame loop
// ...
}
CHECK_XR(xrDestroyHandMeshTracker(handMeshTracker));
新对象类型
新枚举常量
XrObjectType 枚举已扩展,包含
XR_OBJECT_TYPE_HAND_MESH_TRACKER_ANDROID
XrStructureType 枚举已扩展,包含
XR_TYPE_SYSTEM_HAND_MESH_TRACKING_PROPERTIES_ANDROIDXR_TYPE_HAND_MESH_TRACKER_CREATE_INFO_ANDROIDXR_TYPE_HAND_MESH_GET_INFO_ANDROIDXR_TYPE_HAND_TRACKING_MESHES_ANDROID
新枚举
新结构
- XrSystemHandMeshTrackingPropertiesANDROID
- XrHandMeshTrackerCreateInfoANDROID
- XrHandMeshGetInfoANDROID
- XrHandMeshANDROID
- XrHandTrackingMeshesANDROID
新函数
问题
版本历史
- 修订版 1,2024-09-10 (Levana Chen)
- 初始扩展说明
OpenXR™ 和 OpenXR 标志是 Khronos Group Inc. 拥有的商标,并在中国、欧盟、日本和英国注册为商标。