• OpenXR手部追踪实现详解


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

    开始之前

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

    检查手部追踪支持

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

    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;  // 系统不支持手部追踪
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

    PFN_xrCreateHandTrackerEXT pfnCreateHandTrackerEXT;
    CHK_XR(xrGetInstanceProcAddr(instance, "xrCreateHandTrackerEXT",
                                 reinterpret_cast<PFN_xrVoidFunction*>(&pfnCreateHandTrackerEXT)));
    
    • 1
    • 2
    • 3

    创建手部追踪器

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

    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));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置关节数据结构

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

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

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

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

    PFN_xrLocateHandJointsEXT pfnLocateHandJointsEXT;
    CHK_XR(xrGetInstanceProcAddr(instance, "xrLocateHandJointsEXT",
                                 reinterpret_cast<PFN_xrVoidFunction*>(&pfnLocateHandJointsEXT)));
    
    • 1
    • 2
    • 3

    执行帧循环中的手部追踪

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

    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;
            // 可以进一步处理关节位置和速度数据...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    完整代码

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

    #include 
    #include 
    
    // 已经初始化的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]; // 食指尖端速度
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

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

    结语

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

  • 相关阅读:
    Java / Android 多线程和 synchroized 锁
    LeetCode-37-解数独
    五、DRF 模型序列化器ModelSerializer
    zabbix5 使用自动发现对端口进行监控
    Vue定时器的使用和设置(图文详解)附上源码
    mysql leetcode打题记录
    如何设计软件架构:重要技巧和最佳实践
    Vue.js 框架源码与进阶 - Virtual DOM 的实现原理
    【Java】SpringMVC ResponseBodyAdvice详解
    JavaScript变量及声明
  • 原文地址:https://blog.csdn.net/m0_52537869/article/details/137908044