A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
HandSocketComponent.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
5#include "CoreMinimal.h"
7#include "VRBPDatatypes.h"
8#include "VRGripInterface.h"
10#include "GameplayTagContainer.h"
11#include "GameplayTagAssetInterface.h"
12#include "Components/SceneComponent.h"
13#include "Components/SkeletalMeshComponent.h"
14#include "Components/PoseableMeshComponent.h"
15#include "Animation/AnimSequence.h"
16#include "Animation/AnimInstance.h"
17#include "Animation/AnimInstanceProxy.h"
18#include "Animation/PoseSnapshot.h"
19#include "Misc/Guid.h"
20#include "HandSocketComponent.generated.h"
21
22DECLARE_LOG_CATEGORY_EXTERN(LogVRHandSocketComponent, Log, All);
23
24// Custom serialization version for the hand socket component
25struct VREXPANSIONPLUGIN_API FVRHandSocketCustomVersion
26{
27 enum Type
28 {
29 // Before any version changes were made in the plugin
30 BeforeCustomVersionWasAdded = 0,
31
32 // Added a set state tracker to handle in editor construction edge cases
33 HandSocketStoringSetState = 1,
34
35 // -----<new versions can be added above this line>-------------------------------------------------
37 LatestVersion = VersionPlusOne - 1
38 };
39
40 // The GUID for this custom version number
41 const static FGuid GUID;
42
43private:
45};
46
47
48UENUM()
49namespace EVRAxis
50{
51 enum Type
52 {
54 Y,
56 };
57}
64USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
65struct VREXPANSIONPLUGIN_API FBPVRHandPoseBonePair
66{
67 GENERATED_BODY()
68public:
69
70 // Distance to offset to get center of waist from tracked parent location
71 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings")
72 FName BoneName;
73
74 // Initial "Resting" location of the tracker parent, assumed to be the calibration zero
75 UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings")
76 FQuat DeltaPose;
77
78 FBoneReference ReferenceToConstruct;
79
81 {
82 BoneName = NAME_None;
83 DeltaPose = FQuat::Identity;
84 }
85
86 FORCEINLINE bool operator==(const FName& Other) const
87 {
88 return (BoneName == Other);
89 }
90};
92UCLASS(Blueprintable, ClassGroup = (VRExpansionPlugin), hideCategories = ("Component Tick", Events, Physics, Lod, "Asset User Data", Collision))
93class VREXPANSIONPLUGIN_API UHandSocketComponent : public USceneComponent, public IGameplayTagAssetInterface
94{
95 GENERATED_BODY()
96
97public:
98
99 UHandSocketComponent(const FObjectInitializer& ObjectInitializer);
101
102 //static get socket compoonent
103
104 //Axis to mirror on for this socket
105 UPROPERTY(EditDefaultsOnly, Category = "Hand Socket Data|Mirroring|Advanced")
106 TEnumAsByte<EVRAxis::Type> MirrorAxis;
107
108 // Axis to flip on when mirroring this socket
109 UPROPERTY(VisibleDefaultsOnly, Category = "Hand Socket Data|Mirroring|Advanced")
110 TEnumAsByte<EVRAxis::Type> FlipAxis;
112 // Relative placement of the hand to this socket
113 UPROPERTY(EditAnywhere, BlueprintReadWrite, /*DuplicateTransient,*/ Category = "Hand Socket Data")
114 FTransform HandRelativePlacement;
115
116 // Target Slot Prefix
117 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
118 FName SlotPrefix;
119
120 // If true the hand meshes relative transform will be de-coupled from the hand socket
121 UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Hand Socket Data")
122 bool bDecoupleMeshPlacement;
123
124 // If true we should only be used to snap mesh to us, not for the actual socket transform
125 // Will act like free gripping but the mesh will snap into position
126 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
127 bool bOnlySnapMesh;
128
129 // If true we will not create the mesh relative transform using the attach socket we are attached too
130 // Useful in cases where you aren't doing per bone gripping but want the socket to follow a bone that is animating
131 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
132 bool bIgnoreAttachBone;
133
134 // If true then this socket is left hand dominant and will flip for the right hand instead
135 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Hand Socket Data")
136 bool bLeftHandDominant;
137
138 // If true we will mirror ourselves automatically for the off hand
139 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data|Mirroring", meta = (DisplayName = "Flip For Off Hand"))
140 bool bFlipForLeftHand;
141
142 // If true, when we mirror the hand socket it will only mirror rotation, not position
143 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data|Mirroring", meta = (editcondition = "bFlipForLeftHand"))
144 bool bOnlyFlipRotation;
145
146 // If true then this hand socket will always be considered "in range" and checked against others for lowest distance
147 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
148 bool bAlwaysInRange;
149
150 // If true and there are multiple hand socket components in range with this setting
151 // Then the default behavior will compare closest rotation on them all to pick one
152 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
153 bool bMatchRotation;
154
155 // If true then the hand socket will not be considered for search operations
156 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
157 bool bDisabled;
158
159 // Snap distance to use if you want to override the defaults.
160 // Will be ignored if == 0.0f or bAlwaysInRange is true
161 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
162 float OverrideDistance;
163
164 // If true we are expected to have a list of custom deltas for bones to overlay onto our base pose
165 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
166 bool bUseCustomPoseDeltas;
167
168 // Custom rotations that are added on top of an animations bone rotation to make a final transform
169 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
170 TArray<FBPVRHandPoseBonePair> CustomPoseDeltas;
171
172 // Primary hand animation, for both hands if they share animations, right hand if they don't
173 // If using a custom pose delta this is expected to be the base pose
174 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
175 UAnimSequence* HandTargetAnimation;
176
177 // Scale to apply when mirroring the hand, adjust to visualize your off hand correctly
178 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Hand Visualization")
179 FVector MirroredScale;
180
181 FTransform GetBoneTransformAtTime(UAnimSequence* MyAnimSequence, /*float AnimTime,*/ int BoneIdx, bool bUseRawDataOnly);
183 // Returns the base target animation of the hand (if there is one)
184 UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
185 UAnimSequence* GetTargetAnimation();
186
194 UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
195 bool GetBlendedPoseSnapShot(FPoseSnapshot& PoseSnapShot, USkeletalMeshComponent* TargetMesh = nullptr, bool bSkipRootBone = false, bool bFlipHand = false);
196
205 UFUNCTION(BlueprintCallable, Category = "Hand Socket Data", meta = (bIgnoreSelf = "true"))
206 static bool GetAnimationSequenceAsPoseSnapShot(UAnimSequence * InAnimationSequence, FPoseSnapshot& OutPoseSnapShot, USkeletalMeshComponent* TargetMesh = nullptr, bool bSkipRootBone = false, bool bFlipHand = false);
207
208 // Returns the target relative transform of the hand
209 //UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
210 FTransform GetHandRelativePlacement();
211
212 inline void MirrorHandTransform(FTransform& ReturnTrans, FTransform& relTrans)
213 {
214 if (bOnlyFlipRotation)
216 ReturnTrans.SetTranslation(ReturnTrans.GetTranslation() - relTrans.GetTranslation());
217 ReturnTrans.Mirror(GetAsEAxis(MirrorAxis), GetCrossAxis());
218 ReturnTrans.SetTranslation(ReturnTrans.GetTranslation() + relTrans.GetTranslation());
219 }
220 else
221 {
222 ReturnTrans.Mirror(GetAsEAxis(MirrorAxis), GetCrossAxis());
224 }
225
226 inline TEnumAsByte<EAxis::Type> GetAsEAxis(TEnumAsByte<EVRAxis::Type> InAxis)
227 {
228 switch (InAxis)
229 {
230 case EVRAxis::X:
231 {
232 return EAxis::X;
233 }break;
234 case EVRAxis::Y:
235 {
236 return EAxis::Y;
237 }break;
238 case EVRAxis::Z:
239 {
240 return EAxis::Z;
241 }break;
242 }
243
244 return EAxis::X;
245 }
246
247
248 inline FVector GetMirrorVector()
249 {
250 switch (MirrorAxis)
251 {
252 case EVRAxis::Y:
253 {
254 return FVector::RightVector;
255 }break;
256 case EVRAxis::Z:
258 return FVector::UpVector;
259 }break;
260 case EVRAxis::X:
261 default:
262 {
263 return FVector::ForwardVector;
264 }break;
266 }
267
268 inline FVector GetFlipVector()
269 {
270 switch (FlipAxis)
271 {
272 case EVRAxis::Y:
273 {
274 return FVector::RightVector;
275 }break;
276 case EVRAxis::Z:
277 {
278 return FVector::UpVector;
279 }break;
280 case EVRAxis::X:
281 default:
282 {
283 return FVector::ForwardVector;
284 }break;
285 }
286 }
287
288 inline TEnumAsByte<EAxis::Type> GetCrossAxis()
289 {
290 // Checking against the sign now to avoid possible mobile precision issues
291 FVector SignVec = MirroredScale.GetSignVector();
292
293 if (SignVec.X < 0)
294 {
295 return EAxis::X;
296 }
297 else if (SignVec.Z < 0)
298 {
299 return EAxis::Z;
300 }
301 else if (SignVec.Y < 0)
302 {
303 return EAxis::Y;
304 }
305
306 return GetAsEAxis(FlipAxis);
308 /*if (FlipAxis == EVRAxis::Y)
309 {
310 return EAxis::Z;
311 }
312 else if (FlipAxis == EVRAxis::Z)
313 {
314 return EAxis::X;
315 }
316 else if (FlipAxis == EVRAxis::X)
317 {
318 return EAxis::Y;
319 }*/
320
321 //return EAxis::None;
322 }
323 // Returns the target relative transform of the hand to the gripped object
324 // If you want the transform mirrored you need to pass in which hand is requesting the information
325 // If UseParentScale is true then we will scale the value by the parent scale (generally only for when not using absolute hand scale)
326 // If UseMirrorScale is true then we will mirror the scale on the hand by the hand sockets mirror scale when appropriate (not for fully body!)
327 // if UseMirrorScale is false than the resulting transform will not have mirroring scale added so you may have to break the transform.
328 UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
329 FTransform GetMeshRelativeTransform(bool bIsRightHand, bool bUseParentScale = false, bool bUseMirrorScale = false);
330
331 // Returns the defined hand socket component (if it exists, you need to valid check the return!
332 // If it is a valid return you can then cast to your projects base socket class and handle whatever logic you want
333 UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
334 static UHandSocketComponent * GetHandSocketComponentFromObject(UObject * ObjectToCheck, FName SocketName)
335 {
336 if (AActor* OwningActor = Cast<AActor>(ObjectToCheck))
337 {
338 if (USceneComponent* OwningRoot = Cast<USceneComponent>(OwningActor->GetRootComponent()))
339 {
340 TArray<USceneComponent*> AttachChildren = OwningRoot->GetAttachChildren();
341 for (USceneComponent* AttachChild : AttachChildren)
342 {
343 if (AttachChild && AttachChild->IsA<UHandSocketComponent>() && AttachChild->GetFName() == SocketName)
344 {
345 return Cast<UHandSocketComponent>(AttachChild);
346 }
347 }
348 }
349 }
350 else if (USceneComponent* OwningRoot = Cast<USceneComponent>(ObjectToCheck))
351 {
352 TArray<USceneComponent*> AttachChildren = OwningRoot->GetAttachChildren();
353 for (USceneComponent* AttachChild : AttachChildren)
354 {
355 if (AttachChild && AttachChild->IsA<UHandSocketComponent>() && AttachChild->GetFName() == SocketName)
356 {
357 return Cast<UHandSocketComponent>(AttachChild);
358 }
359 }
360 }
361
362 return nullptr;
364
365 virtual FTransform GetHandSocketTransform(UGripMotionControllerComponent* QueryController, bool bIgnoreOnlySnapMesh = false);
366
367#if WITH_EDITOR
368 virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
369#endif
370#if WITH_EDITORONLY_DATA
371 static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
372 virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
373 void PoseVisualizationToAnimation(bool bForceRefresh = false);
374 bool bTickedPose;
375
376 UPROPERTY()
377 bool bDecoupled;
378#endif
379 virtual void Serialize(FArchive& Ar) override;
380 virtual void OnRegister() override;
381 virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override;
382
383 // ------------------------------------------------
384 // Gameplay tag interface
385 // ------------------------------------------------
386
388 virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override
389 {
390 TagContainer = GameplayTags;
391 }
392
394 UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags")
395 FGameplayTagContainer GameplayTags;
396
397 // End Gameplay Tag Interface
398
399 // Requires bReplicates to be true for the component
400 UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication")
401 bool bRepGameplayTags;
402
403 // Overrides the default of : true and allows for controlling it like in an actor, should be default of off normally with grippable components
404 UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication")
405 bool bReplicateMovement;
406
408#if WITH_EDITORONLY_DATA
409 //UPROPERTY(EditAnywhere, BlueprintReadOnly, Transient, Category = "Hand Visualization")
410 //class USkeletalMeshComponent* HandVisualizerComponent;
411 class UPoseableMeshComponent* HandVisualizerComponent;
412
413 UPROPERTY(EditAnywhere, BlueprintReadOnly, Transient, Category = "Hand Visualization")
414 class USkeletalMesh* VisualizationMesh;
415
416 // If we should show the visualization mesh
417 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Hand Visualization")
418 bool bShowVisualizationMesh;
419
420 // Show the visualization mirrored
421 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Hand Visualization")
422 bool bMirrorVisualizationMesh;
423
424 // If we should show the grip range of this socket (shows text if always in range)
425 // If override distance is zero then it attempts to infer the value from the parent architecture
426 UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Hand Visualization")
427 bool bShowRangeVisualization;
428
429 void PositionVisualizationMesh();
430 void HideVisualizationMesh();
431
432#endif
433
434#if WITH_EDITORONLY_DATA
435 // Material to apply to the hand
436 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Visualization")
437 UMaterial* HandPreviewMaterial;
438
439#endif
440};
441
442UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType)
443class VREXPANSIONPLUGIN_API UHandSocketAnimInstance : public UAnimInstance
444{
445 GENERATED_BODY()
446
447public:
448
449 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, transient, Category = "Socket Data")
450 UHandSocketComponent* OwningSocket;
451
452 virtual void NativeInitializeAnimation() override
453 {
454 Super::NativeInitializeAnimation();
455
456 OwningSocket = Cast<UHandSocketComponent>(GetOwningComponent()->GetAttachParent());
457 }
458};
DECLARE_LOG_CATEGORY_EXTERN(LogVRHandSocketComponent, Log, All)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = MotionController)
UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType)
virtual void NativeInitializeAnimation() override
UHandSocketComponent * OwningSocket
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, transient, Category = "Socket Data")
UCLASS(Blueprintable, ClassGroup = (VRExpansionPlugin), hideCategories = ("Component Tick",...
TArray< FBPVRHandPoseBonePair > CustomPoseDeltas
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
bool bUseCustomPoseDeltas
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
FGameplayTagContainer GameplayTags
UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "GameplayTags")
bool bOnlyFlipRotation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data|Mirroring",...
bool bOnlySnapMesh
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
TEnumAsByte< EVRAxis::Type > FlipAxis
UPROPERTY(VisibleDefaultsOnly, Category = "Hand Socket Data|Mirroring|Advanced")
bool bDisabled
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
TEnumAsByte< EAxis::Type > GetCrossAxis()
void MirrorHandTransform(FTransform &ReturnTrans, FTransform &relTrans)
bool bIgnoreAttachBone
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
UAnimSequence * HandTargetAnimation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
TEnumAsByte< EAxis::Type > GetAsEAxis(TEnumAsByte< EVRAxis::Type > InAxis)
bool bMatchRotation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
float OverrideDistance
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
bool bFlipForLeftHand
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data|Mirroring",...
bool bRepGameplayTags
UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication")
bool bLeftHandDominant
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Hand Socket Data")
FName SlotPrefix
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
bool bDecoupleMeshPlacement
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Hand Socket Data")
static UHandSocketComponent * GetHandSocketComponentFromObject(UObject *ObjectToCheck, FName SocketName)
UFUNCTION(BlueprintCallable, Category = "Hand Socket Data")
TEnumAsByte< EVRAxis::Type > MirrorAxis
UPROPERTY(EditDefaultsOnly, Category = "Hand Socket Data|Mirroring|Advanced")
virtual void GetOwnedGameplayTags(FGameplayTagContainer &TagContainer) const override
bool bAlwaysInRange
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
FTransform HandRelativePlacement
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Socket Data")
FVector MirroredScale
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Hand Visualization")
bool bReplicateMovement
UPROPERTY(EditAnywhere, Replicated, BlueprintReadWrite, Category = "VRGripInterface|Replication")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")
FName BoneName
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings")
FBoneReference ReferenceToConstruct
FQuat DeltaPose
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Settings")
FORCEINLINE bool operator==(const FName &Other) const