OpenXR手部追踪实现详解

ops/2024/12/23 7:29:41/

在虚拟现实(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;  // 系统不支持手部追踪
}

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

OpenXR利用扩展机制提供了手部追踪功能,我们需要通过xrGetInstanceProcAddr获取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)));

执行帧循环中的手部追踪

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

while (1) {XrFrameState frameState; // 预先从xrWaitFrame获取const XrTime time = frameState.predictedDisplayTime;XrHandJointsLocateInfoEXTlocateInfo{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环境下实现手部追踪功能,包括检查手部追踪支持、创建手部追踪器、定位手部关节等:

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


http://www.ppmy.cn/ops/7930.html

相关文章

【已解决】电脑设置notepad++默认打开txt

1、以管理员的方式打开notepad 步骤&#xff1a;打开设置 -> 首选项 -> 文件关联 2、 设置Notepad默认打开 按照以下步骤将Notepad设置为默认打开.txt文件&#xff1a; 右键单击任何一个.txt文件。选择“属性”。在“常规”选项卡中&#xff0c;找到“打开方式”&#…

NX二次开发UF_MTX(矩阵运算)常用函数

目录 一、概述 二、函数的介绍 2.1 UF_MTX3_copy&#xff08;复制原来矩阵&#xff09; 2.2 UF_MTX3_determinant&#xff08;计算矩阵的行列式&#xff09; 2.3 UF_MTX3_identity&#xff08;单位矩阵&#xff09; 2.4 UF_MTX3_initialize&#xff08;可以根据X、Y方向向…

工程师每日刷题-7

(1)final和override的作用&#xff1f;final为什么能提高代码执行效率&#xff1f; override&#xff1a;保证在派生类中声明的重载函数&#xff0c;与基类的虚函数有相同的签名&#xff0c;作用就是用于编译期代码检查。 final&#xff1a;阻止类的进一步派生和虚函数的进一步…

温湿度LCD显示并上传服务器

项目需求 通过温湿度传感器将值传到LCD1602&#xff0c;并实时通过蓝牙透传到手机。 硬件介绍 温湿度传感器 DHT11温湿度传感器 DHT11_温湿度传感器数据格式-CSDN博客 LCD1602LCD1602-CSDN博客 HC-01 继电器模块 硬件接线 LCD1602 D0~D7 --> A0~A7VDD, A --> 5v…

利用Sentinel解决雪崩问题(一)流量控制

1、解决雪崩问题的常见方式有四种: 超时处理:设定超时时间&#xff0c;请求超过一定时间没有响应就返回错误信息&#xff0c;不会无休止等待;舱壁模式:限定每个业务能使用的线程数&#xff0c;避免耗尽整个tomcat的资源&#xff0c;因此也叫线程隔离;熔断降级:由断路器统计业务…

Docker - WEB应用实例

原文地址&#xff0c;使用效果更佳&#xff01; Docker - WEB应用实例 | CoderMast编程桅杆Docker - WEB应用实例 在之前的章节中&#xff0c;仅对普通容器进行了演示&#xff0c;但在实际中常常使用到 Docker 容器中的 WEB 应用程序。 运行一个WEB应用 拉取镜像 创建一个容器…

Mac m1 vscode 配置latex 详细教程

1、LaTeX官网下载MacTex https://www.tug.org/mactex/mactex-download.html 2、VScode安装插件 LaTeX language supportLaTeX Workshop 3、MacTeX和插件安装完成后&#xff0c;在VScode点击设置&#xff0c;找到settings.json文件&#xff0c;在文件配置中加入&#xff1…

OpenHarmony多媒体-video_trimmer

简介 videotrimmer是在OpenHarmony环境下&#xff0c;提供视频剪辑能力的三方库。 效果展示&#xff1a; 安装教程 ohpm install ohos/videotrimmerOpenHarmony ohpm环境配置等更多内容&#xff0c;请参考 如何安装OpenHarmony ohpm包 。 使用说明 目前支持MP4格式。 视频…