A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
OpenXRHandPoseComponent.h
Go to the documentation of this file.
1// Fill out your copyright notice in the Description page of Project Settings.
2
3#pragma once
4#include "CoreMinimal.h"
5#include "UObject/Object.h"
6#include "Engine/Texture.h"
7#include "Engine/EngineTypes.h"
8#include "HeadMountedDisplayTypes.h"
9//#include "Runtime/Launch/Resources/Version.h"
10
11#include "Animation/AnimInstanceProxy.h"
13#include "Engine/DataAsset.h"
14
15#include "OpenXRHandPoseComponent.generated.h"
16
17USTRUCT(BlueprintType, Category = "VRExpansionFunctions|OpenXR|HandSkeleton")
18struct OPENXREXPANSIONPLUGIN_API FBPSkeletalRepContainer
19{
20 GENERATED_BODY()
21public:
22
23 UPROPERTY(Transient, NotReplicated)
24 EVRSkeletalHandIndex TargetHand;
25
26 UPROPERTY(Transient, NotReplicated)
27 bool bAllowDeformingMesh;
28
29 // If true we will skip sending the 4 metacarpal bones that ue4 doesn't need, (STEAMVR skeletons need this disabled!)
30 UPROPERTY(Transient, NotReplicated)
31 bool bEnableUE4HandRepSavings;
32
33 UPROPERTY(Transient, NotReplicated)
34 TArray<FTransform> SkeletalTransforms;
35
36 UPROPERTY(Transient, NotReplicated)
37 uint8 BoneCount;
39
41 {
43 bAllowDeformingMesh = false;
44 bEnableUE4HandRepSavings = true;
45 BoneCount = 0;
46 }
47
48 bool bHasValidData()
49 {
50 return SkeletalTransforms.Num() > 0;
51 }
52
53 void CopyForReplication(FBPOpenXRActionSkeletalData& Other);
54 static void CopyReplicatedTo(const FBPSkeletalRepContainer& Container, FBPOpenXRActionSkeletalData& Other);
55
56 bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);
57};
58
59template<>
60struct TStructOpsTypeTraits< FBPSkeletalRepContainer > : public TStructOpsTypeTraitsBase2<FBPSkeletalRepContainer>
61{
62 enum
63 {
64 WithNetSerializer = true
65 };
66};
67
68USTRUCT(BlueprintType, Category = "VRGestures")
69struct OPENXREXPANSIONPLUGIN_API FOpenXRGestureFingerPosition
70{
71 GENERATED_BODY()
72public:
73
74 // The Finger index, not editable
75 UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "VRGesture")
76 EXRHandJointType IndexType;
77
78 // The locational value of this element 0.f - 1.f
79 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
80 FVector Value;
81
82 // The threshold within which this finger value will be detected as matching (1.0 would be always matching, IE: finger doesn't count)
83 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture", meta = (ClampMin = "0.0", ClampMax = "100.0", UIMin = "0.0", UIMax = "100.0"))
84 float Threshold;
85
87 {
88 IndexType = Type;
89 Value = TipLoc;
90 Threshold = 5.0f;
91 }
93 {
95 Value = FVector(0.f);
96 Threshold = 5.0f;
97 }
98};
99
100USTRUCT(BlueprintType, Category = "VRGestures")
101struct OPENXREXPANSIONPLUGIN_API FOpenXRGesture
102{
103 GENERATED_BODY()
104public:
105
106 // Name of the recorded gesture
107 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
108 FName Name;
109
110 // Samples in the recorded gesture
111 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
112 TArray<FOpenXRGestureFingerPosition> FingerValues;
113
115 {
116 InitPoseValues();
117 Name = NAME_None;
118 }
119
120 void InitPoseValues()
121 {
127 }
128};
129
133UCLASS(BlueprintType, Category = "VRGestures")
134class OPENXREXPANSIONPLUGIN_API UOpenXRGestureDatabase : public UDataAsset
135{
136 GENERATED_BODY()
137public:
138
139 // Gestures in this database
140 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
141 TArray <FOpenXRGesture> Gestures;
145 }
146};
147
148DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOpenXRGestureDetected, const FName &, GestureDetected, int32, GestureIndex, EVRSkeletalHandIndex, ActionHandType);
149DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOpenXRGestureEnded, const FName &, GestureEnded, int32, GestureIndex, EVRSkeletalHandIndex, ActionHandType);
150
151UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
152class OPENXREXPANSIONPLUGIN_API UOpenXRHandPoseComponent : public UActorComponent
154 GENERATED_BODY()
155
156public:
157 UOpenXRHandPoseComponent(const FObjectInitializer& ObjectInitializer);
158
159 // Says whether we should run gesture detection
160 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
161 bool bDetectGestures;
162
163 UFUNCTION(BlueprintCallable, Category = "VRGestures")
164 void SetDetectGestures(bool bNewDetectGestures)
165 {
166 bDetectGestures = bNewDetectGestures;
167 }
168
169 UPROPERTY(BlueprintAssignable, Category = "VRGestures")
170 FOpenXRGestureDetected OnNewGestureDetected;
171
172 UPROPERTY(BlueprintAssignable, Category = "VRGestures")
173 FOpenXRGestureEnded OnGestureEnded;
174
175 // Known sequences
176 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
177 UOpenXRGestureDatabase *GesturesDB;
178
179 UFUNCTION(BlueprintCallable, Category = "VRGestures")
180 bool SaveCurrentPose(FName RecordingName, EVRSkeletalHandIndex HandToSave = EVRSkeletalHandIndex::EActionHandIndex_Right);
181
182 UFUNCTION(BlueprintCallable, Category = "VRGestures", meta = (DisplayName = "DetectCurrentPose"))
183 bool K2_DetectCurrentPose(UPARAM(ref) FBPOpenXRActionSkeletalData& SkeletalAction, FOpenXRGesture & GestureOut);
184
185 // This version throws events
186 bool DetectCurrentPose(FBPOpenXRActionSkeletalData& SkeletalAction);
187
188 // Need this as I can't think of another way for an actor component to make sure it isn't on the server
189 inline bool IsLocallyControlled() const
190 {
191#if ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 22
192 const AActor* MyOwner = GetOwner();
193 return MyOwner->HasLocalNetOwner();
194#else
195 // I like epics new authority check more than mine
196 const AActor* MyOwner = GetOwner();
197 const APawn* MyPawn = Cast<APawn>(MyOwner);
198 return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner && MyOwner->Role == ENetRole::ROLE_Authority);
199#endif
200 }
201
202 // Using tick and not timers because skeletal components tick anyway, kind of a waste to make another tick by adding a timer over that
203 void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
206 //virtual void OnUnregister() override;
207 virtual void BeginPlay() override;
208
209 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
210 bool bGetMockUpPoseForDebugging;
212 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
213 TArray<FBPOpenXRActionSkeletalData> HandSkeletalActions;
214
215 UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformLeft)
216 FBPSkeletalRepContainer LeftHandRep;
217
218 UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformRight)
219 FBPSkeletalRepContainer RightHandRep;
220
221 UFUNCTION(Unreliable, Server, WithValidation)
222 void Server_SendSkeletalTransforms(const FBPSkeletalRepContainer& SkeletalInfo);
223
224 bool bLerpingPositionLeft;
225 bool bReppedOnceLeft;
226
227 bool bLerpingPositionRight;
228 bool bReppedOnceRight;
229
231 {
232 bool bReplicatedOnce;
233 bool bLerping;
234 float UpdateCount;
235 float UpdateRate;
236 TArray<FTransform> NewTransforms;
237
239 void NotifyNewData(FBPOpenXRActionSkeletalData& ActionInfo, int NetUpdateRate);
240
241 FORCEINLINE void BlendBone(uint8 BoneToBlend, FBPOpenXRActionSkeletalData& ActionInfo, float & LerpVal)
242 {
243 ActionInfo.SkeletalTransforms[BoneToBlend].Blend(ActionInfo.OldSkeletalTransforms[BoneToBlend], NewTransforms[BoneToBlend], LerpVal);
244 }
246 void UpdateManager(float DeltaTime, FBPOpenXRActionSkeletalData& ActionInfo);
247
248 };
249
250 FTransformLerpManager LeftHandRepManager;
251 FTransformLerpManager RightHandRepManager;
252
253 UFUNCTION()
254 virtual void OnRep_SkeletalTransformLeft()
255 {
256 for (int i = 0; i < HandSkeletalActions.Num(); i++)
257 {
258 if (HandSkeletalActions[i].TargetHand == LeftHandRep.TargetHand)
259 {
260 HandSkeletalActions[i].OldSkeletalTransforms = HandSkeletalActions[i].SkeletalTransforms;
261
262 FBPSkeletalRepContainer::CopyReplicatedTo(LeftHandRep, HandSkeletalActions[i]);
263
264 if(bSmoothReplicatedSkeletalData)
265 LeftHandRepManager.NotifyNewData(HandSkeletalActions[i], ReplicationRateForSkeletalAnimations);
266 break;
267 }
268 }
269 }
270
271 UFUNCTION()
272 virtual void OnRep_SkeletalTransformRight()
273 {
274 for (int i = 0; i < HandSkeletalActions.Num(); i++)
275 {
276 if (HandSkeletalActions[i].TargetHand == RightHandRep.TargetHand)
277 {
278 HandSkeletalActions[i].OldSkeletalTransforms = HandSkeletalActions[i].SkeletalTransforms;
279
280 FBPSkeletalRepContainer::CopyReplicatedTo(RightHandRep, HandSkeletalActions[i]);
281
282 if (bSmoothReplicatedSkeletalData)
283 RightHandRepManager.NotifyNewData(HandSkeletalActions[i], ReplicationRateForSkeletalAnimations);
284 break;
285 }
286 }
287 }
288
289 // If we should replicate the skeletal transform data
290 UPROPERTY(EditAnywhere, Category = SkeletalData)
291 bool bReplicateSkeletalData;
292
293 // If true we will lerp between updates of the skeletal mesh transforms and smooth the result
294 UPROPERTY(EditAnywhere, Category = SkeletalData)
295 bool bSmoothReplicatedSkeletalData;
297 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalData)
298 float ReplicationRateForSkeletalAnimations;
299
300 // Used in Tick() to accumulate before sending updates, didn't want to use a timer in this case, also used for remotes to lerp position
301 float SkeletalNetUpdateCount;
302 // Used in Tick() to accumulate before sending updates, didn't want to use a timer in this case, also used for remotes to lerp position
303 float SkeletalUpdateCount;
304};
305
306USTRUCT()
307struct OPENXREXPANSIONPLUGIN_API FOpenXRAnimInstanceProxy : public FAnimInstanceProxy
308{
309public:
310 GENERATED_BODY()
311
314
316 virtual void PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds) override;
318public:
319
320 EVRSkeletalHandIndex TargetHand;
321 TArray<FBPOpenXRActionSkeletalData> HandSkeletalActionData;
322
323};
324
325UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType)
326class OPENXREXPANSIONPLUGIN_API UOpenXRAnimInstance : public UAnimInstance
328 GENERATED_BODY()
329
330public:
332 UPROPERTY(transient)
333 UOpenXRHandPoseComponent * OwningPoseComp;
334
335 FOpenXRAnimInstanceProxy AnimInstanceProxy;
337 virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override
339 return new FOpenXRAnimInstanceProxy(this);
340 //return &AnimInstanceProxy;
341 }
342
343 virtual void NativeBeginPlay() override;
345 //virtual void NativeInitializeAnimation() override;
346
347 UFUNCTION(BlueprintCallable, Category = "BoneMappings")
348 void InitializeCustomBoneMapping(UPARAM(ref) FBPOpenXRSkeletalMappingData & SkeletalMappingData);
349
350
351};
EVRSkeletalHandIndex
UENUM(BlueprintType)
EXRHandJointType
UENUM(BlueprintType)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOpenXRGestureDetected, const FName &, GestureDetected, int32, GestureIndex, EVRSkeletalHandIndex, ActionHandType)
UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType)
virtual FAnimInstanceProxy * CreateAnimInstanceProxy() override
FOpenXRAnimInstanceProxy AnimInstanceProxy
UOpenXRHandPoseComponent * OwningPoseComp
UPROPERTY(transient)
UCLASS(BlueprintType, Category = "VRGestures")
TArray< FOpenXRGesture > Gestures
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
FTransformLerpManager LeftHandRepManager
bool bSmoothReplicatedSkeletalData
UPROPERTY(EditAnywhere, Category = SkeletalData)
virtual void OnRep_SkeletalTransformLeft()
UFUNCTION()
TArray< FBPOpenXRActionSkeletalData > HandSkeletalActions
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
FBPSkeletalRepContainer RightHandRep
UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformRight)
bool bDetectGestures
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
bool bGetMockUpPoseForDebugging
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
bool bReplicateSkeletalData
UPROPERTY(EditAnywhere, Category = SkeletalData)
FBPSkeletalRepContainer LeftHandRep
UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformLeft)
UOpenXRGestureDatabase * GesturesDB
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
FOpenXRGestureEnded OnGestureEnded
UPROPERTY(BlueprintAssignable, Category = "VRGestures")
float ReplicationRateForSkeletalAnimations
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalData)
virtual void OnRep_SkeletalTransformRight()
UFUNCTION()
void SetDetectGestures(bool bNewDetectGestures)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
FOpenXRGestureDetected OnNewGestureDetected
UPROPERTY(BlueprintAssignable, Category = "VRGestures")
FTransformLerpManager RightHandRepManager
void Server_SendSkeletalTransforms(const FBPSkeletalRepContainer &SkeletalInfo)
UFUNCTION(Unreliable, Server, WithValidation)
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|OpenXR|HandSkeleton")
TArray< FTransform > OldSkeletalTransforms
UPROPERTY(BlueprintReadOnly, NotReplicated, Transient, Category = Default)
TArray< FTransform > SkeletalTransforms
UPROPERTY(BlueprintReadOnly, NotReplicated, Transient, Category = Default)
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|SteamVR|HandSkeleton")
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|OpenXR|HandSkeleton")
uint8 BoneCount
UPROPERTY(Transient, NotReplicated)
EVRSkeletalHandIndex TargetHand
UPROPERTY(Transient, NotReplicated)
bool bEnableUE4HandRepSavings
UPROPERTY(Transient, NotReplicated)
bool bAllowDeformingMesh
UPROPERTY(Transient, NotReplicated)
TArray< FTransform > SkeletalTransforms
UPROPERTY(Transient, NotReplicated)
static void CopyReplicatedTo(const FBPSkeletalRepContainer &Container, FBPOpenXRActionSkeletalData &Other)
TArray< FBPOpenXRActionSkeletalData > HandSkeletalActionData
USTRUCT(BlueprintType, Category = "VRGestures")
float Threshold
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture", meta = (ClampMin = "0....
EXRHandJointType IndexType
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "VRGesture")
FOpenXRGestureFingerPosition(FVector TipLoc, EXRHandJointType Type)
FVector Value
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
USTRUCT(BlueprintType, Category = "VRGestures")
FName Name
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
TArray< FOpenXRGestureFingerPosition > FingerValues
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGesture")
void NotifyNewData(FBPOpenXRActionSkeletalData &ActionInfo, int NetUpdateRate)
FORCEINLINE void BlendBone(uint8 BoneToBlend, FBPOpenXRActionSkeletalData &ActionInfo, float &LerpVal)