XR_ANDROID_hand_mesh OpenXR 扩展

名称字符串

XR_ANDROID_hand_mesh

扩展程序类型

实例扩展

已注册的扩展号码

704

修订版本

1

扩展程序和版本依赖项

OpenXR 1.0

上次修改日期

2024-09-10

IP 状态

没有已知的 IP 版权主张。

创作贡献者

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::textureUVs NULL

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

有效用法(隐式)

创建手部网格跟踪器手柄

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 函数访问运行时生成的手部网格缓冲区。

在首次调用 xrGetHandMeshANDROID 之前,应用在会话期间至少调用一次 xrBeginFrame

应用使用 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 中放置顶点的转换的参考空间。
  • timeXrTime,用于描述应用希望查询手部网格的时刻。

有效用法(隐式)

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,用于指示当前的手部网格跟踪器是否处于活动状态以及网格数据是否有效。
  • dynamicLastUpdateTimeXrTime,用于指定上次更新动态缓冲区的时间。
  • indexCount 是一个 uint32_t,用作手网格的 indices 数量。
  • vertexCount 是一个 uint32_t,用作手部网格的 positions 数量。当系统支持 textureUVsnormals 时,还可以将其用于 textureUVsnormals
  • indices 是一个 uint32_t 数组,表示三角形的网格索引,顺序为逆时针。指向的值的数量为 indexCount
  • textureUVsNULL 或表示顶点纹理坐标的 XrVector2f 数组。所指向的值的数量为 vertexCount
  • positions 是一个 XrVector3f 数组,表示 baseSpaceFromVertexSpace 中的顶点位置。所指向的值的数量为 vertexCount
  • normalsNULLXrVector3f 数组,表示 baseSpaceFromVertexSpace 中的顶点法向量。所指向的值的数量为 vertexCount
  • baseSpaceFromVertexSpace 是调用 xrGetHandMeshANDROID 时位于 XrHandMeshGetInfoANDROID::baseSpace 中的顶点 XrSpace。应用可以使用它在渲染期间转换网格顶点和法线的坐标空间。

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

如果返回的 isActive 值为 XR_FALSE,则表示系统未主动跟踪手部;例如,手部超出传感器的范围、输入焦点已从应用移开,或者应用无权访问手部跟踪数据。

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

XrHandMeshANDROID 中返回的手部网格缓冲区指向的内存归运行时所有,并与应用共享。在下次调用 xrBeginFrame 之前,只要 XrHandMeshTrackerANDROID 句柄有效,就可以从任何线程安全地访问内存。

  • indicestextureUVs 指向的值不是动态
  • 指针以及 positionsnormals 指向的值都是动态的,在对 xrBeginFrame 的调用之间,这两个值都可能会发生变化。应用可以使用 dynamicLastUpdateTime 检查值自上一个帧以来是否发生了变化,并在没有变化时避免不必要的数据处理。

有效用法(隐式)

  • 必须先启用 XR_ANDROID_hand_mesh 扩展程序,然后才能使用 XrHandMeshANDROID
  • 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 年 9 月 10 日(Levana Chen)
    • 初始扩展程序说明