A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
ParentRelativeAttachmentComponent.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"
6#include "Engine/Engine.h"
8#include "IXRTrackingSystem.h"
9#include "Components/ShapeComponent.h"
11#include "ParentRelativeAttachmentComponent.generated.h"
12
14class AVRCharacter;
15
16// Type of rotation sampling to use
17UENUM(BlueprintType)
18enum class EVR_PRC_RotationMethod : uint8
19{
20 // Rotate purely to the HMD yaw, default mode
21 PRC_ROT_HMD UMETA(DisplayName = "HMD rotation"),
22
23 // Rotate to a blend between the HMD and Controller facing
24 PRC_ROT_HMDControllerBlend UMETA(DisplayName = "ROT HMD Controller Blend"),
25
26 // Rotate to the controllers with behind the back detection, clamp within neck limit
27 PRC_ROT_ControllerHMDClamped UMETA(DisplayName = "Controller Clamped to HMD")
28};
29
30
37UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
38class VREXPANSIONPLUGIN_API UParentRelativeAttachmentComponent : public USceneComponent, public IVRTrackedParentInterface
39{
40 GENERATED_BODY()
41
42public:
43 UParentRelativeAttachmentComponent(const FObjectInitializer& ObjectInitializer);
44 virtual void InitializeComponent() override;
45
46 // Rotation method to use for facing calulations
47 //UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
48 //EVR_PRC_RotationMethod YawRotationMethod;
49
50 // Angle tolerance before we lerp / snap to the new rotation
51 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary", meta = (ClampMin = "0", UIMin = "0"))
52 float YawTolerance;
53
54 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary", meta = (ClampMin = "0", UIMin = "0"))
55 float LerpSpeed;
56
57 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
58 bool bLerpTransition;
59
60 float LastRot;
61 float LastLerpVal;
62 float LerpTarget;
63 bool bWasSetOnce;
64 FTransform LeftControllerTrans;
65 FTransform RightControllerTrans;
66
67 // If true uses feet/bottom of the capsule as the base Z position for this component instead of the HMD/Camera Z position
68 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
69 bool bUseFeetLocation;
70
71 // An additional value added to the relative position of the PRC
72 // Can be used to offset the floor, or component heights if needed
73 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
74 FVector CustomOffset;
75
76 // If true will subtract the HMD's location from the position, useful for if the actors base is set to the HMD location always (simple character).
77 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
78 bool bOffsetByHMD;
80 // If true, will not set rotation every frame, only position
81 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
82 bool bIgnoreRotationFromParent;
84 // If true, this component will not perform logic in its tick, it will instead allow the character movement component to move it (unless the CMC is inactive, then it will go back to self managing)
85 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
86 bool bUpdateInCharacterMovement;
87
88 // If valid will use this as the tracked parent instead of the HMD / Parent
89 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRTrackedParentInterface")
90 FBPVRWaistTracking_Info OptionalWaistTrackingParent;
92 virtual void SetTrackedParent(UPrimitiveComponent * NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode) override
93 {
94 IVRTrackedParentInterface::Default_SetTrackedParent_Impl(NewParentComponent, WaistRadius, WaistTrackingMode, OptionalWaistTrackingParent, this);
95 }
96
97 UPROPERTY()
98 TWeakObjectPtr<AVRCharacter> AttachChar;
99 UPROPERTY()
100 TWeakObjectPtr<AVRBaseCharacter> AttachBaseChar;
101
102 void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
103
104 virtual void OnAttachmentChanged() override;
105 void UpdateTracking(float DeltaTime);
106
107 bool IsLocallyControlled() const
109 // I like epics implementation better than my own
110 const AActor* MyOwner = GetOwner();
111 return MyOwner->HasLocalNetOwner();
112 //const APawn* MyPawn = Cast<APawn>(MyOwner);
113 //return MyPawn ? MyPawn->IsLocallyControlled() : (MyOwner->Role == ENetRole::ROLE_Authority);
114 }
115
116 // Sets the rotation and location depending on the control variables. Trying to remove some code duplication here
117 inline void SetRelativeRotAndLoc(FVector NewRelativeLocation, FRotator NewRelativeRotation, float DeltaTime)
118 {
119
120 RunSampling(NewRelativeRotation, NewRelativeLocation);
121
122 if (bUseFeetLocation)
123 {
124 if (!bIgnoreRotationFromParent)
125 {
126 SetRelativeLocationAndRotation(
127 FVector(NewRelativeLocation.X, NewRelativeLocation.Y, 0.0f) + CustomOffset,
128 GetCalculatedRotation(NewRelativeRotation, DeltaTime)
129 );
130 }
131 else
133 SetRelativeLocation(FVector(NewRelativeLocation.X, NewRelativeLocation.Y, 0.0f) + CustomOffset);
135 }
136 else
137 {
138 if (!bIgnoreRotationFromParent)
139 {
140 SetRelativeLocationAndRotation(
141 NewRelativeLocation + CustomOffset,
142 GetCalculatedRotation(NewRelativeRotation, DeltaTime)
143 ); // Use the HMD height instead
144 }
145 else
147 SetRelativeLocation(NewRelativeLocation + CustomOffset); // Use the HMD height instead
148 }
149 }
150 }
151
152 FQuat GetCalculatedRotation(FRotator InverseRot, float DeltaTime)
154 FRotator FinalRot = FRotator::ZeroRotator;
155
156 if (FPlatformMath::Abs(FRotator::ClampAxis(InverseRot.Yaw) - LastRot) < YawTolerance) // This is never true with the default value of 0.0f
157 {
158 if (!bWasSetOnce)
159 {
160 LastRot = FRotator::ClampAxis(InverseRot.Yaw);
161 LastLerpVal = LastRot;
162 LerpTarget = LastRot;
163 bWasSetOnce = true;
164 }
165
166 if (bLerpTransition && !FMath::IsNearlyEqual(LastLerpVal, LerpTarget))
167 {
168 LastLerpVal = FMath::FixedTurn(LastLerpVal, LerpTarget, LerpSpeed * DeltaTime);
169 FinalRot = FRotator(0, LastLerpVal, 0);
170 }
171 else
172 {
173 FinalRot = FRotator(0, LastRot, 0);
174 LastLerpVal = LastRot;
175 }
176 }
177 else
178 {
179 // If we are using a snap threshold
180 if (!FMath::IsNearlyZero(YawTolerance))
181 {
182 LerpTarget = FRotator::ClampAxis(InverseRot.Yaw);
183 LastLerpVal = FMath::FixedTurn(/*LastRot*/LastLerpVal, LerpTarget, LerpSpeed * DeltaTime);
184 FinalRot = FRotator(0, LastLerpVal, 0);
185 }
186 else // If we aren't then just directly set it to the correct rotation
187 {
188 FinalRot = FRotator(0, FRotator::ClampAxis(InverseRot.Yaw), 0);
189 }
190
191 LastRot = FRotator::ClampAxis(InverseRot.Yaw);
192 }
193
194 return FinalRot.Quaternion();
195 }
196
197
199 void RunSampling(FRotator &HMDRotation, FVector &HMDLocation)
200 {
201 /*switch(YawRotationMethod)
202 {
203 case EVR_PRC_RotationMethod::PRC_ROT_HMD:
204 {
205 return;
206 }break;
207
208 case EVR_PRC_RotationMethod::PRC_ROT_HMDControllerBlend:
209 {
210 return;
211 }break;
212
213 case EVR_PRC_RotationMethod::PRC_ROT_ControllerHMDClamped:
214 {
215 GetEstShoulderRotation(HMDRotation, HMDLocation);
216 return;
217 }break;
218 }*/
219
220 }
221
222 // Get combined direction angle up
223 void GetEstShoulderRotation(FRotator &InputHMDRotation, FVector &InputHMDLocation)
224 {
225 float WorldToMeters = GetWorld() ? GetWorld()->GetWorldSettings()->WorldToMeters : 100.0f;
226
227 // Position shoulder (neck)
228 FTransform shoulder = FTransform::Identity;
229 FVector headNeckDirectionVector = FVector(-.05f, 0.f, -1.f);
230 FVector neckShoulderDistance = FVector(-0.02f, 0.f, -.15f) * WorldToMeters; // World To Meters idealy
231 float headNeckDistance = 0.03f * WorldToMeters; // World To Meters idealy
232
233 FVector headNeckOffset = InputHMDRotation.RotateVector(headNeckDirectionVector);
234 FVector targetPosition = InputHMDLocation + headNeckOffset * headNeckDistance;
235 shoulder.SetLocation(targetPosition + InputHMDRotation.RotateVector(neckShoulderDistance));
236
237 //DrawDebugSphere(GetWorld(), (shoulder * GetAttachParent()->GetComponentTransform()).GetLocation(), 4.0f, 32, FColor::White);
238 return;
239
240
241 /*if (IsLocallyControlled() && GEngine->XRSystem.IsValid())
242 {
243 FVector Position = GetRelativeLocation();
244 FRotator Orientation = GetRelativeRotation();
246 if (AttachBaseChar.IsValid())
247 {
248 if (AttachBaseChar->LeftMotionController)
249 {
250 const bool bNewTrackedState = AttachBaseChar->LeftMotionController->GripPollControllerState(Position, Orientation, WorldToMeters);
251 bool bTracked = bNewTrackedState && CurrentTrackingStatus != ETrackingStatus::NotTracked;
252
253 if (bTracked)
254 {
255 LeftControllerTrans = FTransform(Position, Orientation);
256 }
257 }
258
259 if (AttachBaseChar->RightMotionController)
260 {
261 const bool bNewTrackedState = AttachBaseChar->RightMotionController->GripPollControllerState(Position, Orientation, WorldToMeters);
262 bool bTracked = bNewTrackedState && CurrentTrackingStatus != ETrackingStatus::NotTracked;
263
264 if (bTracked)
265 {
266 RightControllerTrans = FTransform(Position, Orientation);
267 }
268 }
270 }
271 else if (AttachBaseChar.IsValid())
272 {
273 LeftControllerTrans = AttachBaseChar->LeftMotionController->GetRelativeTransform();
274 RightControllerTrans = AttachBaseChar->RightMotionController->GetRelativeTransform();
275 }
276
277 FVector LeftHand = LeftControllerTrans.GetLocation();
278 FVector RightHand = RightControllerTrans.GetLocation();
279
280 //FRotator LeveledRel = CurrentTransforms.PureCameraYaw;
281
282 FVector DistLeft = LeftHand - shoulder.Transform.GetLocation();
283 FVector DistRight = RightHand - shoulder.Transform.GetLocation();
284
285 if (bIgnoreZPos)
286 {
287 DistLeft.Z = 0.0f;
288 DistRight.Z = 0.0f;
289 }
290
291 FVector DirLeft = DistLeft.GetSafeNormal();
292 FVector DirRight = DistRight.GetSafeNormal();
293
294 FVector CombinedDir = DirLeft + DirRight;
295 float FinalRot = FMath::RadiansToDegrees(FMath::Atan2(CombinedDir.Y, CombinedDir.X));
296
297 DetectHandsBehindHead(FinalRot, InputHMDRotation);
298 ClampHeadRotationDelta(FinalRot, InputHMDRotation);
299
300 return FinalRot;*/
301 }
302
303 void DetectHandsBehindHead(float& TargetRot, FRotator HMDRotation)
304 {
305 /*float delta = FRotator::ClampAxis(FMath::FindDeltaAngleDegrees(TargetRot, LastTargetRot));// FRotator::ClampAxis(TargetRot - LastTargetRot);
306
307 if (delta > 150.f && delta < 210.0f && !FMath::IsNearlyZero(LastTargetRot) && !bClampingHeadRotation)
308 {
309 bHandsBehindHead = !bHandsBehindHead;
310 if (bHandsBehindHead)
311 {
312 BehindHeadAngle = TargetRot;
313 }
314 else
315 {
316 BehindHeadAngle = 0.f;
317 }
318 }
319 else if (bHandsBehindHead)
320 {
321 float delta2 = FMath::Abs(FMath::FindDeltaAngleDegrees(TargetRot, BehindHeadAngle));
322
323 if (delta2 > 90.f)
324 {
325 bHandsBehindHead = !bHandsBehindHead;
326 BehindHeadAngle = 0.f;
327 }
328 }
329
330 LastTargetRot = TargetRot;
331
332 if (bHandsBehindHead)
333 {
334 TargetRot += 180.f;
335 }*/
336 }
337
338 // Clamp head rotation delta yaw
339 void ClampHeadRotationDelta(float& TargetRotation, FRotator HMDRotation)
340 {
341 /*float HeadRotation = FRotator::ClampAxis(CurrentTransforms.PureCameraYaw.Yaw);
342 float cTargetRotation = FRotator::ClampAxis(TargetRotation);
343
344 float delta = HeadRotation - cTargetRotation;
345
346 if ((delta > 80.f && delta < 180.f) || (delta < -180.f && delta >= -360.f + 80))
347 {
348 TargetRotation = HeadRotation - 80.f;
349 bClampingHeadRotation = true;
350 }
351 else if ((delta < -80.f && delta > -180.f) || (delta > 180.f && delta < 360.f - 80.f))
352 {
353 TargetRotation = HeadRotation + 80.f;
354 bClampingHeadRotation = true;
355 }
356 else
357 {
358 bClampingHeadRotation = false;
359 }*/
360 }
361};
362
EVR_PRC_RotationMethod
UENUM(BlueprintType)
EBPVRWaistTrackingMode
UENUM(Blueprintable)
UCLASS()
Definition VRCharacter.h:23
static void Default_SetTrackedParent_Impl(UPrimitiveComponent *NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode, FBPVRWaistTracking_Info &OptionalWaistTrackingParent, USceneComponent *Self)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
TWeakObjectPtr< AVRCharacter > AttachChar
UPROPERTY()
void SetRelativeRotAndLoc(FVector NewRelativeLocation, FRotator NewRelativeRotation, float DeltaTime)
void DetectHandsBehindHead(float &TargetRot, FRotator HMDRotation)
TWeakObjectPtr< AVRBaseCharacter > AttachBaseChar
UPROPERTY()
void ClampHeadRotationDelta(float &TargetRotation, FRotator HMDRotation)
FBPVRWaistTracking_Info OptionalWaistTrackingParent
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRTrackedParentInterface")
bool bUseFeetLocation
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
FVector CustomOffset
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bOffsetByHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
void RunSampling(FRotator &HMDRotation, FVector &HMDLocation)
bool bIgnoreRotationFromParent
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bUpdateInCharacterMovement
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
void GetEstShoulderRotation(FRotator &InputHMDRotation, FVector &InputHMDLocation)
bool bLerpTransition
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
virtual void SetTrackedParent(UPrimitiveComponent *NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode) override
UFUNCTION(BlueprintCallable, Category = "VRTrackedParentInterface")
float YawTolerance
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary", meta = (ClampMin = "0",...
FQuat GetCalculatedRotation(FRotator InverseRot, float DeltaTime)
float LerpSpeed
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary", meta = (ClampMin = "0",...
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")