A Demo Project for the UnrealEngineSDK
Loading...
Searching...
No Matches
VRRootComponent.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 "Engine/Engine.h"
6#include "Components/ShapeComponent.h"
8#include "VRBaseCharacter.h"
10#include "GameFramework/PhysicsVolume.h"
11#include "VRRootComponent.generated.h"
12
13//For UE4 Profiler ~ Stat Group
14//DECLARE_STATS_GROUP(TEXT("VRPhysicsUpdate"), STATGROUP_VRPhysics, STATCAT_Advanced);
15
16//class AVRBaseCharacter;
17
18DECLARE_LOG_CATEGORY_EXTERN(LogVRRootComponent, Log, All);
19
20DECLARE_STATS_GROUP(TEXT("VRRootComponent"), STATGROUP_VRRootComponent, STATCAT_Advanced);
21DECLARE_CYCLE_STAT(TEXT("VR Root Set Half Height"), STAT_VRRootSetHalfHeight, STATGROUP_VRRootComponent);
22DECLARE_CYCLE_STAT(TEXT("VR Root Set Capsule Size"), STAT_VRRootSetCapsuleSize, STATGROUP_VRRootComponent);
23
28UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
29class VREXPANSIONPLUGIN_API UVRRootComponent : public UCapsuleComponent, public IVRTrackedParentInterface
30{
31 GENERATED_BODY()
33public:
34 UVRRootComponent(const FObjectInitializer& ObjectInitializer);
35
36 friend class FDrawCylinderSceneProxy;
37
38 bool bCalledUpdateTransform;
40 // Overriding this and applying the offset to world position for the elements
41 virtual void GetNavigationData(FNavigationRelevantData& Data) const override;
42
43 FORCEINLINE void GenerateOffsetToWorld(bool bUpdateBounds = true, bool bGetPureYaw = true);
44
45 // If valid will use this as the tracked parent instead of the HMD / Parent
46 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRTrackedParentInterface")
47 FBPVRWaistTracking_Info OptionalWaistTrackingParent;
48
49 virtual void SetTrackedParent(UPrimitiveComponent * NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode) override
50 {
51 IVRTrackedParentInterface::Default_SetTrackedParent_Impl(NewParentComponent, WaistRadius, WaistTrackingMode, OptionalWaistTrackingParent, this);
52 }
53
61 UFUNCTION(BlueprintCallable, Category = "Components|Capsule")
62 virtual void SetCapsuleSizeVR(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps = true);
63
64 // Used to update the capsule half height and calculate the new offset value for VR
65 UFUNCTION(BlueprintCallable, Category = "Components|Capsule")
66 void SetCapsuleHalfHeightVR(float HalfHeight, bool bUpdateOverlaps = true);
67
68 inline void OnUpdateTransform_Public(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None)
69 {
70 OnUpdateTransform(UpdateTransformFlags, Teleport);
71 if (bNavigationRelevant && bRegistered)
72 {
73 UpdateNavigationData();
74 PostUpdateNavigationData();
75 }
76 }
77
78 virtual void SetSimulatePhysics(bool bSimulate) override;
79
80protected:
81 virtual bool MoveComponentImpl(const FVector& Delta, const FQuat& NewRotation, bool bSweep, FHitResult* OutHit = NULL, EMoveComponentFlags MoveFlags = MOVECOMP_NoFlags, ETeleportType Teleport = ETeleportType::None) override;
82 virtual void OnUpdateTransform(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport = ETeleportType::None) override;
83
84 void SendPhysicsTransform(ETeleportType Teleport);
85 virtual bool UpdateOverlapsImpl(const TOverlapArrayView* NewPendingOverlaps = nullptr, bool bDoNotifies = true, const TOverlapArrayView* OverlapsAtEndLocation = nullptr) override;
86
88 template<typename AllocatorType>
89 bool ConvertRotationOverlapsToCurrentOverlaps(TArray<FOverlapInfo, AllocatorType>& OutOverlapsAtEndLocation, const TOverlapArrayView& CurrentOverlaps);
90
91 template<typename AllocatorType>
92 bool GetOverlapsWithActor_Template(const AActor* Actor, TArray<FOverlapInfo, AllocatorType>& OutOverlaps) const;
93
95 template<typename AllocatorType>
96 bool ConvertSweptOverlapsToCurrentOverlaps(TArray<FOverlapInfo, AllocatorType>& OutOverlapsAtEndLocation, const TOverlapArrayView& SweptOverlaps, int32 SweptOverlapsIndex, const FVector& EndLocation, const FQuat& EndRotationQuat);
97
98
99public:
100 void BeginPlay() override;
101 virtual void InitializeComponent() override;
102
103 bool IsLocallyControlled() const;
104
105 UPROPERTY(BlueprintReadWrite, Transient, Category = "VRExpansionLibrary")
106 USceneComponent * TargetPrimitiveComponent;
107
108 //UPROPERTY(BlueprintReadWrite, Transient, Category = "VRExpansionLibrary")
109 AVRBaseCharacter * owningVRChar;
110
111 //UPROPERTY(BlueprintReadWrite, Transient, Category = "VRExpansionLibrary")
112 //UCapsuleComponent * VRCameraCollider;
113
114 FVector DifferenceFromLastFrame;
115 //UPROPERTY(BlueprintReadOnly, Transient, Category = "VRExpansionLibrary")
116 FTransform OffsetComponentToWorld;
117
118 // Used to offset the collision (IE backwards from the player slightly.
119 // The default 2.15 Z offset is to account for floor hover from the character movement component.
120 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
121 FVector VRCapsuleOffset;
122
123 // If true we will stop tracking the camera / hmd until enabled again
124 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
125 bool bPauseTracking;
127 UFUNCTION(BlueprintCallable, Category = "VRExpansionLibrary")
128 void SetTrackingPaused(bool bPaused);
129
130 // #TODO: Test with 100.f rounding to make sure it isn't noticable, currently that is what it is
131 // 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).
132 /*UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ReplicatedCamera")
133 bool bOffsetByHMD;
134 */
135
136
137
138 // #TODO: See if making this multiplayer compatible is viable
139 // Offsets capsule to be centered on HMD - currently NOT multiplayer compatible
140 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
141 bool bCenterCapsuleOnHMD;
143 // Allows the root component to be blocked by simulating objects (default off due to sickness inducing stuttering).
144 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
145 bool bAllowSimulatingCollision;
146
147 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
148 bool bUseWalkingCollisionOverride;
149
150 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
151 TEnumAsByte<ECollisionChannel> WalkingCollisionOverride;
152
153 /*ECollisionChannel GetVRCollisionObjectType()
154 {
155 if (bUseWalkingCollisionOverride)
156 return WalkingCollisionOverride;
157 else
158 return GetCollisionObjectType();
159 }*/
160
161 FVector curCameraLoc;
162 FRotator curCameraRot;
163 FRotator StoredCameraRotOffset;
164
165 FVector lastCameraLoc;
166 FRotator lastCameraRot;
167
168 // While misnamed, is true if we collided with a wall/obstacle due to the HMDs movement in this frame (not movement components)
169 UPROPERTY(BlueprintReadOnly, Category = "VRExpansionLibrary")
170 bool bHadRelativeMovement;
171
172 FPrimitiveSceneProxy* CreateSceneProxy() override;
173 void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
174
175 virtual void UpdatePhysicsVolume(bool bTriggerNotifiers) override;
176
177 inline bool AreWeOverlappingVolume(APhysicsVolume* V)
178 {
179 bool bInsideVolume = true;
180 if (!V->bPhysicsOnContact)
182 FVector ClosestPoint(0.f);
183 // If there is no primitive component as root we consider you inside the volume. This is odd, but the behavior
184 // has existed for a long time, so keeping it this way
185 UPrimitiveComponent* RootPrimitive = Cast<UPrimitiveComponent>(V->GetRootComponent());
186 if (RootPrimitive)
187 {
188 float DistToCollisionSqr = -1.f;
189 if (RootPrimitive->GetSquaredDistanceToCollision(OffsetComponentToWorld.GetTranslation(), DistToCollisionSqr, ClosestPoint))
190 {
191 bInsideVolume = (DistToCollisionSqr == 0.f);
192 }
193 else
194 {
195 bInsideVolume = false;
196 }
197 }
198 }
199
200 return bInsideVolume;
201 }
202
203public:
204 // Begin UObject interface
205#if WITH_EDITOR
206 virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
207 void PreEditChange(FProperty* PropertyThatWillChange);
208#endif // WITH_EDITOR
209 // End UObject interface
211 virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const override;
212
213 private:
215};
216
218// Have to declare inlines here for blueprint
219void inline UVRRootComponent::GenerateOffsetToWorld(bool bUpdateBounds, bool bGetPureYaw)
220{
221 FRotator CamRotOffset;
222
223 if (bGetPureYaw)
224 CamRotOffset = StoredCameraRotOffset;//UVRExpansionFunctionLibrary::GetHMDPureYaw_I(curCameraRot);
225 else
226 CamRotOffset = curCameraRot;
227
228 /*if(bOffsetByHMD)
229 {
230 OffsetComponentToWorld = FTransform(CamRotOffset.Quaternion(), FVector(0, 0, bCenterCapsuleOnHMD ? curCameraLoc.Z : CapsuleHalfHeight) + CamRotOffset.RotateVector(VRCapsuleOffset), FVector(1.0f)) * GetComponentTransform();
231 }
232 else*/
233 {
234 OffsetComponentToWorld = FTransform(CamRotOffset.Quaternion(), FVector(curCameraLoc.X, curCameraLoc.Y, bCenterCapsuleOnHMD ? curCameraLoc.Z : CapsuleHalfHeight) + CamRotOffset.RotateVector(VRCapsuleOffset), FVector(1.0f)) * GetComponentTransform();
235 }
236
237 if (owningVRChar)
238 {
240 }
241
242 if (bUpdateBounds)
243 UpdateBounds();
244}
245
246
247FORCEINLINE void UVRRootComponent::SetCapsuleHalfHeightVR(float HalfHeight, bool bUpdateOverlaps)
248{
249 SCOPE_CYCLE_COUNTER(STAT_VRRootSetHalfHeight);
250
251 if (FMath::IsNearlyEqual(HalfHeight, CapsuleHalfHeight))
252 {
253 return;
254 }
255
256 SetCapsuleSizeVR(GetUnscaledCapsuleRadius(), HalfHeight, bUpdateOverlaps);
257}
258
259FORCEINLINE void UVRRootComponent::SetCapsuleSizeVR(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps)
260{
261 SCOPE_CYCLE_COUNTER(STAT_VRRootSetCapsuleSize);
262
263 if (FMath::IsNearlyEqual(NewRadius, CapsuleRadius) && FMath::IsNearlyEqual(NewHalfHeight, CapsuleHalfHeight))
264 {
265 return;
267
268 CapsuleHalfHeight = FMath::Max3(0.f, NewHalfHeight, NewRadius);
269
270 // Make sure that our character parent updates its replicated var as well
271 if (AVRBaseCharacter * BaseChar = Cast<AVRBaseCharacter>(GetOwner()))
272 {
273 if (GetNetMode() < ENetMode::NM_Client && BaseChar->VRReplicateCapsuleHeight)
274 BaseChar->ReplicatedCapsuleHeight.CapsuleHeight = CapsuleHalfHeight;
275 }
276
277 CapsuleRadius = FMath::Max(0.f, NewRadius);
278 UpdateBounds();
279 UpdateBodySetup();
280 MarkRenderStateDirty();
282
283 // do this if already created
284 // otherwise, it hasn't been really created yet
285 if (bPhysicsStateCreated)
286 {
287 // Update physics engine collision shapes
288 BodyInstance.UpdateBodyScale(GetComponentTransform().GetScale3D(), true);
289
290 if (bUpdateOverlaps && IsCollisionEnabled() && GetOwner())
291 {
292 UpdateOverlaps();
293 }
295}
EBPVRWaistTrackingMode
UENUM(Blueprintable)
DECLARE_LOG_CATEGORY_EXTERN(LogVRRootComponent, Log, All)
DECLARE_STATS_GROUP(TEXT("VRRootComponent"), STATGROUP_VRRootComponent, STATCAT_Advanced)
DECLARE_CYCLE_STAT(TEXT("VR Root Set Half Height"), STAT_VRRootSetHalfHeight, STATGROUP_VRRootComponent)
FTransform OffsetComponentToWorld
UPROPERTY(BlueprintReadOnly, Transient, Category = "VRExpansionLibrary")
static void Default_SetTrackedParent_Impl(UPrimitiveComponent *NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode, FBPVRWaistTracking_Info &OptionalWaistTrackingParent, USceneComponent *Self)
UCLASS(Blueprintable, meta = (BlueprintSpawnableComponent), ClassGroup = VRExpansionLibrary)
FBPVRWaistTracking_Info OptionalWaistTrackingParent
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRTrackedParentInterface")
FRotator StoredCameraRotOffset
FORCEINLINE void GenerateOffsetToWorld(bool bUpdateBounds=true, bool bGetPureYaw=true)
FVector DifferenceFromLastFrame
virtual void SetCapsuleSizeVR(float NewRadius, float NewHalfHeight, bool bUpdateOverlaps=true)
UFUNCTION(BlueprintCallable, Category = "Components|Capsule")
void SetCapsuleHalfHeightVR(float HalfHeight, bool bUpdateOverlaps=true)
UFUNCTION(BlueprintCallable, Category = "Components|Capsule")
bool AreWeOverlappingVolume(APhysicsVolume *V)
void OnUpdateTransform_Public(EUpdateTransformFlags UpdateTransformFlags, ETeleportType Teleport=ETeleportType::None)
FTransform OffsetComponentToWorld
FVector VRCapsuleOffset
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bAllowSimulatingCollision
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
USceneComponent * TargetPrimitiveComponent
UPROPERTY(BlueprintReadWrite, Transient, Category = "VRExpansionLibrary")
bool bUseWalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bCenterCapsuleOnHMD
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
AVRBaseCharacter * owningVRChar
virtual void SetTrackedParent(UPrimitiveComponent *NewParentComponent, float WaistRadius, EBPVRWaistTrackingMode WaistTrackingMode) override
UFUNCTION(BlueprintCallable, Category = "VRTrackedParentInterface")
TEnumAsByte< ECollisionChannel > WalkingCollisionOverride
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bPauseTracking
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VRExpansionLibrary")
bool bHadRelativeMovement
UPROPERTY(BlueprintReadOnly, Category = "VRExpansionLibrary")
USTRUCT(BlueprintType, Category = "VRExpansionLibrary")