XR_ANDROID_hand_mesh OpenXR 扩展

名称字符串

XR_ANDROID_hand_mesh

扩展类型

实例扩展

注册扩展号

704

修订版本

1

扩展和版本依赖项

OpenXR 1.0

最后修改日期

2024-09-10

知识产权状态

无已知知识产权声明。

贡献者

Nihav Jain, Google

Cairn Overturf, Google

Spencer Quin, Google

Levana Chen, Google

概览

此扩展支持以动态手部网格形式表示的手部追踪。

此扩展旨在为用户手部的个性化表示网格提供顶点和索引缓冲区。它可以用于遮挡和可视化。

此扩展不应用于其他手部追踪目的。

手部追踪数据可能是敏感的个人信息,与个人隐私和完整性密切相关。强烈建议存储或传输手部追踪数据的应用始终主动征得用户的明确同意。

检查系统功能

应用可以在调用 xrGetSystemProperties 时,通过将 XrSystemHandMeshTrackingPropertiesANDROID 结构链接到 XrSystemProperties 来检查系统是否支持手部网格追踪。

typedef struct XrSystemHandMeshTrackingPropertiesANDROID {
  XrStructureType    type;
  void*              next;
  XrBool32           supportsHandMeshTracking;
  XrBool32           supportsTextureUV;
  XrBool32           supportsVertexNormal;
} XrSystemHandMeshTrackingPropertiesANDROID;

成员说明

  • type 是此结构的 XrStructureType
  • nextNULL 或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。
  • supportsHandMeshTracking 是一个 XrBool32,指示所选的 XrSystemId 是否支持手部网格追踪。
  • supportsTextureUV 是一个 XrBool32,指示所选的 XrSystemId 是否支持网格顶点的纹理 UV。
  • supportsVertexNormal 是一个 XrBool32,指示所选的 XrSystemId 是否支持网格顶点的顶点法线。

supportsHandMeshTrackingXR_FALSE 时,应用避免使用手部网格功能,因为这意味着系统不支持手部网格追踪。在这种情况下,xrCreateHandMeshTrackerANDROID 将返回 XR_ERROR_FEATURE_UNSUPPORTED

如果 supportsHandMeshTracking 返回 XR_TRUE,则系统支持手部网格追踪。应用使用 XrHandMeshANDROID::indexCountXrHandMeshANDROID::vertexCount 来访问手部网格缓冲区,并在每次调用 xrGetHandMeshANDROID 时在渲染循环中重用它们。

如果 supportsTextureUV 返回 XR_FALSE,则系统不支持网格顶点的纹理 UV,因此在调用 xrGetHandMeshANDROID 时,应用将收到 XrHandMeshANDROID::textureUVsNULL

如果 supportsVertexNormal 返回 XR_FALSE,则系统不支持网格顶点的顶点法线,因此在调用 xrGetHandMeshANDROID 时,应用将收到 XrHandMeshANDROID::normalsNULL

有效用法(隐式)

创建手部网格追踪器句柄

XR_DEFINE_HANDLE(XrHandMeshTrackerANDROID)

XrHandMeshTrackerANDROID 句柄表示用于手部网格追踪和管理相关资源的手部网格追踪器。

此句柄可以用于使用此扩展中的其他函数访问手部网格缓冲区。

应用可以使用 xrCreateHandMeshTrackerANDROID 函数创建 XrHandMeshTrackerANDROID 句柄。

XrResult xrCreateHandMeshTrackerANDROID(
    XrSession                                   session,
    const XrHandMeshTrackerCreateInfoANDROID*   createInfo,
    XrHandMeshTrackerANDROID*                   handMeshTracker);

参数说明

如果系统不支持手部网格追踪,xrCreateHandMeshTrackerANDROID 将返回 XR_ERROR_FEATURE_UNSUPPORTED

XrHandMeshTrackerANDROID 句柄拥有手部网格追踪的所有资源。在完成手部网格追踪体验后,应用必须使用 xrDestroyHandMeshTrackerANDROID 函数销毁该句柄。

有效用法(隐式)

返回代码

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失败

  • XR_ERROR_FEATURE_UNSUPPORTED
  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_LIMIT_REACHED

XrHandMeshTrackerCreateInfoANDROID 结构描述了创建 XrHandMeshTrackerANDROID 句柄所需的信息。

typedef struct XrHandMeshTrackerCreateInfoANDROID {
    XrStructureType    type;
    const void*        next;
} XrHandMeshTrackerCreateInfoANDROID;

成员说明

  • type 是此结构的 XrStructureType
  • nextNULL 或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。

有效用法(隐式)

xrDestroyHandMeshTrackerANDROID 函数在完成手部网格追踪体验后,释放 handMeshTracker 和底层资源。

XrResult xrDestroyHandMeshTrackerANDROID(
    XrHandMeshTrackerANDROID handMeshTracker);

参数说明

有效用法(隐式)

线程安全

  • handMeshTracker 和任何子句柄的访问必须进行外部同步

返回代码

成功

  • XR_SUCCESS

失败

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID

定位手部网格

