Skip to content
Snippets Groups Projects
Select Git revision
  • 19aa1653cbce7ed067188326033db1cf26bdc62c
  • 5.4 default protected
  • 5.5
  • dev/5.5
  • dev/5.4
  • dev/5.3_downgrade
  • feature/experimenttime_hack
  • 5.3 protected
  • _IntenSelect5.3
  • IntenSelect5.3
  • 4.27 protected
  • 4.26 protected
  • 5.0 protected
  • 4.22 protected
  • 4.21 protected
  • UE5.4-2024.1
  • UE5.4-2024.1-rc1
  • UE5.3-2023.1-rc3
  • UE5.3-2023.1-rc2
  • UE5.3-2023.1-rc
20 results

VirtualRealityPawn.cpp

Blame
  • user avatar
    Qurabi authored
    19aa1653
    History
    VirtualRealityPawn.cpp 17.61 KiB
    #include "VirtualRealityPawn.h"
    
    #include "Camera/CameraComponent.h"
    #include "Cluster/IDisplayClusterClusterManager.h"
    #include "Engine/Engine.h"
    #include "Engine/World.h"
    #include "Game/IDisplayClusterGameManager.h"
    #include "GameFramework/InputSettings.h"
    #include "GameFramework/WorldSettings.h"
    #include "Kismet/GameplayStatics.h"
    #include "DisplayClusterSettings.h"
    #include "IDisplayCluster.h"
    #include "Engine/Engine.h"
    #include "Camera/CameraComponent.h"
    #include "Components/SphereComponent.h"
    #include "DrawDebugHelpers.h" // include draw debug helpers header file
    #include "Math/Vector.h"
    #include "VirtualRealityUtilities.h"
    
    
    AVirtualRealityPawn::AVirtualRealityPawn(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
    {
    	bUseControllerRotationYaw = true;
    	bUseControllerRotationPitch = true;
    	bUseControllerRotationRoll = true;
    
    	AutoPossessPlayer = EAutoReceiveInput::Player0; // Necessary for receiving motion controller events.
    
    	Movement = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("Movement"));
    	Movement->UpdatedComponent = RootComponent;
    
    	RotatingMovement = CreateDefaultSubobject<URotatingMovementComponent>(TEXT("RotatingMovement"));
    	RotatingMovement->UpdatedComponent = RootComponent;
    	RotatingMovement->bRotationInLocalSpace = false;
    	RotatingMovement->PivotTranslation = FVector::ZeroVector;
    	RotatingMovement->RotationRate = FRotator::ZeroRotator;
    
    	Head = CreateDefaultSubobject<USceneComponent>(TEXT("Head"));
    	RightHand = CreateDefaultSubobject<USceneComponent>(TEXT("RightHand"));
    	LeftHand = CreateDefaultSubobject<USceneComponent>(TEXT("LeftHand"));
    
    	HmdLeftMotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("HmdLeftMotionController"));
    	HmdLeftMotionController->SetupAttachment(RootComponent);
    	HmdLeftMotionController->SetTrackingSource(EControllerHand::Left);
    	HmdLeftMotionController->SetShowDeviceModel(true);
    	HmdLeftMotionController->SetVisibility(false);
    
    	HmdRightMotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("HmdRightMotionController"));
    	HmdRightMotionController->SetupAttachment(RootComponent);
    	HmdRightMotionController->SetTrackingSource(EControllerHand::Right);
    	HmdRightMotionController->SetShowDeviceModel(true);
    	HmdRightMotionController->SetVisibility(false);
    
    	CapsuleColliderComponent = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleCollider"));
    	CapsuleColliderComponent->OnComponentHit.AddDynamic(this, &AVirtualRealityPawn::OnHit);
    	CapsuleColliderComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
    	CapsuleColliderComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
    	CapsuleColliderComponent->SetCollisionResponseToChannel(ECollisionChannel::ECC_WorldStatic, ECollisionResponse::ECR_Block);
    	CapsuleColliderComponent->SetCapsuleSize(NewRadius, ColliderHalfHight);
    	CapsuleColliderComponent->AddWorldOffset(FVector(0,0, RootComponent->GetComponentLocation().Z + ColliderHalfHight*2));
    	// das hier ist nur da damit man sieht wo die Kapsel ist!
    	CapsuleMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereMesh"));
    	CapsuleMesh->SetupAttachment(CapsuleColliderComponent);
    	static ConstructorHelpers::FObjectFinder<UStaticMesh>SphereMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
    	CapsuleMesh->SetStaticMesh(SphereMeshAsset.Object);
    	CapsuleMesh->SetRelativeScale3D(FVector(0.3f));
    }
    
    void AVirtualRealityPawn::OnForward_Implementation(float Value)
    {
    	VRWolkingMode(Value, RightHand->GetForwardVector());
    
    }
    
    void AVirtualRealityPawn::OnRight_Implementation(float Value)
    {
    	VRWolkingMode(Value, RightHand->GetRightVector());
    }
    
    void AVirtualRealityPawn::OnTurnRate_Implementation(float Rate)
    {
    	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation);
    }
    
    void AVirtualRealityPawn::OnLookUpRate_Implementation(float Rate)
    {
    	if (UVirtualRealityUtilities::IsRoomMountedMode())
    	{
    		// User-centered projection causes simulation sickness on look up interaction hence not implemented.
    	}
    	else
    	{
    		AddControllerPitchInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation);
    	}
    }
    
    float AVirtualRealityPawn::GetBaseTurnRate() const
    {
    	return BaseTurnRate;
    }
    
    void AVirtualRealityPawn::SetBaseTurnRate(float Value)
    {
    	BaseTurnRate = Value;
    }
    
    UFloatingPawnMovement* AVirtualRealityPawn::GetFloatingPawnMovement()
    {
    	return Movement;
    }
    
    URotatingMovementComponent* AVirtualRealityPawn::GetRotatingMovementComponent()
    {
    	return RotatingMovement;
    }
    
    UDisplayClusterSceneComponent* AVirtualRealityPawn::GetFlystickComponent()
    {
    	return Flystick;
    }
    
    UDisplayClusterSceneComponent* AVirtualRealityPawn::GetRightHandtargetComponent()
    {
    	return RightHandTarget;
    }
    
    UDisplayClusterSceneComponent* AVirtualRealityPawn::GetLeftHandtargetComponent()
    {
    	return LeftHandTarget;
    }
    
    UMotionControllerComponent* AVirtualRealityPawn::GetHmdLeftMotionControllerComponent()
    {
    	return HmdLeftMotionController;
    }
    
    UMotionControllerComponent* AVirtualRealityPawn::GetHmdRightMotionControllerComponent()
    {
    	return HmdRightMotionController;
    }
    
    USceneComponent* AVirtualRealityPawn::GetHeadComponent()
    {
    	return Head;
    }
    
    USceneComponent* AVirtualRealityPawn::GetLeftHandComponent()
    {
    	return LeftHand;
    }
    
    USceneComponent* AVirtualRealityPawn::GetRightHandComponent()
    {
    	return RightHand;
    }
    
    USceneComponent* AVirtualRealityPawn::GetTrackingOriginComponent()
    {
    	return TrackingOrigin;
    }
    
    USceneComponent* AVirtualRealityPawn::GetCaveCenterComponent()
    {
    	return CaveCenter;
    }
    
    USceneComponent* AVirtualRealityPawn::GetShutterGlassesComponent()
    {
    	return ShutterGlasses;
    }
    
    void AVirtualRealityPawn::ClusterExecute(const FString& Command)
    {
    	FDisplayClusterClusterEvent event;
    	event.Name = "NDisplayCMD: " + Command;
    	event.Type = "NDisplayCMD";
    	event.Category = "VRPawn";
    	event.Parameters.Add("Command", Command);
    	IDisplayCluster::Get().GetClusterMgr()->EmitClusterEvent(event, false);
    }
    
    void AVirtualRealityPawn::OnHit(UPrimitiveComponent * HitComponent, AActor * OtherActor, UPrimitiveComponent * OtherComponent, FVector NormalImpulse, const FHitResult & Hit)
    {
    	// Other Actor is the actor that triggered the event. Check that is not ourself. 
    	if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComponent != nullptr))
    	{
    		//if (IsColliderOnGround()) {
    		//	UE_LOG(LogTemp, Warning, TEXT("I collided with something!"));
    		//	UE_LOG(LogTemp, Warning, TEXT("Something is: %s"), *Hit.ToString()); 
    		//	UE_LOG(LogTemp, Warning, TEXT("Hit.Actor.Get()->GetTargetLocation().Z: %f"), Hit.Actor.Get()->GetTargetLocation().Z);
    		//	UE_LOG(LogTemp, Warning, TEXT("Hit.Actor.Get()->GetActorLocation().Z: %f"), Hit.Actor.Get()->GetActorLocation().Z);
    		//	UE_LOG(LogTemp, Warning, TEXT("Distance(Pawn, Actor with TargetLocation) : %f"), FVector::Distance(RootComponent->GetComponentLocation(),Hit.Actor.Get()->GetTargetLocation()));
    		//	UE_LOG(LogTemp, Warning, TEXT("Distance(Pawn, Actor with ActorLocation) : %f"), FVector::Distance(RootComponent->GetComponentLocation(),Hit.Actor.Get()->GetActorLocation()));
    		//}
    	}
    }
    
    void AVirtualRealityPawn::HandleClusterEvent(const FDisplayClusterClusterEvent& Event)
    {
    	if (Event.Category.Equals("VRPawn") && Event.Type.Equals("NDisplayCMD") && Event.Parameters.Contains("Command"))
    	{
    		GEngine->Exec(GetWorld(), *Event.Parameters["Command"]);
    	}
    }
    
    void AVirtualRealityPawn::OnOverlapBegin(UPrimitiveComponent * OverlappedComp, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
    {
    	//if (OtherActor && (OtherActor != this) && OtherComp)
    	//{
    	//	HasContact = true;
    	//	DistancBetwCollisionAndClossestPointOnSurface = OtherComp->GetDistanceToCollision(SphereCollisionComponent->GetComponentLocation(), closestPointOnSurface);//Gibt die Entfernung zur nchstgelegenen Krperinstanzoberflche zurck.
    	//}
    }
    
    void AVirtualRealityPawn::OnOverlapEnd(UPrimitiveComponent * OverlappedComp, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex)
    {
    	//if (OtherActor && (OtherActor != this) && OtherComp)
    	//{
    	//	HasContact = false;
    	//}
    }
    
    void AVirtualRealityPawn::BeginPlay()
    {
    	Super::BeginPlay();
    
    
    	// Display cluster settings apply to all setups (PC, HMD, CAVE/ROLV) despite the unfortunate name due to being an UE4 internal.
    	TArray<AActor*> SettingsActors;
    	UGameplayStatics::GetAllActorsOfClass(GetWorld(), ADisplayClusterSettings::StaticClass(), SettingsActors);
    	if (SettingsActors.Num() > 0)
    	{
    		ADisplayClusterSettings* Settings = Cast<ADisplayClusterSettings>(SettingsActors[0]);
    		Movement->MaxSpeed = Settings->MovementMaxSpeed;
    		Movement->Acceleration = Settings->MovementAcceleration;
    		Movement->Deceleration = Settings->MovementDeceleration;
    		Movement->TurningBoost = Settings->MovementTurningBoost;
    		BaseTurnRate = Settings->RotationSpeed;
    	}
    
    	if (UVirtualRealityUtilities::IsRoomMountedMode())
    	{
    		UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("TurnRate", EKeys::MouseX));
    		UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("LookUpRate", EKeys::MouseY));
    
    		InitRoomMountedComponentReferences();
    	}
    	else if (UVirtualRealityUtilities::IsHeadMountedMode())
    	{
    		UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("TurnRate", EKeys::MouseX));
    		UInputSettings::GetInputSettings()->RemoveAxisMapping(FInputAxisKeyMapping("LookUpRate", EKeys::MouseY));
    
    		HmdLeftMotionController->SetVisibility(ShowHMDControllers);
    		HmdRightMotionController->SetVisibility(ShowHMDControllers);
    
    		LeftHand->AttachToComponent(HmdLeftMotionController, FAttachmentTransformRules::KeepRelativeTransform);
    		RightHand->AttachToComponent(HmdRightMotionController, FAttachmentTransformRules::KeepRelativeTransform);
    		Head->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform);
    	}
    	else //Desktop
    	{
    		Head->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform);
    
    		//also attach the hands to the camera component so we can use them for interaction
    		LeftHand->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform);
    		RightHand->AttachToComponent(GetCameraComponent(), FAttachmentTransformRules::KeepRelativeTransform);
    
    
    		//move to eyelevel
    		GetCameraComponent()->SetRelativeLocation(FVector(0, 0, 160));
    	}
    
    	//In ADisplayClusterPawn::BeginPlay() input is disabled on all slaves, so we cannot react to button presses, e.g. on the flystick correctly.
    	//Therefore, we activate it again:
    	UWorld* World = GetWorld();
    	if (World)
    	{
    		APlayerController* PlayerController = World->GetFirstPlayerController();
    		if (PlayerController)
    		{
    			this->EnableInput(PlayerController);
    		}
    	}
    
    	// Register cluster event listeners
    	IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
    	if (ClusterManager && !ClusterEventListenerDelegate.IsBound())
    	{
    		ClusterEventListenerDelegate = FOnClusterEventListener::CreateUObject(this, &AVirtualRealityPawn::HandleClusterEvent);
    		ClusterManager->AddClusterEventListener(ClusterEventListenerDelegate);
    	}
    
    	CollisionComponent->SetCollisionProfileName(FName("NoCollision"));
    	CollisionComponent->SetCollisionEnabled(ECollisionEnabled::NoCollision);
    
    	LastCameraPosition = CameraComponent->GetComponentLocation();
    	LastPawnPosition = RootComponent->GetComponentLocation();
    }
    
    void AVirtualRealityPawn::EndPlay(const EEndPlayReason::Type EndPlayReason)
    {
    	IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
    	if (ClusterManager && ClusterEventListenerDelegate.IsBound())
    	{
    		ClusterManager->RemoveClusterEventListener(ClusterEventListenerDelegate);
    	}
    
    	Super::EndPlay(EndPlayReason);
    }
    
    void AVirtualRealityPawn::Tick(float DeltaSeconds)
    {
    	Super::Tick(DeltaSeconds);
    	MyDeltaSeconds = DeltaSeconds;
    	SetCapsuleColliderCharacterSizeVR();
    
    	PhysWolkingMode(DeltaSeconds);
    
    	VRClimbStepUp(DeltaSeconds);
    
    	//Flystick might not be available at start, hence is checked every frame.
    	InitRoomMountedComponentReferences();
    
    	LastCameraPosition = CameraComponent->GetComponentLocation();
    	LastPawnPosition = RootComponent->GetComponentLocation();
    }
    
    void AVirtualRealityPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    	if (PlayerInputComponent)
    	{
    		PlayerInputComponent->BindAxis("MoveForward", this, &AVirtualRealityPawn::OnForward);
    		PlayerInputComponent->BindAxis("MoveRight", this, &AVirtualRealityPawn::OnRight);
    		PlayerInputComponent->BindAxis("TurnRate", this, &AVirtualRealityPawn::OnTurnRate);
    		PlayerInputComponent->BindAxis("LookUpRate", this, &AVirtualRealityPawn::OnLookUpRate);
    	}
    }
    
    UPawnMovementComponent* AVirtualRealityPawn::GetMovementComponent() const
    {
    	return Movement;
    }
    
    void AVirtualRealityPawn::SetCapsuleColliderCharacterSizeVR()
    { 
    	FVector NewLocationForCapsuleCollider = GetCameraComponent()->GetComponentLocation();
    	NewLocationForCapsuleCollider.Z -= ColliderHalfHight - 5.0f;
    	CapsuleColliderComponent->SetWorldLocation(NewLocationForCapsuleCollider, true);
    	FRotator NewRotationForCapsuleCollider = FRotator(0, 0, 1);
    	CapsuleColliderComponent->SetWorldRotation(NewRotationForCapsuleCollider, true);
    	float CharachterSize = abs(RootComponent->GetComponentLocation().Z - GetCameraComponent()->GetComponentLocation().Z) + 10.0f;
    	float ColliderHight = CharachterSize - MaxStepHeight;
    	ColliderHalfHight = ColliderHight / 2.0f;
    	CapsuleColliderComponent->SetCapsuleSize(NewRadius, ColliderHalfHight);
    }
    
    void AVirtualRealityPawn::PhysWolkingMode(float DeltaTime)
    {
    	FVector CurrentCameraPosition = CameraComponent->GetComponentLocation();
    	FVector DirectionVector = CurrentCameraPosition - LastCameraPosition;
    	DirectionVector.Z = 0;
    	FHitResult FHitResultPhys;
    	CapsuleColliderComponent->AddWorldOffset(DirectionVector, true, &FHitResultPhys);
    	if (FHitResultPhys.bBlockingHit) {
    		RootComponent->AddLocalOffset(-FHitResultPhys.Normal*FHitResultPhys.PenetrationDepth, true);
    	}
    }
    
    void AVirtualRealityPawn::VRWolkingMode(float Value, FVector Direction)
    {
    	FVector End = (Direction * GetFloatingPawnMovement()->GetMaxSpeed());
    	FHitResult FHitResultVR;
    	CapsuleColliderComponent->AddWorldOffset(End* MyDeltaSeconds*Value, true, &FHitResultVR);
    	
    	if (FVector::Distance(FHitResultVR.Location, CapsuleColliderComponent->GetComponentLocation()) > CapsuleColliderComponent->GetScaledCapsuleRadius() && RightHand && (NavigationMode == EVRNavigationModes::nav_mode_walk || UVirtualRealityUtilities::IsDesktopMode() || UVirtualRealityUtilities::IsHeadMountedMode() || UVirtualRealityUtilities::IsRoomMountedMode()))
    	{
    		AddMovementInput(Direction, Value);
    	}
    }
    
    bool AVirtualRealityPawn::IsColliderOnGround()
    {
    	if (FVector::Distance(RootComponent->GetComponentLocation(), CapsuleColliderComponent->GetComponentLocation()) >CapsuleColliderComponent->GetScaledCapsuleHalfHeight())
    	{
    		return true;
    	}
    	return false;
    }
    
    void AVirtualRealityPawn::VRClimbStepUp(float DeltaTime)
    {
    	FVector StartLineTraceUnderCollider = CapsuleColliderComponent->GetComponentLocation();
    	StartLineTraceUnderCollider.Z -= CapsuleColliderComponent->GetScaledCapsuleHalfHeight();
    	FHitResult LineTraceUnderCollider = CreateLineTrace(FVector(0, 0, -1), StartLineTraceUnderCollider, true);
    
    	if ((LineTraceUnderCollider.bBlockingHit && LineTraceUnderCollider.Distance < MaxStepHeight) && IsColliderOnGround())
    	{
    		RootComponent->AddLocalOffset(FVector(0, 0, +abs(MaxStepHeight - LineTraceUnderCollider.Distance)), true);
    	}
    	else if ((LineTraceUnderCollider.bBlockingHit && LineTraceUnderCollider.Distance > MaxStepHeight) && IsColliderOnGround())
    	{
    		RootComponent->AddLocalOffset(FVector(0, 0, -abs(MaxStepHeight - LineTraceUnderCollider.Distance)), true);
    	}
    }
    
    void AVirtualRealityPawn::InitRoomMountedComponentReferences()
    {
    	if (!UVirtualRealityUtilities::IsRoomMountedMode()) return;
    
    	//check whether the nodes already exist (otherwise GetClusterComponent() returns nullptr and prints a warning) and assign them
    	if (!TrackingOrigin) TrackingOrigin = UVirtualRealityUtilities::GetClusterComponent("cave_origin");
    	if (!TrackingOrigin) TrackingOrigin = UVirtualRealityUtilities::GetClusterComponent("rolv_origin");
    	if (!CaveCenter) CaveCenter = UVirtualRealityUtilities::GetClusterComponent("cave_center");
    	if (!ShutterGlasses)
    	{
    		ShutterGlasses = UVirtualRealityUtilities::GetClusterComponent("shutter_glasses");
    		Head->AttachToComponent(ShutterGlasses, FAttachmentTransformRules::KeepRelativeTransform);
    	}
    	if (!Flystick)
    	{
    		Flystick = UVirtualRealityUtilities::GetClusterComponent("flystick");
    		if (AttachRightHandInCAVE == EAttachementType::AT_FLYSTICK)
    			RightHand->AttachToComponent(Flystick, FAttachmentTransformRules::KeepRelativeTransform);
    		if (AttachLeftHandInCAVE == EAttachementType::AT_FLYSTICK)
    			LeftHand->AttachToComponent(Flystick, FAttachmentTransformRules::KeepRelativeTransform);
    	}
    	if (!LeftHandTarget)
    	{
    		LeftHandTarget = UVirtualRealityUtilities::GetClusterComponent("left_hand_target");
    		if (AttachLeftHandInCAVE == EAttachementType::AT_HANDTARGET)
    			LeftHand->AttachToComponent(LeftHandTarget, FAttachmentTransformRules::KeepRelativeTransform);
    	}
    	if (!RightHandTarget)
    	{
    		RightHandTarget = UVirtualRealityUtilities::GetClusterComponent("right_hand_target");
    		if (AttachRightHandInCAVE == EAttachementType::AT_HANDTARGET)
    			RightHand->AttachToComponent(RightHandTarget, FAttachmentTransformRules::KeepRelativeTransform);
    	}
    }
    
    
    FHitResult AVirtualRealityPawn::CreateLineTrace(FVector Direction, const FVector Start, bool Visibility)
    {
    		FHitResult OutHit;
    
    		FVector End = ((Direction * 1000.f) + Start);
    		FCollisionQueryParams CollisionParams;
    
    		if (Visibility)
    			DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 1);
    
    		if (GetWorld()->LineTraceSingleByChannel(OutHit, Start, End, ECC_Visibility, CollisionParams))
    		{
    			if (OutHit.bBlockingHit)
    			{
    			}
    		}
    	return OutHit;
    }