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应用开发的基石之一。

相关推荐
向宇it4 小时前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
向宇it9 小时前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
神码编程15 小时前
【Unity功能集】TextureShop纹理工坊(五)选区
unity·游戏引擎·shader·ps选区
m0_7482517221 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
benben04421 小时前
Unity3D仿星露谷物语开发7之事件创建动画
unity·游戏引擎
林枫依依1 天前
Unity2021.3.16f1可以正常打开,但是Unity2017.3.0f3却常常打开闪退或者Unity2017编辑器运行起来就闪退掉
unity
异次元的归来2 天前
Unity DOTS中的share component
unity·游戏引擎
向宇it2 天前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
_oP_i2 天前
unity webgl部署到iis报错
unity
Go_Accepted2 天前
Unity全局雾效
unity