A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
OpenXRHandPoseComponent.cpp
Go to the documentation of this file.
1// Fill out your copyright notice in the Description page of Project Settings.
3#include "Net/UnrealNetwork.h"
4#include "MotionControllerComponent.h"
6
7#include "XRMotionControllerBase.h" // for GetHandEnumForSourceName()
8//#include "EngineMinimal.h"
9
10UOpenXRHandPoseComponent::UOpenXRHandPoseComponent(const FObjectInitializer& ObjectInitializer)
11 : Super(ObjectInitializer)
12{
13 PrimaryComponentTick.bCanEverTick = true;
14 PrimaryComponentTick.bStartWithTickEnabled = true;
15
20 bDetectGestures = true;
21 SetIsReplicatedByDefault(true);
23}
24
25void UOpenXRHandPoseComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
26{
27 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
28
29 // Skipping the owner with this as the owner will use the controllers location directly
30 DOREPLIFETIME_CONDITION(UOpenXRHandPoseComponent, LeftHandRep, COND_SkipOwner);
31 DOREPLIFETIME_CONDITION(UOpenXRHandPoseComponent, RightHandRep, COND_SkipOwner);
32}
33
34void UOpenXRHandPoseComponent::Server_SendSkeletalTransforms_Implementation(const FBPSkeletalRepContainer& SkeletalInfo)
35{
36 for (int i = 0; i < HandSkeletalActions.Num(); i++)
37 {
38 if (HandSkeletalActions[i].TargetHand == SkeletalInfo.TargetHand)
39 {
40 HandSkeletalActions[i].OldSkeletalTransforms = HandSkeletalActions[i].SkeletalTransforms;
41
43
45 {
46 LeftHandRep = SkeletalInfo;
49 }
50 else
51 {
52 RightHandRep = SkeletalInfo;
55 }
56
57 break;
58 }
59 }
60}
61
62bool UOpenXRHandPoseComponent::Server_SendSkeletalTransforms_Validate(const FBPSkeletalRepContainer& SkeletalInfo)
63{
64 return true;
65}
66
67void FOpenXRAnimInstanceProxy::PreUpdate(UAnimInstance* InAnimInstance, float DeltaSeconds)
68{
69 Super::PreUpdate(InAnimInstance, DeltaSeconds);
70
71 if (UOpenXRAnimInstance* OwningInstance = Cast<UOpenXRAnimInstance>(InAnimInstance))
72 {
73 if (OwningInstance->OwningPoseComp)
74 {
75 if (HandSkeletalActionData.Num() != OwningInstance->OwningPoseComp->HandSkeletalActions.Num())
76 {
77 HandSkeletalActionData.Empty(OwningInstance->OwningPoseComp->HandSkeletalActions.Num());
78
79 for(FBPOpenXRActionSkeletalData& actionInfo : OwningInstance->OwningPoseComp->HandSkeletalActions)
80 {
81 HandSkeletalActionData.Add(actionInfo);
82 }
83 }
84 else
85 {
86 for (int i = 0; i < OwningInstance->OwningPoseComp->HandSkeletalActions.Num(); ++i)
87 {
88 HandSkeletalActionData[i] = OwningInstance->OwningPoseComp->HandSkeletalActions[i];
89 }
90 }
91 }
92 }
93}
94
99
101{
102 /*if (UMotionControllerComponent * MotionParent = Cast<UMotionControllerComponent>(GetAttachParent()))
103 {
104 EControllerHand HandType;
105 if (!FXRMotionControllerBase::GetHandEnumForSourceName(MotionParent->MotionSource, HandType))
106 {
107 HandType = EControllerHand::Left;
108 }
109
110 for (int i = 0; i < HandSkeletalActions.Num(); i++)
111 {
112 if (HandType == EControllerHand::Left || HandType == EControllerHand::AnyHand)
113 HandSkeletalActions[i].SkeletalData.TargetHand = EVRSkeletalHandIndex::EActionHandIndex_Left;
114 else
115 HandSkeletalActions[i].SkeletalData.TargetHand = EVRSkeletalHandIndex::EActionHandIndex_Right;
116 }
117
118 }*/
119
120 Super::BeginPlay();
121}
122
123void UOpenXRHandPoseComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
124{
125 if (!IsLocallyControlled())
126 {
128 {
129 // Handle bone lerping here if we are replicating
131 {
133 {
134 if (actionInfo.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left)
135 {
136 LeftHandRepManager.UpdateManager(DeltaTime, actionInfo);
137 }
138 else
139 {
140 RightHandRepManager.UpdateManager(DeltaTime, actionInfo);
141 }
142 }
143 }
144
145
146 }
147 }
148 else // Get data and process
149 {
150 bool bGetCompressedTransforms = false;
152 {
153 SkeletalNetUpdateCount += DeltaTime;
155 {
157 bGetCompressedTransforms = true;
158 }
159 }
160
162 {
164 {
165 if (bGetCompressedTransforms)
166 {
167 if (GetNetMode() == NM_Client)
168 {
169 if (actionInfo.bHasValidData)
170 {
171 FBPSkeletalRepContainer ContainerSend;
172 ContainerSend.CopyForReplication(actionInfo);
173 Server_SendSkeletalTransforms(ContainerSend);
174 }
175 }
176 else
177 {
178 if (actionInfo.bHasValidData)
179 {
180 if (actionInfo.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left)
182 else
184 }
185 }
186 }
187 }
188
189 if (bDetectGestures && actionInfo.bHasValidData && actionInfo.SkeletalTransforms.Num() > 0 && GesturesDB != nullptr && GesturesDB->Gestures.Num() > 0)
190 {
191 DetectCurrentPose(actionInfo);
192 }
193 }
194 }
195
196 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
197}
198
200{
201
202 if (!HandSkeletalActions.Num())
203 return false;
204
205 // Default to the first hand element so that single length arrays work as is.
206 FBPOpenXRActionSkeletalData* HandSkeletalAction = nullptr;
207
208 // Now check for the specific passed in hand if this is a multi hand
209 for (int i = 0; i < HandSkeletalActions.Num(); ++i)
210 {
211 if (HandSkeletalActions[i].TargetHand == HandToSave)
212 {
213 HandSkeletalAction = &HandSkeletalActions[i];
214 break;
215 }
216 }
217
218 if (!HandSkeletalAction || !HandSkeletalAction->bHasValidData || HandSkeletalAction->SkeletalTransforms.Num() < EHandKeypointCount)
219 return false;
220
221 if (GesturesDB)
222 {
223 FOpenXRGesture NewGesture;
224
225 int32 FingerMap[5] =
226 {
232 };
233
234 FVector WristLoc = FVector::ZeroVector;
235
237 {
238 WristLoc = HandSkeletalAction->SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation().MirrorByVector(FVector::RightVector);
239 }
240 else
241 {
242 WristLoc = HandSkeletalAction->SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation();
243 }
244
245 for (int i = 0; i < 5; ++i)
246 {
248 {
249 NewGesture.FingerValues[i] = FOpenXRGestureFingerPosition(HandSkeletalAction->SkeletalTransforms[FingerMap[i]].GetLocation().MirrorByVector(FVector::RightVector) - WristLoc, (EXRHandJointType)FingerMap[i]);
250 }
251 else
252 {
253 NewGesture.FingerValues[i] = FOpenXRGestureFingerPosition(HandSkeletalAction->SkeletalTransforms[FingerMap[i]].GetLocation() - WristLoc, (EXRHandJointType)FingerMap[i]);
254 }
255 }
256
257 NewGesture.Name = RecordingName;
258 GesturesDB->Gestures.Add(NewGesture);
259
260 return true;
261 }
262
263 return false;
264}
265
266
268{
269 if (!GesturesDB || GesturesDB->Gestures.Num() < 1)
270 return false;
271
272 int32 FingerMap[5] =
273 {
279 };
280
281 FVector WristLoc = FVector::ZeroVector;
282
283 if (SkeletalAction.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left)
284 {
285 WristLoc = SkeletalAction.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation().MirrorByVector(FVector::RightVector);
286 }
287 else
288 {
289 WristLoc = SkeletalAction.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation();
290 }
291
292 // Early fill in an array to keep from performing math for each gesture
293 TArray<FVector> CurrentTips;
294 CurrentTips.AddUninitialized(5);
295 for (int i = 0; i < 5; ++i)
296 {
297 if (SkeletalAction.TargetHand == EVRSkeletalHandIndex::EActionHandIndex_Left)
298 {
299 CurrentTips[i] = SkeletalAction.SkeletalTransforms[FingerMap[i]].GetLocation().MirrorByVector(FVector::RightVector) - WristLoc;
300 }
301 else
302 {
303 CurrentTips[i] = SkeletalAction.SkeletalTransforms[FingerMap[i]].GetLocation() - WristLoc;
304 }
305 }
306
307 for (const FOpenXRGesture& Gesture : GesturesDB->Gestures)
308 {
309 // If not enough indexs to match curl values, or if this gesture requires finger splay and the controller can't do it
310 if (Gesture.FingerValues.Num() < 5 || SkeletalAction.SkeletalTransforms.Num() < EHandKeypointCount)
311 continue;
312
313 bool bDetectedPose = true;
314 for (int i = 0; i < 5; ++i)
315 {
316 FVector GestureV = Gesture.FingerValues[i].Value;
317 FVector CurrentV = CurrentTips[i];
318 FVector Difference = GestureV - CurrentV;
319
320 if (!Gesture.FingerValues[i].Value.Equals(CurrentTips[i], Gesture.FingerValues[i].Threshold))
321 {
322 bDetectedPose = false;
323 break;
324 }
325 }
326
327 if (bDetectedPose)
328 {
329 GestureOut = Gesture;
330 return true;
331 }
332 }
333
334 return false;
335}
336
338{
339 if (!GesturesDB || GesturesDB->Gestures.Num() < 1 || SkeletalAction.SkeletalTransforms.Num() < EHandKeypointCount)
340 return false;
341
342 FTransform BoneTransform = FTransform::Identity;
343
344 int32 FingerMap[5] =
345 {
351 };
352
353 FVector WristLoc = FVector::ZeroVector;
354
356 {
357 WristLoc = SkeletalAction.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation().MirrorByVector(FVector::RightVector);
358 }
359 else
360 {
361 WristLoc = SkeletalAction.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT].GetLocation();
362 }
363
364 // Early fill in an array to keep from performing math for each gesture
365 TArray<FVector> CurrentTips;
366 CurrentTips.AddUninitialized(5);
367 for (int i = 0; i < 5; ++i)
368 {
370 {
371 CurrentTips[i] = SkeletalAction.SkeletalTransforms[FingerMap[i]].GetLocation().MirrorByVector(FVector::RightVector) - WristLoc;
372 }
373 else
374 {
375 CurrentTips[i] = SkeletalAction.SkeletalTransforms[FingerMap[i]].GetLocation() - WristLoc;
376 }
377 }
378
379 for (auto GestureIterator = GesturesDB->Gestures.CreateConstIterator(); GestureIterator; ++GestureIterator)
380 {
381 const FOpenXRGesture &Gesture = *GestureIterator;
382
383 // If not enough indexs to match curl values, or if this gesture requires finger splay and the controller can't do it
384 if (Gesture.FingerValues.Num() < 5 || SkeletalAction.SkeletalTransforms.Num() < EHandKeypointCount)
385 continue;
386
387 bool bDetectedPose = true;
388 for (int i = 0; i < 5; ++i)
389 {
390 if (Gesture.FingerValues[i].Threshold <= 0.0f)
391 continue;
392
393 if (!Gesture.FingerValues[i].Value.Equals(CurrentTips[i], Gesture.FingerValues[i].Threshold))
394 {
395 bDetectedPose = false;
396 break;
397 }
398 }
399
400 if (bDetectedPose)
401 {
402 if (SkeletalAction.LastHandGesture != Gesture.Name)
403 {
404 if (SkeletalAction.LastHandGesture != NAME_None)
405 OnGestureEnded.Broadcast(SkeletalAction.LastHandGesture, SkeletalAction.LastHandGestureIndex, SkeletalAction.TargetHand);
406
407 SkeletalAction.LastHandGesture = Gesture.Name;
408 SkeletalAction.LastHandGestureIndex = GestureIterator.GetIndex();
409 OnNewGestureDetected.Broadcast(SkeletalAction.LastHandGesture, SkeletalAction.LastHandGestureIndex, SkeletalAction.TargetHand);
410
411 return true;
412 }
413 else
414 return false; // Same gesture
415 }
416 }
417
418 if (SkeletalAction.LastHandGesture != NAME_None)
419 {
420 OnGestureEnded.Broadcast(SkeletalAction.LastHandGesture, SkeletalAction.LastHandGestureIndex, SkeletalAction.TargetHand);
421 SkeletalAction.LastHandGesture = NAME_None;
422 SkeletalAction.LastHandGestureIndex = INDEX_NONE;
423 }
424
425 return false;
426}
427
435
437{
438 UpdateRate = (1.0f / NetUpdateRate);
439 if (bReplicatedOnce)
440 {
441 bLerping = true;
442 UpdateCount = 0.0f;
443 NewTransforms = ActionInfo.SkeletalTransforms;
444 }
445 else
446 {
447 bReplicatedOnce = true;
448 }
449}
450
452{
453 if (!ActionInfo.bHasValidData)
454 return;
455
456 if (bLerping)
457 {
458 UpdateCount += DeltaTime;
459 float LerpVal = FMath::Clamp(UpdateCount / UpdateRate, 0.0f, 1.0f);
460
461 if (LerpVal >= 1.0f)
462 {
463 bLerping = false;
464 UpdateCount = 0.0f;
465 ActionInfo.SkeletalTransforms = NewTransforms;
466 }
467 else
468 {
469 int32 BoneCountAdjustment = 5 + (ActionInfo.bEnableUE4HandRepSavings ? 4 : 0);
470 if ((NewTransforms.Num() < (EHandKeypointCount - BoneCountAdjustment)) || (NewTransforms.Num() != ActionInfo.SkeletalTransforms.Num() || NewTransforms.Num() != ActionInfo.OldSkeletalTransforms.Num()))
471 {
472 return;
473 }
474
475 ActionInfo.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_PALM_EXT] = FTransform::Identity;
476 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT, ActionInfo, LerpVal);
477
478 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_METACARPAL_EXT, ActionInfo, LerpVal);
479 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_PROXIMAL_EXT, ActionInfo, LerpVal);
480 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_DISTAL_EXT, ActionInfo, LerpVal);
481 //BlendBone((uint8)EVROpenXRBones::eBone_Thumb3, ActionInfo, LerpVal); // Technically can be projected instead of blended
482
483 if (!ActionInfo.bEnableUE4HandRepSavings)
484 {
485 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_METACARPAL_EXT, ActionInfo, LerpVal);
486 }
487 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_PROXIMAL_EXT, ActionInfo, LerpVal);
488 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_INTERMEDIATE_EXT, ActionInfo, LerpVal);
489 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_DISTAL_EXT, ActionInfo, LerpVal);
490 //BlendBone((uint8)EVROpenXRBones::eBone_IndexFinger4, ActionInfo, LerpVal); // Technically can be projected instead of blended
491
492 if (!ActionInfo.bEnableUE4HandRepSavings)
493 {
494 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_METACARPAL_EXT, ActionInfo, LerpVal);
495 }
496 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_PROXIMAL_EXT, ActionInfo, LerpVal);
497 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT, ActionInfo, LerpVal);
498 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_DISTAL_EXT, ActionInfo, LerpVal);
499 //BlendBone((uint8)EVROpenXRBones::eBone_IndexFinger4, ActionInfo, LerpVal); // Technically can be projected instead of blended
500
501 if (!ActionInfo.bEnableUE4HandRepSavings)
502 {
503 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_RING_METACARPAL_EXT, ActionInfo, LerpVal);
504 }
505 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_RING_PROXIMAL_EXT, ActionInfo, LerpVal);
506 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_RING_INTERMEDIATE_EXT, ActionInfo, LerpVal);
507 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_RING_DISTAL_EXT, ActionInfo, LerpVal);
508 //BlendBone((uint8)EVROpenXRBones::eBone_IndexFinger4, ActionInfo, LerpVal); // Technically can be projected instead of blended
509
510 if (!ActionInfo.bEnableUE4HandRepSavings)
511 {
512 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_METACARPAL_EXT, ActionInfo, LerpVal);
513 }
514 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_PROXIMAL_EXT, ActionInfo, LerpVal);
515 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT, ActionInfo, LerpVal);
516 BlendBone((int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_DISTAL_EXT, ActionInfo, LerpVal);
517 //BlendBone((uint8)EVROpenXRBones::eBone_IndexFinger4, ActionInfo, LerpVal); // Technically can be projected instead of blended
518
519 // These are copied from the 3rd joints as they use the same transform but a different root
520 // Don't want to waste cpu time blending these
521 //ActionInfo.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Aux_Thumb] = ActionInfo.SkeletalData.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Thumb2];
522 //ActionInfo.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Aux_IndexFinger] = ActionInfo.SkeletalData.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_IndexFinger3];
523 //ActionInfo.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Aux_MiddleFinger] = ActionInfo.SkeletalData.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_MiddleFinger3];
524 //ActionInfo.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Aux_RingFinger] = ActionInfo.SkeletalData.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_RingFinger3];
525 //ActionInfo.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_Aux_PinkyFinger] = ActionInfo.SkeletalData.SkeletalTransforms[(uint8)EVROpenXRBones::eBone_PinkyFinger3];
526 }
527 }
528}
529
531{
532 TargetHand = Other.TargetHand;
533
534 if (!Other.bHasValidData)
535 return;
536
537 bAllowDeformingMesh = Other.bAllowDeformingMesh;
538 bEnableUE4HandRepSavings = Other.bEnableUE4HandRepSavings;
539
540 // Instead of doing this, we likely need to lerp but this is for testing
541 //SkeletalTransforms = Other.SkeletalData.SkeletalTransforms;
542
543 if (Other.SkeletalTransforms.Num() < EHandKeypointCount)
544 {
545 SkeletalTransforms.Empty();
546 return;
547 }
548
549 int32 BoneCountAdjustment = 5 + (bEnableUE4HandRepSavings ? 4 : 0);
550
551 if (SkeletalTransforms.Num() != EHandKeypointCount - BoneCountAdjustment)
552 {
553 SkeletalTransforms.Reset(EHandKeypointCount - BoneCountAdjustment); // Minus bones we don't need
554 SkeletalTransforms.AddUninitialized(EHandKeypointCount - BoneCountAdjustment);
555 }
556
557 int32 idx = 0;
558 // Root is always identity
559 //SkeletalTransforms[0] = Other.SkeletalData.SkeletalTransforms[(uint8)EVROpenInputBones::eBone_Root]; // This has no pos right? Need to skip pos on it
560 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT];
561 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_METACARPAL_EXT];
562 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_PROXIMAL_EXT];
563 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_DISTAL_EXT];
564
565 if (!bEnableUE4HandRepSavings)
566 {
567 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_METACARPAL_EXT];
568 }
569 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_PROXIMAL_EXT];
570 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_INTERMEDIATE_EXT];
571 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_DISTAL_EXT];
572
573 if (!bEnableUE4HandRepSavings)
574 {
575 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_METACARPAL_EXT];
576 }
577 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_PROXIMAL_EXT];
578 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT];
579 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_DISTAL_EXT];
580
581 if (!bEnableUE4HandRepSavings)
582 {
583 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_METACARPAL_EXT];
584 }
585 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_PROXIMAL_EXT];
586 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_INTERMEDIATE_EXT];
587 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_DISTAL_EXT];
588
589 if (!bEnableUE4HandRepSavings)
590 {
591 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_METACARPAL_EXT];
592 }
593 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_PROXIMAL_EXT];
594 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT];
595 SkeletalTransforms[idx++] = Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_DISTAL_EXT];
596}
597
599{
600 int32 BoneCountAdjustment = 5 + (Container.bEnableUE4HandRepSavings ? 4 : 0);
601 if (Container.SkeletalTransforms.Num() < (EHandKeypointCount - BoneCountAdjustment))
602 {
603 Other.SkeletalTransforms.Empty();
604 Other.bHasValidData = false;
605 return;
606 }
607
608 Other.bAllowDeformingMesh = Container.bAllowDeformingMesh;
609 Other.bEnableUE4HandRepSavings = Container.bEnableUE4HandRepSavings;
610
611 // Instead of doing this, we likely need to lerp but this is for testing
612 //Other.SkeletalData.SkeletalTransforms = Container.SkeletalTransforms;
613
614 if (Other.SkeletalTransforms.Num() != EHandKeypointCount)
615 Other.SkeletalTransforms.Reset(EHandKeypointCount);
616 {
617 Other.SkeletalTransforms.AddUninitialized(EHandKeypointCount);
618 }
619
620 int32 idx = 0;
621
622 // Only fill in the ones that we care about
623 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_PALM_EXT] = FTransform::Identity; // Always identity
624 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_WRIST_EXT] = Container.SkeletalTransforms[idx++];
625
626 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_METACARPAL_EXT] = Container.SkeletalTransforms[idx++];
627 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_PROXIMAL_EXT] = Container.SkeletalTransforms[idx++];
628 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_THUMB_DISTAL_EXT] = Container.SkeletalTransforms[idx++];
629
630 if (!Container.bEnableUE4HandRepSavings)
631 {
632 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_METACARPAL_EXT] = Container.SkeletalTransforms[idx++];
633 }
634 else
635 {
636 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_METACARPAL_EXT] = FTransform::Identity;
637 }
638 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_PROXIMAL_EXT] = Container.SkeletalTransforms[idx++];
639 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_INTERMEDIATE_EXT] = Container.SkeletalTransforms[idx++];
640 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_INDEX_DISTAL_EXT] = Container.SkeletalTransforms[idx++];
641
642 if (!Container.bEnableUE4HandRepSavings)
643 {
644 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_METACARPAL_EXT] = Container.SkeletalTransforms[idx++];
645 }
646 else
647 {
648 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_METACARPAL_EXT] = FTransform::Identity;
649 }
650 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_PROXIMAL_EXT] = Container.SkeletalTransforms[idx++];
651 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT] = Container.SkeletalTransforms[idx++];
652 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_MIDDLE_DISTAL_EXT] = Container.SkeletalTransforms[idx++];
653
654 if (!Container.bEnableUE4HandRepSavings)
655 {
656 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_METACARPAL_EXT] = Container.SkeletalTransforms[idx++];
657 }
658 else
659 {
660 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_METACARPAL_EXT] = FTransform::Identity;
661 }
662 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_PROXIMAL_EXT] = Container.SkeletalTransforms[idx++];
663 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_INTERMEDIATE_EXT] = Container.SkeletalTransforms[idx++];
664 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_RING_DISTAL_EXT] = Container.SkeletalTransforms[idx++];
665
666 if (!Container.bEnableUE4HandRepSavings)
667 {
668 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_METACARPAL_EXT] = Container.SkeletalTransforms[idx++];
669 }
670 else
671 {
672 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_METACARPAL_EXT] = FTransform::Identity;
673 }
674 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_PROXIMAL_EXT] = Container.SkeletalTransforms[idx++];
675 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT] = Container.SkeletalTransforms[idx++];
676 Other.SkeletalTransforms[(int32)EXRHandJointType::OXR_HAND_JOINT_LITTLE_DISTAL_EXT] = Container.SkeletalTransforms[idx++];
677
678 Other.bHasValidData = true;
679}
680
681bool FBPSkeletalRepContainer::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
682{
683 bOutSuccess = true;
684
685 Ar.SerializeBits(&TargetHand, 1);
686 Ar.SerializeBits(&bAllowDeformingMesh, 1);
687 Ar.SerializeBits(&bEnableUE4HandRepSavings, 1);
688
689 int32 BoneCountAdjustment = 5 + (bEnableUE4HandRepSavings ? 4 : 0);
690 uint8 TransformCount = EHandKeypointCount - BoneCountAdjustment;
691
692 //Ar << TransformCount;
693
694 if (Ar.IsLoading())
695 {
696 SkeletalTransforms.Reset(TransformCount);
697 }
698
699 FVector Position = FVector::ZeroVector;
700 FRotator Rot = FRotator::ZeroRotator;
701
702 for (int i = 0; i < TransformCount; i++)
703 {
704 if (Ar.IsSaving())
705 {
706 if (bAllowDeformingMesh)
707 Position = SkeletalTransforms[i].GetLocation();
708
709 Rot = SkeletalTransforms[i].Rotator();
710 }
711
712 if (bAllowDeformingMesh)
713 bOutSuccess &= SerializePackedVector<10, 11>(Position, Ar);
714
715 Rot.SerializeCompressed(Ar); // Short? 10 bit?
716
717 if (Ar.IsLoading())
718 {
719 if (bAllowDeformingMesh)
720 SkeletalTransforms.Add(FTransform(Rot, Position));
721 else
722 SkeletalTransforms.Add(FTransform(Rot));
723 }
724 }
725
726 return bOutSuccess;
727}
728
730{
731 Super::NativeBeginPlay();
732
733 AActor* Owner = GetOwningComponent()->GetOwner();
734 UActorComponent* HandPoseComp = nullptr;
735
736 if (Owner)
737 {
738 HandPoseComp = Owner->GetComponentByClass(UOpenXRHandPoseComponent::StaticClass());
739
740 if (!HandPoseComp)
741 {
742 // We are also checking owner->owner in case hand mesh is in a sub actor
743 if (Owner->GetOwner())
744 {
745 HandPoseComp = Owner->GetOwner()->GetComponentByClass(UOpenXRHandPoseComponent::StaticClass());
746 }
747 }
748 }
749
750 if (!HandPoseComp)
751 {
752 return;
753 }
754
755 if (UOpenXRHandPoseComponent* HandComp = Cast<UOpenXRHandPoseComponent>(HandPoseComp))
756 {
757 OwningPoseComp = HandComp;
758 }
759}
760
761/*void UOpenXRAnimInstance::NativeInitializeAnimation()
762{
763 Super::NativeInitializeAnimation();
764
765 AActor* Owner = GetOwningComponent()->GetOwner();
766 UActorComponent* HandPoseComp = nullptr;
767
768 if (Owner)
769 {
770 HandPoseComp = Owner->GetComponentByClass(UOpenXRHandPoseComponent::StaticClass());
771
772 if (!HandPoseComp)
773 {
774 // We are also checking owner->owner in case hand mesh is in a sub actor
775 if (Owner->GetOwner())
776 {
777 HandPoseComp = Owner->GetOwner()->GetComponentByClass(UOpenXRHandPoseComponent::StaticClass());
778 }
779 }
780 }
781
782 if (!HandPoseComp)
783 {
784 return;
785 }
786
787 if (UOpenXRHandPoseComponent* HandComp = Cast<UOpenXRHandPoseComponent>(HandPoseComp))
788 {
789 OwningPoseComp = HandComp;
790 }
791}*/
792
794{
795 USkeleton* AssetSkeleton = this->CurrentSkeleton;//RequiredBones.GetSkeletonAsset();
796
797 if (AssetSkeleton)
798 {
799 FBoneContainer& RequiredBones = this->GetRequiredBones();
800 for (FBPOpenXRSkeletalPair& BonePair : SkeletalMappingData.BonePairs)
801 {
802 // Fill in the bone name for the reference
803 BonePair.ReferenceToConstruct.BoneName = BonePair.BoneToTarget;
804
805 // Init the reference
806 BonePair.ReferenceToConstruct.Initialize(AssetSkeleton);
807 BonePair.ReferenceToConstruct.CachedCompactPoseIndex = BonePair.ReferenceToConstruct.GetCompactPoseIndex(RequiredBones);
808
809 if ((BonePair.ReferenceToConstruct.CachedCompactPoseIndex != INDEX_NONE))
810 {
811 // Get our parent bones index
812 BonePair.ParentReference = RequiredBones.GetParentBoneIndex(BonePair.ReferenceToConstruct.CachedCompactPoseIndex);
813 }
814 }
815
816 if (UObject* OwningAsset = RequiredBones.GetAsset())
817 {
818 SkeletalMappingData.LastInitializedName = OwningAsset->GetFName();
819 }
820
821 SkeletalMappingData.bInitialized = true;
822 return;
823 }
824
825 SkeletalMappingData.bInitialized = false;
826}
EVRSkeletalHandIndex
UENUM(BlueprintType)
EXRHandJointType
UENUM(BlueprintType)
@ OXR_HAND_JOINT_MIDDLE_PROXIMAL_EXT
@ OXR_HAND_JOINT_RING_DISTAL_EXT
@ OXR_HAND_JOINT_RING_METACARPAL_EXT
@ OXR_HAND_JOINT_MIDDLE_METACARPAL_EXT
@ OXR_HAND_JOINT_RING_PROXIMAL_EXT
@ OXR_HAND_JOINT_RING_INTERMEDIATE_EXT
@ OXR_HAND_JOINT_LITTLE_METACARPAL_EXT
@ OXR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT
@ OXR_HAND_JOINT_INDEX_PROXIMAL_EXT
@ OXR_HAND_JOINT_INDEX_INTERMEDIATE_EXT
@ OXR_HAND_JOINT_LITTLE_PROXIMAL_EXT
@ OXR_HAND_JOINT_THUMB_METACARPAL_EXT
@ OXR_HAND_JOINT_MIDDLE_DISTAL_EXT
@ OXR_HAND_JOINT_LITTLE_DISTAL_EXT
@ OXR_HAND_JOINT_INDEX_DISTAL_EXT
@ OXR_HAND_JOINT_THUMB_DISTAL_EXT
@ OXR_HAND_JOINT_THUMB_PROXIMAL_EXT
@ OXR_HAND_JOINT_INDEX_METACARPAL_EXT
@ OXR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT
UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType)
virtual void NativeBeginPlay() override
void InitializeCustomBoneMapping(UPARAM(ref) FBPOpenXRSkeletalMappingData &SkeletalMappingData)
UFUNCTION(BlueprintCallable, Category = "BoneMappings")
static bool GetOpenXRHandPose(FBPOpenXRActionSkeletalData &HandPoseContainer, UOpenXRHandPoseComponent *HandPoseComponent, bool bGetMockUpPose=false)
UFUNCTION(BlueprintCallable, Category = "VRExpansionFunctions|OpenXR", meta = (bIgnoreSelf = "true"))
TArray< FOpenXRGesture > Gestures
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent))
FTransformLerpManager LeftHandRepManager
bool bSmoothReplicatedSkeletalData
UPROPERTY(EditAnywhere, Category = SkeletalData)
TArray< FBPOpenXRActionSkeletalData > HandSkeletalActions
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
FBPSkeletalRepContainer RightHandRep
UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformRight)
bool bDetectGestures
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override
bool bGetMockUpPoseForDebugging
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "SkeletalData|Actions")
bool SaveCurrentPose(FName RecordingName, EVRSkeletalHandIndex HandToSave=EVRSkeletalHandIndex::EActionHandIndex_Right)
UFUNCTION(BlueprintCallable, Category = "VRGestures")
bool bReplicateSkeletalData
UPROPERTY(EditAnywhere, Category = SkeletalData)
FBPSkeletalRepContainer LeftHandRep
UPROPERTY(Replicated, Transient, ReplicatedUsing = OnRep_SkeletalTransformLeft)
UOpenXRGestureDatabase * GesturesDB
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "VRGestures")
UOpenXRHandPoseComponent(const FObjectInitializer &ObjectInitializer)
FOpenXRGestureEnded OnGestureEnded
UPROPERTY(BlueprintAssignable, Category = "VRGestures")
float ReplicationRateForSkeletalAnimations
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = SkeletalData)
bool K2_DetectCurrentPose(UPARAM(ref) FBPOpenXRActionSkeletalData &SkeletalAction, FOpenXRGesture &GestureOut)
UFUNCTION(BlueprintCallable, Category = "VRGestures", meta = (DisplayName = "DetectCurrentPose"))
virtual void BeginPlay() override
FOpenXRGestureDetected OnNewGestureDetected
UPROPERTY(BlueprintAssignable, Category = "VRGestures")
bool DetectCurrentPose(FBPOpenXRActionSkeletalData &SkeletalAction)
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)
bool bEnableUE4HandRepSavings
UPROPERTY(EditAnywhere, NotReplicated, BlueprintReadWrite, Category = Default)
EVRSkeletalHandIndex TargetHand
UPROPERTY(EditAnywhere, NotReplicated, BlueprintReadWrite, Category = Default)
bool bHasValidData
UPROPERTY(NotReplicated, BlueprintReadOnly, Category = Default)
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|SteamVR|HandSkeleton")
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|SteamVR|HandSkeleton")
USTRUCT(BlueprintType, Category = "VRExpansionFunctions|OpenXR|HandSkeleton")
EVRSkeletalHandIndex TargetHand
UPROPERTY(Transient, NotReplicated)
bool bEnableUE4HandRepSavings
UPROPERTY(Transient, NotReplicated)
bool bAllowDeformingMesh
UPROPERTY(Transient, NotReplicated)
TArray< FTransform > SkeletalTransforms
UPROPERTY(Transient, NotReplicated)
void CopyForReplication(FBPOpenXRActionSkeletalData &Other)
static void CopyReplicatedTo(const FBPSkeletalRepContainer &Container, FBPOpenXRActionSkeletalData &Other)
bool NetSerialize(FArchive &Ar, class UPackageMap *Map, bool &bOutSuccess)
TArray< FBPOpenXRActionSkeletalData > HandSkeletalActionData
virtual void PreUpdate(UAnimInstance *InAnimInstance, float DeltaSeconds) override
USTRUCT(BlueprintType, Category = "VRGestures")
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)
void UpdateManager(float DeltaTime, FBPOpenXRActionSkeletalData &ActionInfo)