October3d55/M/PICOOpen7991a2a23d57V5/Source/PICOOpenXRHandTracking/Private/PICO_HandTracking.h

170 lines
6.8 KiB
C
Raw Normal View History

2025-03-10 09:43:27 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "HeadMountedDisplayTypes.h"
#include "XRMotionControllerBase.h"
#include "ILiveLinkSource.h"
#include "IInputDevice.h"
#include "IHandTracker.h"
#include "IOpenXRExtensionPlugin.h"
enum class ETrackingStatus : uint8;
struct FMotionControllerSource;
/**
* OpenXR HandTracking
*/
class FHandTrackingPICO :
public IOpenXRExtensionPlugin,
public IInputDevice,
public FXRMotionControllerBase,
public IHandTracker,
public ILiveLinkSource
{
public:
struct FHandState : public FNoncopyable
{
FHandState();
XrHandTrackerEXT HandTracker{};
XrHandJointLocationEXT JointLocations[XR_HAND_JOINT_COUNT_EXT];
XrHandJointVelocityEXT JointVelocities[XR_HAND_JOINT_COUNT_EXT];
XrHandJointVelocitiesEXT Velocities{ XR_TYPE_HAND_JOINT_VELOCITIES_EXT };
XrHandJointLocationsEXT Locations{ XR_TYPE_HAND_JOINT_LOCATIONS_EXT };
XrHandTrackingScaleFB Scale{ XR_TYPE_HAND_TRACKING_SCALE_FB };
// Transforms are cached in Unreal Tracking Space
FTransform KeypointTransforms[EHandKeypointCount];
float Radii[EHandKeypointCount];
FVector LinearVelocity[EHandKeypointCount];
FVector AngularVelocity[EHandKeypointCount];
float HandScale = 1.0f;
bool ReceivedJointPoses = false;
bool GetTransform(EHandKeypoint KeyPoint, FTransform& OutTransform) const;
const FTransform& GetTransform(EHandKeypoint KeyPoint) const;
};
public:
FHandTrackingPICO(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler);
virtual ~FHandTrackingPICO();
/** IOpenXRExtensionPlugin */
virtual FString GetDisplayName() override
{
return FString(TEXT("HandTrackingPICO"));
}
virtual bool GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
virtual bool GetOptionalExtensions(TArray<const ANSICHAR*>& OutExtensions) override;
virtual const void* OnGetSystem(XrInstance InInstance, const void* InNext) override;
virtual const void* OnCreateSession(XrInstance InInstance, XrSystemId InSystem, const void* InNext) override;
virtual const void* OnBeginSession(XrSession InSession, const void* InNext) override;
virtual void UpdateDeviceLocations(XrSession InSession, XrTime DisplayTime, XrSpace TrackingSpace) override;
/** IMotionController interface */
virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource, FRotator& OutOrientation, FVector& OutPosition, float WorldToMetersScale) const override;
virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const override;
virtual FName GetMotionControllerDeviceTypeName() const override;
virtual void EnumerateSources(TArray<FMotionControllerSource>& SourcesOut) const override;
// ILiveLinkSource interface
virtual void ReceiveClient(ILiveLinkClient* InClient, FGuid InSourceGuid) override;
virtual bool IsSourceStillValid() const override;
virtual bool RequestSourceShutdown() override;
virtual FText GetSourceMachineName() const override;
virtual FText GetSourceStatus() const override;
virtual FText GetSourceType() const override;
// End ILiveLinkSource
/** IInputDevice interface */
virtual void Tick(float DeltaTime) override;
virtual void SendControllerEvents() override;
virtual void SetMessageHandler(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler) override;
virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override;
virtual void SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value) override {};
virtual void SetChannelValues(int32 ControllerId, const FForceFeedbackValues &values) override {};
virtual bool SupportsForceFeedback(int32 ControllerId) override { return false; }
virtual bool IsGamepadAttached() const override;
/** IHandTracker */
virtual FName GetHandTrackerDeviceTypeName() const override;
virtual bool IsHandTrackingStateValid() const override;
virtual bool GetKeypointState(EControllerHand Hand, EHandKeypoint Keypoint, FTransform& OutTransform, float& OutRadius) const override;
virtual bool GetAllKeypointStates(EControllerHand Hand, TArray<FVector>& OutPositions, TArray<FQuat>& OutRotations, TArray<float>& OutRadii) const override;
private:
XrSession Session = XR_NULL_HANDLE;
XrSpace TrackingSpace = XR_NULL_HANDLE;
XrTime DisplayTime = 0;
bool bHandTrackingRunning = false;
FHandState& GetLeftHandState();
FHandState& GetRightHandState();
public:
bool StartHandTracking();
void StopHandTracking();
bool UpdateHandTrackingData();
bool IsHandTrackingRunning() { return bHandTrackingRunning; }
bool GetHandTrackingData(EControllerHand Hand, TArray<FVector>& OutPositions, TArray<FQuat>& OutRotations, TArray<float>& OutRadii, TArray<FVector>& LinearVelocity, TArray<FVector>& AngularVelocity, float& Scale) const;
bool GetHandTrackingMeshScale(EControllerHand Hand, float& Scale);
const FHandState& GetLeftHandState() const;
const FHandState& GetRightHandState() const;
bool IsHandTrackingSupportedByDevice() const;
/** Parses the enum name removing the prefix */
static FName ParseEOpenXRHandKeypointEnumName(FName EnumName)
{
static int32 EnumNameLength = FString(TEXT("EHandKeypoint::")).Len();
FString EnumString = EnumName.ToString();
return FName(*EnumString.Right(EnumString.Len() - EnumNameLength));
}
private:
void AddKeys();
void BuildMotionSourceToKeypointMap();
void SetupLiveLinkData();
void UpdateLiveLink();
void UpdateLiveLinkTransforms(TArray<FTransform>& OutTransforms, const FHandTrackingPICO::FHandState& HandState);
bool bHandTrackingAvailable = false;
PFN_xrCreateHandTrackerEXT xrCreateHandTrackerEXT = nullptr;
PFN_xrDestroyHandTrackerEXT xrDestroyHandTrackerEXT = nullptr;
PFN_xrLocateHandJointsEXT xrLocateHandJointsEXT = nullptr;
class IXRTrackingSystem* XRTrackingSystem = nullptr;
TSharedPtr<FGenericApplicationMessageHandler> MessageHandler;
int32 DeviceIndex;
int32 CurrentHandTrackingDataIndex = 0;
TArray<int32> BoneParents;
TArray<EHandKeypoint> BoneKeypoints;
typedef TPair<EHandKeypoint, bool> MotionSourceInfo; // bool true == left, false == right
TMap<FName, MotionSourceInfo> MotionSourceToKeypointMap;
bool bSupportLegacyControllerMotionSources = true;
FHandState HandStates[2];
// LiveLink Data
/** The local client to push data updates to */
ILiveLinkClient* LiveLinkClient = nullptr;
/** Our identifier in LiveLink */
FGuid LiveLinkSourceGuid;
static FLiveLinkSubjectName LiveLinkLeftHandTrackingSubjectName;
static FLiveLinkSubjectName LiveLinkRightHandTrackingSubjectName;
FLiveLinkSubjectKey LiveLinkLeftHandTrackingSubjectKey;
FLiveLinkSubjectKey LiveLinkRightHandTrackingSubjectKey;
bool bNewLiveLinkClient = false;
FLiveLinkStaticDataStruct LiveLinkSkeletonStaticData;
TArray<FTransform> LeftAnimationTransforms;
TArray<FTransform> RightAnimationTransforms;
};
DEFINE_LOG_CATEGORY_STATIC(PICOOpenXRHandTracking, Display, All);