OpenXR手部追踪实现详解

在虚拟现实(VR)和增强现实(AR)应用中,手部追踪技术是提高用户交互自然性的关键技术之一。本文将详细介绍如何使用OpenXR API实现手部追踪功能,包括系统属性的查询、手部追踪器的创建和手部关节的定位。

开始之前

在深入手部追踪实现之前,确保您已经有一个正确配置的OpenXR环境,包括有效的XrInstanceXrSystemIdXrSession,以及一个参考空间XrSpace。这些对象通常在应用程序初始化阶段创建,并在整个应用程序生命周期中使用。

检查手部追踪支持

首先,我们需要检查当前XR系统是否支持手部追踪。这一步骤是通过查询XrSystemProperties来完成的,该结构中嵌入了XrSystemHandTrackingPropertiesEXT以获取手部追踪相关的支持信息:

cpp 复制代码
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties{
    XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT};
XrSystemProperties systemProperties{XR_TYPE_SYSTEM_PROPERTIES,
                                    &handTrackingSystemProperties};

CHK_XR(xrGetSystemProperties(instance, systemId, &systemProperties));

if (!handTrackingSystemProperties.supportsHandTracking) {
    return;  // 系统不支持手部追踪
}

获取创建手部追踪器的函数指针

OpenXR利用扩展机制提供了手部追踪功能,我们需要通过xrGetInstanceProcAddr获取xrCreateHandTrackerEXT函数的指针,以便创建手部追踪器:

cpp 复制代码
PFN_xrCreateHandTrackerEXT pfnCreateHandTrackerEXT;
CHK_XR(xrGetInstanceProcAddr(instance, "xrCreateHandTrackerEXT",
                             reinterpret_cast<PFN_xrVoidFunction*>(&pfnCreateHandTrackerEXT)));

创建手部追踪器

有了函数指针后,我们可以为左手创建一个追踪器,配置为追踪默认的手部关节集合:

cpp 复制代码
XrHandTrackerEXT leftHandTracker{};
XrHandTrackerCreateInfoEXT createInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
createInfo.hand = XR_HAND_LEFT_EXT;
createInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
CHK_XR(pfnCreateHandTrackerEXT(session, &createInfo, &leftHandTracker));

配置关节数据结构

在开始帧循环之前,初始化用于存储关节位置和速度数据的结构:

cpp 复制代码
XrHandJointLocationEXT jointLocations[XR_HAND_JOINT_COUNT_EXT];
XrHandJointVelocityEXT jointVelocities[XR_HAND_JOINT_COUNT_EXT];

XrHandJointVelocitiesEXT velocities{XR_TYPE_HAND_JOINT_VELOCITIES_EXT};
velocities.jointCount = XR_HAND_JOINT_COUNT_EXT;
velocities.jointVelocities = jointVelocities;

XrHandJointLocationsEXT locations{XR_TYPE_HAND_JOINT_LOCATIONS_EXT};
locations.next = &velocities;
locations.jointCount = XR_HAND_JOINT_COUNT_EXT;
locations.jointLocations = jointLocations;

获取定位手部关节的函数指针

与创建手部追踪器相似,我们需要获取xrLocateHandJointsEXT函数指针:

cpp 复制代码
PFN_xrLocateHandJointsEXT pfnLocateHandJointsEXT;
CHK_XR(xrGetInstanceProcAddr(instance, "xrLocateHandJointsEXT",
                             reinterpret_cast<PFN_xrVoidFunction*>(&pfnLocateHandJointsEXT)));

执行帧循环中的手部追踪

在每一帧中,使用xrLocateHandJointsEXT函数来更新手部关节的位置和速度:

cpp 复制代码
while (1) {
    XrFrameState frameState; // 预先从xrWaitFrame获取
    const XrTime time = frameState.predictedDisplayTime;

    XrHandJointsLocateInfoEXT

 locateInfo{XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT};
    locateInfo.baseSpace = worldSpace;
    locateInfo.time = time;

    CHK_XR(pfnLocateHandJointsEXT(leftHandTracker, &locateInfo, &locations));

    if (locations.isActive) {
        const XrPosef &indexTipInWorld = jointLocations[XR_HAND_JOINT_INDEX_TIP_EXT].pose;
        const XrPosef &thumbTipInWorld = jointLocations[XR_HAND_JOINT_THUMB_TIP_EXT].pose;
        // 可以进一步处理关节位置和速度数据...
    }
}

完整代码

以下是完整的代码示例,展示了如何在OpenXR环境下实现手部追踪功能,包括检查手部追踪支持、创建手部追踪器、定位手部关节等:

cpp 复制代码
#include <openxr/openxr.h>
#include <openxr/openxr_ext.h>

// 已经初始化的XR实例,系统ID,会话,以及一个参考空间
XrInstance instance; // XR实例
XrSystemId systemId; // 系统ID
XrSession session;   // XR会话
XrSpace worldSpace;  // 参考空间,例如从XR_REFERENCE_SPACE_TYPE_LOCAL创建

// 检查手部追踪系统属性
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties{
    XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT}; // 手部追踪属性结构
