/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/EnginePlugins/OpenXRPlugin/Input/Implementation/OpenXRHandTracking.cpp
190 строк
8 KB
Sanakan8472
OpenXR plugin fixes (#1800)
30 янв 2026, 18:51
Не верифицирован
30 янв 2026, 18:51
52fc455
Код
Авторство
О чём код?
#include <OpenXRPlugin/OpenXRPluginPCH.h> #include <Core/World/World.h> #include <Foundation/Profiling/Profiling.h> #include <GameEngine/XR/StageSpaceComponent.h> #include <OpenXRPlugin/Input/OpenXRHandTracking.h> #include <OpenXRPlugin/OpenXRDeclarations.h> #include <OpenXRPlugin/OpenXRSingleton.h> #include <OpenXRPlugin/Utils/OpenXRConversionUtils.h> EZ_IMPLEMENT_SINGLETON(ezOpenXRHandTracking); bool ezOpenXRHandTracking::IsHandTrackingSupported(ezOpenXR* pOpenXR) { XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties{XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT}; XrSystemProperties systemProperties{XR_TYPE_SYSTEM_PROPERTIES, &handTrackingSystemProperties}; XrResult res = xrGetSystemProperties(pOpenXR->m_pInstance, pOpenXR->m_SystemId, &systemProperties); if (res == XrResult::XR_SUCCESS) { return handTrackingSystemProperties.supportsHandTracking; } return false; } ezOpenXRHandTracking::ezOpenXRHandTracking(ezOpenXR* pOpenXR) : m_SingletonRegistrar(this) , m_pOpenXR(pOpenXR) { for (ezUInt32 uiSide : {0, 1}) { const XrHandEXT uiHand = uiSide == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT; XrHandTrackerCreateInfoEXT createInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT}; createInfo.hand = uiHand; XR_LOG_ERROR(m_pOpenXR->m_Extensions.pfn_xrCreateHandTrackerEXT(pOpenXR->m_pSession, &createInfo, &m_HandTracker[uiSide])); m_Locations[uiSide].type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT; m_Locations[uiSide].next = &m_Velocities[uiSide]; m_Locations[uiSide].jointCount = XR_HAND_JOINT_COUNT_EXT; m_Locations[uiSide].jointLocations = m_JointLocations[uiSide]; ezMemoryUtils::ZeroFill(&m_JointLocations[uiSide][0], XR_HAND_JOINT_COUNT_EXT); m_Velocities[uiSide].type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT; m_Velocities[uiSide].jointCount = XR_HAND_JOINT_COUNT_EXT; m_Velocities[uiSide].jointVelocities = m_JointVelocities[uiSide]; ezMemoryUtils::ZeroFill(&m_JointVelocities[uiSide][0], XR_HAND_JOINT_COUNT_EXT); m_JointData[uiSide].SetCount(XR_HAND_JOINT_LITTLE_TIP_EXT + 1); for (ezUInt32 i = 0; i <= XR_HAND_JOINT_LITTLE_TIP_EXT; ++i) { m_JointData[uiSide][i].m_Bone.m_Transform.SetIdentity(); m_JointVelocities[uiSide][i].velocityFlags = XR_SPACE_VELOCITY_LINEAR_VALID_BIT | XR_SPACE_VELOCITY_ANGULAR_VALID_BIT; } } // Map hand parts to hand joints m_HandParts[ezXRHandPart::Palm].PushBack(XR_HAND_JOINT_PALM_EXT); m_HandParts[ezXRHandPart::Palm].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Wrist].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Thumb].PushBack(XR_HAND_JOINT_THUMB_TIP_EXT); m_HandParts[ezXRHandPart::Thumb].PushBack(XR_HAND_JOINT_THUMB_DISTAL_EXT); m_HandParts[ezXRHandPart::Thumb].PushBack(XR_HAND_JOINT_THUMB_PROXIMAL_EXT); m_HandParts[ezXRHandPart::Thumb].PushBack(XR_HAND_JOINT_THUMB_METACARPAL_EXT); m_HandParts[ezXRHandPart::Thumb].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_INDEX_TIP_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_INDEX_DISTAL_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_INDEX_PROXIMAL_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_INDEX_METACARPAL_EXT); m_HandParts[ezXRHandPart::Index].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_MIDDLE_TIP_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_MIDDLE_DISTAL_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT); m_HandParts[ezXRHandPart::Middle].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_RING_TIP_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_RING_DISTAL_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_RING_INTERMEDIATE_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_RING_PROXIMAL_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_RING_METACARPAL_EXT); m_HandParts[ezXRHandPart::Ring].PushBack(XR_HAND_JOINT_WRIST_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_LITTLE_TIP_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_LITTLE_DISTAL_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_LITTLE_METACARPAL_EXT); m_HandParts[ezXRHandPart::Little].PushBack(XR_HAND_JOINT_WRIST_EXT); } ezOpenXRHandTracking::~ezOpenXRHandTracking() { for (ezUInt32 uiSide : {0, 1}) { XR_LOG_ERROR(m_pOpenXR->m_Extensions.pfn_xrDestroyHandTrackerEXT(m_HandTracker[uiSide])); } } ezXRHandTrackingInterface::HandPartTrackingState ezOpenXRHandTracking::TryGetBoneTransforms( ezEnum<ezXRHand> hand, ezEnum<ezXRHandPart> handPart, ezEnum<ezXRTransformSpace> space, ezDynamicArray<ezXRHandBone>& out_bones) { EZ_ASSERT_DEV(handPart <= ezXRHandPart::Little, "Invalid hand part."); out_bones.Clear(); for (ezUInt32 uiJointIndex : m_HandParts[handPart]) { const JointData& jointData = m_JointData[hand][uiJointIndex]; if (!jointData.m_bValid) return ezXRHandTrackingInterface::HandPartTrackingState::Untracked; out_bones.PushBack(jointData.m_Bone); } if (space == ezXRTransformSpace::Global) { ezWorld* pWorld = m_pOpenXR->GetWorld(); if (!pWorld) return ezXRHandTrackingInterface::HandPartTrackingState::NotSupported; if (const ezStageSpaceComponentManager* pStageMan = pWorld->GetComponentManager<ezStageSpaceComponentManager>()) { if (const ezStageSpaceComponent* pStage = pStageMan->GetSingletonComponent()) { const ezTransform globalStageTransform = pStage->GetOwner()->GetGlobalTransform(); for (ezXRHandBone& bone : out_bones) { ezTransform local = bone.m_Transform; bone.m_Transform = ezTransform::MakeGlobalTransform(globalStageTransform, local); } } } } return ezXRHandTrackingInterface::HandPartTrackingState::Tracked; } void ezOpenXRHandTracking::UpdateJointTransforms() { EZ_PROFILE_SCOPE("UpdateJointTransforms"); const XrTime time = m_pOpenXR->m_FrameState.predictedDisplayTime; XrHandJointsLocateInfoEXT locateInfo{XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT}; locateInfo.baseSpace = m_pOpenXR->GetBaseSpace(); locateInfo.time = time; for (ezUInt32 uiSide : {0, 1}) { for (ezUInt32 i = 0; i <= XR_HAND_JOINT_LITTLE_TIP_EXT; ++i) { m_JointData[uiSide][i].m_Bone.m_Transform.SetIdentity(); m_JointVelocities[uiSide][i].velocityFlags = XR_SPACE_VELOCITY_LINEAR_VALID_BIT | XR_SPACE_VELOCITY_ANGULAR_VALID_BIT; } } for (ezUInt32 uiSide : {0, 1}) { if (m_pOpenXR->m_Extensions.pfn_xrLocateHandJointsEXT(m_HandTracker[uiSide], &locateInfo, &m_Locations[uiSide]) != XrResult::XR_SUCCESS) m_Locations[uiSide].isActive = false; if (m_Locations[uiSide].isActive) { for (ezUInt32 i = 0; i <= XR_HAND_JOINT_LITTLE_TIP_EXT; ++i) { const XrHandJointLocationEXT& spaceLocation = m_JointLocations[uiSide][i]; if ((spaceLocation.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) != 0 && (spaceLocation.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) != 0) { m_JointData[uiSide][i].m_bValid = true; m_JointData[uiSide][i].m_Bone.m_fRadius = spaceLocation.radius; m_JointData[uiSide][i].m_Bone.m_Transform.m_vPosition = ezOpenXRConversionUtils::ConvertPosition(spaceLocation.pose.position); m_JointData[uiSide][i].m_Bone.m_Transform.m_qRotation = ezOpenXRConversionUtils::ConvertOrientation(spaceLocation.pose.orientation); } else { m_JointData[uiSide][i].m_bValid = false; } } } else { for (ezUInt32 i = 0; i <= XR_HAND_JOINT_LITTLE_TIP_EXT; ++i) { m_JointData[uiSide][i].m_bValid = false; } } } }