From e16f499aa2b5d37d0775873715e715c329d467f1 Mon Sep 17 00:00:00 2001 From: jehret <ehret@vr.rwth-aachen.de> Date: Mon, 30 Oct 2023 17:29:39 +0100 Subject: [PATCH 1/3] walking movement improvements: fix blocked ghost movement, be able to handle collisions, e.g., already at program start (so just temporarily disable some collision checks) --- .../Private/Pawn/VRPawnMovement.cpp | 67 +++++++++++++++---- .../Public/Pawn/Navigation/VRPawnMovement.h | 4 +- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp index 5822f34a..3f6def5f 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp @@ -22,8 +22,8 @@ UVRPawnMovement::UVRPawnMovement(const FObjectInitializer& ObjectInitializer) : void UVRPawnMovement::BeginPlay() { Super::BeginPlay(); - LastCollisionFreeCapsulePosition = CapsuleColliderComponent->GetComponentLocation(); LastSteeringCollisionVector = FVector(0, 0, 0); + LastCollisionFreeCapsulePosition.Reset(); ActorsToIgnore = {GetOwner()}; } @@ -46,13 +46,14 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, AddInputVector(InputVector); } - //if me managed to get into a collision revert the movement since last Tick - CheckAndRevertCollisionSinceLastTick(); - //check whether we are still in collision e.g. if an object has moved and got us into collision - MoveOutOfNewDynamicCollisions(); - + if (NavigationMode == EVRNavigationModes::NAV_FLY || NavigationMode == EVRNavigationModes::NAV_WALK) { + //if me managed to get into a collision revert the movement since last Tick + CheckAndRevertCollisionSinceLastTick(); + //check whether we are still in collision e.g. if an object has moved and got us into collision + MoveOutOfNewDynamicCollisions(); + if (InputVector.Size() > 0.001) { const FVector SafeSteeringInput = GetCollisionSafeVirtualSteeringVec(InputVector, DeltaTime); @@ -64,6 +65,7 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, AddInputVector(SafeSteeringInput); } } + // so we add stepping-up (for both walk and fly) // and gravity for walking only @@ -139,12 +141,23 @@ void UVRPawnMovement::SetCapsuleColliderToUserSize() const void UVRPawnMovement::CheckAndRevertCollisionSinceLastTick() { - //check whether we are in a collision at the current position const FVector CapsuleLocation = CapsuleColliderComponent->GetComponentLocation(); + + if(!LastCollisionFreeCapsulePosition.IsSet()) + { + //we cannot revert anyways so only check if the current position is collision free + if (!CreateCapsuleTrace(CapsuleLocation, CapsuleLocation).bBlockingHit) + { + LastCollisionFreeCapsulePosition = CapsuleLocation; + } + return; + } + + //check whether we are in a collision at the current position if (CreateCapsuleTrace(CapsuleLocation, CapsuleLocation).bBlockingHit) { //if so move back to last position - UpdatedComponent->AddWorldOffset(LastCollisionFreeCapsulePosition - CapsuleLocation); + UpdatedComponent->AddWorldOffset(LastCollisionFreeCapsulePosition.GetValue() - CapsuleLocation); } else { @@ -154,15 +167,28 @@ void UVRPawnMovement::CheckAndRevertCollisionSinceLastTick() void UVRPawnMovement::MoveOutOfNewDynamicCollisions() { - FVector ResolveDirection = GetOverlapResolveDirection(); - ResolveDirection *= 1.5f; //scale it up for security distance - UpdatedComponent->AddWorldOffset(ResolveDirection); + TOptional<FVector> ResolveDirectionOptional = GetOverlapResolveDirection(); + + if(ResolveDirectionOptional.IsSet()) + { + FVector ResolveDirection = 1.5f * ResolveDirectionOptional.GetValue(); //scale it up for security distance + UpdatedComponent->AddWorldOffset(ResolveDirection); + + //invalidate the last collision-free position, since apparently something change so ew got into this collision + LastCollisionFreeCapsulePosition.Reset(); + } } void UVRPawnMovement::CheckForPhysWalkingCollision() { + if(!LastCollisionFreeCapsulePosition.IsSet()) + { + //we don't know any old location-free location, so do nothing here + return; + } + const FVector CapsuleLocation = CapsuleColliderComponent->GetComponentLocation(); - const FHitResult HitResult = CreateCapsuleTrace(LastCollisionFreeCapsulePosition, CapsuleLocation); + const FHitResult HitResult = CreateCapsuleTrace(LastCollisionFreeCapsulePosition.GetValue(), CapsuleLocation); //if this was not possible move the entire pawn away to avoid the head collision if (HitResult.bBlockingHit) @@ -175,6 +201,14 @@ void UVRPawnMovement::CheckForPhysWalkingCollision() FVector UVRPawnMovement::GetCollisionSafeVirtualSteeringVec(FVector InputVector, float DeltaTime) { + //if we were in a collision in the last step already (so no LastCollisionFreeCapsulePosition is set) + // we allow movement to resole this collision (otherwise you wold be stuck forever) + if(!LastCollisionFreeCapsulePosition.IsSet()) + { + return InputVector; + } + + const float SafetyFactor = 3.0f; //so we detect collision a bit earlier const FVector CapsuleLocation = CapsuleColliderComponent->GetComponentLocation(); FVector ProbePosition = SafetyFactor * InputVector.GetSafeNormal() * GetMaxSpeed() * DeltaTime + CapsuleLocation; @@ -276,7 +310,7 @@ FHitResult UVRPawnMovement::CreateCapsuleTrace(const FVector& Start, const FVect return Hit; } -FVector UVRPawnMovement::GetOverlapResolveDirection() +TOptional<FVector> UVRPawnMovement::GetOverlapResolveDirection() const { TArray<UPrimitiveComponent*> OverlappingComponents; TArray<TEnumAsByte<EObjectTypeQuery>> traceObjectTypes; @@ -286,8 +320,13 @@ FVector UVRPawnMovement::GetOverlapResolveDirection() CapsuleColliderComponent->GetScaledCapsuleHalfHeight(), traceObjectTypes, nullptr, ActorsToIgnore, OverlappingComponents); - FVector ResolveVector = FVector::ZeroVector; + if(OverlappingComponents.Num() == 0) + { + // return unset optional + return TOptional<FVector>(); + } + FVector ResolveVector = FVector::ZeroVector; //check what to do to move out of these collisions (or nothing if non is there) //we just add the penetrations so in very unfortunate conditions this can become problematic/blocking but for now and our regular use cases this works for (const UPrimitiveComponent* OverlappingComp : OverlappingComponents) diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h index 63dc5b0e..f5e34a4d 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h @@ -65,7 +65,7 @@ public: private: //check for FHitResult CreateCapsuleTrace(const FVector& Start, const FVector& End, bool DrawDebug = false) const; - FVector GetOverlapResolveDirection(); + TOptional<FVector> GetOverlapResolveDirection() const; void SetCapsuleColliderToUserSize() const; void CheckForPhysWalkingCollision(); FVector GetCollisionSafeVirtualSteeringVec(FVector InputVector, float DeltaTime); @@ -78,7 +78,7 @@ private: USceneComponent* HeadComponent = nullptr; float VerticalSpeed = 0.0f; - FVector LastCollisionFreeCapsulePosition; + TOptional<FVector> LastCollisionFreeCapsulePosition; FVector LastSteeringCollisionVector; //just stored for performance gains; -- GitLab From 1fa4703d4fb078a7d4a2ce39ce3a7fcb8fd4c8bd Mon Sep 17 00:00:00 2001 From: David Gilbert <gilbert@vr.rwth-aachen.de> Date: Tue, 31 Oct 2023 09:08:54 +0100 Subject: [PATCH 2/3] style(navigation): unify formatting in VRPawnMovement --- .../Private/Pawn/VRPawnMovement.cpp | 16 ++++++++-------- .../Public/Pawn/Navigation/VRPawnMovement.h | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp index 3f6def5f..14fa63ff 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp @@ -1,5 +1,5 @@ #include "Pawn/Navigation/VRPawnMovement.h" -#include "DrawDebugHelpers.h" + #include "Kismet/KismetSystemLibrary.h" UVRPawnMovement::UVRPawnMovement(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) @@ -46,7 +46,7 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, AddInputVector(InputVector); } - + if (NavigationMode == EVRNavigationModes::NAV_FLY || NavigationMode == EVRNavigationModes::NAV_WALK) { //if me managed to get into a collision revert the movement since last Tick @@ -65,7 +65,7 @@ void UVRPawnMovement::TickComponent(float DeltaTime, enum ELevelTick TickType, AddInputVector(SafeSteeringInput); } } - + // so we add stepping-up (for both walk and fly) // and gravity for walking only @@ -143,7 +143,7 @@ void UVRPawnMovement::CheckAndRevertCollisionSinceLastTick() { const FVector CapsuleLocation = CapsuleColliderComponent->GetComponentLocation(); - if(!LastCollisionFreeCapsulePosition.IsSet()) + if (!LastCollisionFreeCapsulePosition.IsSet()) { //we cannot revert anyways so only check if the current position is collision free if (!CreateCapsuleTrace(CapsuleLocation, CapsuleLocation).bBlockingHit) @@ -169,7 +169,7 @@ void UVRPawnMovement::MoveOutOfNewDynamicCollisions() { TOptional<FVector> ResolveDirectionOptional = GetOverlapResolveDirection(); - if(ResolveDirectionOptional.IsSet()) + if (ResolveDirectionOptional.IsSet()) { FVector ResolveDirection = 1.5f * ResolveDirectionOptional.GetValue(); //scale it up for security distance UpdatedComponent->AddWorldOffset(ResolveDirection); @@ -181,7 +181,7 @@ void UVRPawnMovement::MoveOutOfNewDynamicCollisions() void UVRPawnMovement::CheckForPhysWalkingCollision() { - if(!LastCollisionFreeCapsulePosition.IsSet()) + if (!LastCollisionFreeCapsulePosition.IsSet()) { //we don't know any old location-free location, so do nothing here return; @@ -203,7 +203,7 @@ FVector UVRPawnMovement::GetCollisionSafeVirtualSteeringVec(FVector InputVector, { //if we were in a collision in the last step already (so no LastCollisionFreeCapsulePosition is set) // we allow movement to resole this collision (otherwise you wold be stuck forever) - if(!LastCollisionFreeCapsulePosition.IsSet()) + if (!LastCollisionFreeCapsulePosition.IsSet()) { return InputVector; } @@ -320,7 +320,7 @@ TOptional<FVector> UVRPawnMovement::GetOverlapResolveDirection() const CapsuleColliderComponent->GetScaledCapsuleHalfHeight(), traceObjectTypes, nullptr, ActorsToIgnore, OverlappingComponents); - if(OverlappingComponents.Num() == 0) + if (OverlappingComponents.Num() == 0) { // return unset optional return TOptional<FVector>(); diff --git a/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h b/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h index f5e34a4d..95e88e0d 100644 --- a/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h +++ b/Source/RWTHVRToolkit/Public/Pawn/Navigation/VRPawnMovement.h @@ -74,6 +74,7 @@ private: UPROPERTY(VisibleAnywhere) UCapsuleComponent* CapsuleColliderComponent = nullptr; + UPROPERTY() USceneComponent* HeadComponent = nullptr; -- GitLab From b062819e75989dc983e7f9287292ef17dc2223a8 Mon Sep 17 00:00:00 2001 From: David Gilbert <gilbert@vr.rwth-aachen.de> Date: Tue, 31 Oct 2023 09:13:02 +0100 Subject: [PATCH 3/3] docs(navigation): small typo fixes --- Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp index 14fa63ff..1fcabf5b 100644 --- a/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp +++ b/Source/RWTHVRToolkit/Private/Pawn/VRPawnMovement.cpp @@ -174,7 +174,7 @@ void UVRPawnMovement::MoveOutOfNewDynamicCollisions() FVector ResolveDirection = 1.5f * ResolveDirectionOptional.GetValue(); //scale it up for security distance UpdatedComponent->AddWorldOffset(ResolveDirection); - //invalidate the last collision-free position, since apparently something change so ew got into this collision + //invalidate the last collision-free position, since apparently something changed so we got into this collision LastCollisionFreeCapsulePosition.Reset(); } } @@ -183,7 +183,7 @@ void UVRPawnMovement::CheckForPhysWalkingCollision() { if (!LastCollisionFreeCapsulePosition.IsSet()) { - //we don't know any old location-free location, so do nothing here + //we don't know any old collision-free location, so do nothing here return; } @@ -201,7 +201,7 @@ void UVRPawnMovement::CheckForPhysWalkingCollision() FVector UVRPawnMovement::GetCollisionSafeVirtualSteeringVec(FVector InputVector, float DeltaTime) { - //if we were in a collision in the last step already (so no LastCollisionFreeCapsulePosition is set) + // if we were in a collision in the last step already (so no LastCollisionFreeCapsulePosition is set) // we allow movement to resole this collision (otherwise you wold be stuck forever) if (!LastCollisionFreeCapsulePosition.IsSet()) { @@ -327,7 +327,7 @@ TOptional<FVector> UVRPawnMovement::GetOverlapResolveDirection() const } FVector ResolveVector = FVector::ZeroVector; - //check what to do to move out of these collisions (or nothing if non is there) + //check what to do to move out of these collisions (or nothing if none is there) //we just add the penetrations so in very unfortunate conditions this can become problematic/blocking but for now and our regular use cases this works for (const UPrimitiveComponent* OverlappingComp : OverlappingComponents) { -- GitLab