应用可以使用 xrGetHandMeshANDROID 函数在给定时间戳检索手部网格。调用 xrGetHandMeshANDROID 时,手部网格的顶点位置和法线以 XrHandMeshGetInfoANDROID::baseSpace 指定的空间表示。

XrResult xrGetHandMeshANDROID(
    XrHandMeshTrackerANDROID                    handMeshTracker,
    const XrHandMeshGetInfoANDROID*             getInfo,
    XrHandTrackingMeshesANDROID*                handMeshes);

参数说明

应用可以使用 xrGetHandMeshANDROID 函数访问运行时生成的手部网格缓冲区。

应用在会话期间至少调用一次 xrBeginFrame,然后才能首次调用 xrGetHandMeshANDROID

应用使用 XrHandMeshANDROID::indexCountXrHandMeshANDROID::vertexCount 来访问手部网格缓冲区,并在每次调用 xrGetHandMeshANDROID 时在渲染循环中重用它们。

有效用法(隐式)

返回代码

成功

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

失败

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_SIZE_INSUFFICIENT
  • XR_ERROR_TIME_INVALID

XrHandMeshGetInfoANDROID 描述了获取手部网格数据所需的信息。

typedef struct XrHandMeshGetInfoANDROID {
    XrStructureType    type;
    const void*        next;
    XrSpace            baseSpace;
    XrTime             time;
} XrHandMeshGetInfoANDROID;

成员说明

  • type 是此结构的 XrStructureType
  • nextNULL 或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。
  • baseSpace 是一个 XrSpace,定义了用于定位 time 处顶点变换的参考空间。
  • time 是一个 XrTime,描述了应用希望查询手部网格的时间。

有效用法(隐式)

XrHandTrackingMeshesANDROID 结构包含双手网格数据。

typedef struct XrHandTrackingMeshesANDROID {
    XrStructureType      type;
    void*                next;
    XrHandMeshANDROID    leftHandMesh;
    XrHandMeshANDROID    rightHandMesh;
} XrHandTrackingMeshesANDROID;

成员说明

  • type 是此结构的 XrStructureType
  • nextNULL 或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。
  • 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
  • nextNULL 或指向结构链中下一个结构的指针。核心 OpenXR 或此扩展中未定义此类结构。
  • isActive 是一个 XrBool32,指示当前手部网格追踪器是否处于活动状态以及网格数据是否有效。
  • dynamicLastUpdateTime 是一个 XrTime,指定动态缓冲区最后一次更新的时间。
  • indexCount 是一个 uint32_t,表示手部网格的索引数量。
  • vertexCount 是一个 uint32_t,表示手部网格的位置数量。当系统支持时,它也可用作 textureUVsnormals 的数量。
  • indices 是一个 uint32_t 数组,表示逆时针卷绕顺序的三角形网格索引。指向的值数量为 indexCount
  • textureUVsNULL 或一个 XrVector2f 数组,表示顶点纹理坐标。指向的值数量为 vertexCount
  • positions 是一个 XrVector3f 数组,表示 baseSpaceFromVertexSpace 中的顶点位置。指向的值数量为 vertexCount
  • normalsNULL 或一个 XrVector3f 数组,表示 baseSpaceFromVertexSpace 中的顶点法线。指向的值数量为 vertexCount
  • baseSpaceFromVertexSpace 是调用 xrGetHandMeshANDROID 时位于 XrHandMeshGetInfoANDROID::baseSpace 中的顶点 XrSpace。应用可以使用它在渲染期间转换网格顶点和法线的坐标空间。

手部网格以三角形列表表示,每个三角形的顶点从手部外部观察时按逆时针顺序排列。

当返回的 isActive 值为 XR_FALSE 时,表示手部未被主动追踪;例如,手部超出传感器的范围,输入焦点已从应用中移开,或者应用没有访问手部追踪数据的权限。

当返回的 isActive 值为 XR_TRUE 时,indicespositions 中表示的手部追踪网格(如果系统支持,包括 textureUVsnormals)将更新为提供给 xrGetHandMeshANDROID 函数的 XrHandMeshGetInfoANDROID::time 的最新数据。

XrHandMeshANDROID 中返回的手部网格缓冲区所指向的内存由运行时拥有并与应用共享。只要 XrHandMeshTrackerANDROID 句柄有效,从任何线程访问该内存都是安全的,直到下一次调用 xrBeginFrame

  • indicestextureUVs 指向的值不是动态的
  • positionsnormals 指向的指针和值是动态的,它们在调用 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_ANDROID
  • XR_TYPE_HAND_MESH_TRACKER_CREATE_INFO_ANDROID
  • XR_TYPE_HAND_MESH_GET_INFO_ANDROID
  • XR_TYPE_HAND_TRACKING_MESHES_ANDROID

新枚举

新结构

新函数

问题

版本历史

  • 修订版 1,2024-09-10 (Levana Chen)
    • 初始扩展说明

OpenXR™ 和 OpenXR 标志是 Khronos Group Inc. 拥有的商标,并在中国、欧盟、日本和英国注册为商标。