XrSystemProperties systemProperties{XR_TYPE_SYSTEM_PROPERTIES,
                                    &handTrackingSystemProperties}; // 系统属性结构
// 获取系统属性
CHK_XR(xrGetSystemProperties(instance, systemId, &systemProperties));
// 如果系统不支持手部追踪,则不继续执行
if (!handTrackingSystemProperties.supportsHandTracking) {
    return;
}

// 获取xrCreateHandTrackerEXT函数指针
PFN_xrCreateHandTrackerEXT pfnCreateHandTrackerEXT;
CHK_XR(xrGetInstanceProcAddr(instance, "xrCreateHandTrackerEXT",
                             reinterpret_cast<PFN_xrVoidFunction*>(&pfnCreateHandTrackerEXT)));

// 创建左手的手部追踪器,追踪默认设置的手部关节
XrHandTrackerEXT leftHandTracker{};
{
    XrHandTrackerCreateInfoEXT createInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
    createInfo.hand = XR_HAND_LEFT_EXT; // 设置为左手
    createInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT; // 关节集设置为默认
    CHK_XR(pfnCreateHandTrackerEXT(session, &createInfo, &leftHandTracker));
}

// 在帧循环开始前分配缓冲区以接收关节位置和速度数据
XrHandJointLocationEXT jointLocations[XR_HAND_JOINT_COUNT_EXT]; // 关节位置数组
XrHandJointVelocityEXT jointVelocities[XR_HAND_JOINT_COUNT_EXT]; // 关节速度数组

XrHandJointVelocitiesEXT velocities{XR_TYPE_HAND_JOINT_VELOCITIES_EXT};
velocities.jointCount = XR_HAND_JOINT_COUNT_EXT;
velocities.jointVelocities = jointVelocities;

XrHandJointLocationsEXT locations{XR_TYPE_HAND_JOINT_LOCATIONS_EXT};
locations.next = &velocities; // 连接速度和位置结构
locations.jointCount = XR_HAND_JOINT_COUNT_EXT;
locations.jointLocations = jointLocations;

// 获取xrLocateHandJointsEXT函数指针
PFN_xrLocateHandJointsEXT pfnLocateHandJointsEXT;
CHK_XR(xrGetInstanceProcAddr(instance, "xrLocateHandJointsEXT",
                             reinterpret_cast<PFN_xrVoidFunction*>(&pfnLocateHandJointsEXT)));

// 开始帧循环
while (1) {
    XrFrameState frameState; // 从xrWaitFrame获取的帧状态
    const XrTime time = frameState.predictedDisplayTime; // 预测的显示时间

    XrHandJointsLocateInfoEXT locateInfo{XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT};
    locateInfo.baseSpace = worldSpace; // 设置基础空间为世界空间
    locateInfo.time = time; // 设置时间

    // 定位左手的关节
    CHK_XR(pfnLocateHandJointsEXT(leftHandTracker, &locateInfo, &locations));

    if (locations.isActive) {
        // 如果关节位置有效,则可以使用关节位置
        const XrPosef &indexTipInWorld = jointLocations[XR_HAND_JOINT_INDEX_TIP_EXT].pose; // 食指尖端位置
        const XrPosef &thumbTipInWorld = jointLocations[XR_HAND_JOINT_THUMB_TIP_EXT].pose; // 拇指尖端位置

        // 进一步处理关节位置和速度信息...
        const float indexTipRadius = jointLocations[XR_HAND_JOINT_INDEX_TIP_EXT].radius; // 食指尖端半径
        const XrHandJointVelocityEXT &indexTipVelocity = jointVelocities[XR_HAND_JOINT_INDEX_TIP_EXT]; // 食指尖端速度
    }
}

这段代码完整地演示了如何在OpenXR框架下通过扩展接口实现手部追踪。从检查系统属性是否支持手部追踪开始,到获取必要的函数指针,再到创建手部追踪器和关节的实时位置与速度更新,都是建立高交互性VR/AR应用的基础。希望这个示例能帮助开发者更好地理解和使用OpenXR进行手部追踪开发。

结语

通过以上步骤,您可以在支持OpenXR的平台上实现精确的手部追踪功能,进一步丰富您的AR/VR应用的交互体验。这种实现方式提供了高度的灵活性和扩展性,是现代XR应用开发的基石之一。

相关推荐
MediaTea1 小时前
Pr 视频过渡:沉浸式视频 - VR 默比乌斯缩放
vr
道可云1 小时前
道可云人工智能&元宇宙每日资讯|2024国际虚拟现实创新大会将在青岛举办
大数据·人工智能·3d·机器人·ar·vr
MediaTea1 小时前
Pr 视频过渡:沉浸式视频 - VR 球形模糊
vr
小春熙子1 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Sitarrrr4 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧4 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
逐·風12 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i13 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
花生糖@18 小时前
VR 创业之路:从《I Expect You To Die》到未来展望
创业创新·vr·创业
starsongda18 小时前
VR科技展厅重塑科技展示新风貌,引领未来展示潮流
科技·3d·vr