Skip to content
Snippets Groups Projects
Select Git revision
  • c253b671c849b97e01f92cbfd5b7c62bed6b777f
  • stable default protected
  • MA_Pape_2018
  • MA_2018_Lopatin
  • feature/mesh_viewer
  • feature/#468_access_isosurface_scalar
  • feature/#459_default_primitives
  • master protected
  • feature/#470_Create_a_color_lookup_table
  • feature/#473_resize_companion_window
  • feature/#462_do_not_use_arb_extensions
  • feature/#495_Provide_data_for_larger_isosurfaces
  • feature/#323_default_image
  • feature/#480_Create_a_smaller_test_mesh_for_combustion_demo
  • feature/#236_Get_Integration_tests_running_on_CI
  • feature/#447_Copy_standard_assets_to_build_folder
  • 447-copy-standard-assets-to-build-folder-and-remove-resource-path
  • feature/#445_mesh_render_settings_component
  • feature/#251_Make_sure_tests_cpp_is_compiled_once
  • feature/#455_Remove_navigation_and_improve_interaction_for_combustion_demo
  • feature/446_strange_txt_files
  • v18.06.0
  • v18.05.0
  • #251_bad
  • #251_good
  • v18.03.0
  • v18.02.0
  • v18.01.0
  • v17.12.0
  • v17.11.0
  • v17.10.0
  • v17.09.0
  • v17.07.0
33 results

ray_pass.cpp

Blame
  • VirtualRealityPawn.cpp 17.87 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->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
    	CapsuleColliderComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
    	CapsuleColliderComponent->SetCollisionResponseToChannel(ECollisionChannel::ECC_WorldStatic, ECollisionResponse::ECR_Block);
    	CapsuleColliderComponent->SetupAttachment(CameraComponent);
    	CapsuleColliderComponent->SetCapsuleSize(40.0f, 96.0f);
    }
    
    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::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::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();
    }
    
    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);
    	DeltaTime = DeltaSeconds;
    
    	SetCapsuleColliderCharacterSizeVR();
    	if (IsColliderOnGround()) {
    		VRClimbStepUp(DeltaSeconds);
    		PhysWolkingMode();
    	}
    
    	//Flystick might not be available at start, hence is checked every frame.
    	InitRoomMountedComponentReferences();
    
    	LastCameraPosition = CameraComponent->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()
    {
    	float CharachterSize = abs(RootComponent->GetComponentLocation().Z - CameraComponent->GetComponentLocation().Z);
    
    	if (CharachterSize > MaxStepHeight)
    	{
    		float ColliderHeight = CharachterSize - MaxStepHeight;
    		float ColliderHalfHeight = ColliderHeight / 2.0f;
    		if (ColliderHalfHeight < 40.0f) {
    			CapsuleColliderComponent->SetCapsuleSize(ColliderHalfHeight, ColliderHalfHeight);
    		}
    		else {
    			CapsuleColliderComponent->SetCapsuleSize(40.0f, ColliderHalfHeight);
    		}
    
    		CapsuleColliderComponent->SetWorldLocation(CameraComponent->GetComponentLocation());
    		CapsuleColliderComponent->AddWorldOffset(FVector(0, 0, -ColliderHalfHeight));
    		CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1));
    	}
    	else
    	{
    		CapsuleColliderComponent->SetWorldLocation(CameraComponent->GetComponentLocation());
    		CapsuleColliderComponent->SetWorldRotation(FRotator(0, 0, 1));
    	}
    }
    
    void AVirtualRealityPawn::PhysWolkingMode()
    {
    	FVector CurrentCameraPosition = CameraComponent->GetComponentLocation();
    	FVector Direction = CurrentCameraPosition - LastCameraPosition;
    	Direction.Z = 0.0f;
    	FHitResult FHitResultPhys;
    	CapsuleColliderComponent->AddWorldOffset(Direction, true, &FHitResultPhys);
    
    	if (FHitResultPhys.bBlockingHit) {
    		RootComponent->AddLocalOffset(FHitResultPhys.Normal*FHitResultPhys.PenetrationDepth);
    	}
    }
    
    void AVirtualRealityPawn::VRWolkingMode(float Value, FVector Direction)
    {
    	Direction.Z = 0.0f;//Not falling/flying
    	FVector End = (Direction * GetFloatingPawnMovement()->GetMaxSpeed());
    	FHitResult FHitResultVR;
    	CapsuleColliderComponent->AddWorldOffset(End* DeltaTime*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()
    {
    	float CharachterSize = abs(RootComponent->GetComponentLocation().Z - CameraComponent->GetComponentLocation().Z);
    	if (CharachterSize > MaxStepHeight)
    	{
    		return true;
    	}
    	return false;
    }
    
    void AVirtualRealityPawn::VRClimbStepUp(float DeltaSeconds)
    {
    	FVector StartLineTraceUnderCollider = CapsuleColliderComponent->GetComponentLocation();
    	StartLineTraceUnderCollider.Z -= CapsuleColliderComponent->GetScaledCapsuleHalfHeight();
    	FHitResult HitDetailsMultiLineTrace = CreateMultiLineTrace(FVector(0, 0, -1), StartLineTraceUnderCollider, CapsuleColliderComponent->GetScaledCapsuleRadius() / 2.0f, false);
    	float DiffernceDistance = abs(MaxStepHeight - HitDetailsMultiLineTrace.Distance);
    	static float SumUpSteppingSpeed = 0.0f;
    
    	if ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance < MaxStepHeight))
    	{
    		SumUpSteppingSpeed += UpSteppingSpeed * DeltaSeconds;
    		if (SumUpSteppingSpeed*DeltaSeconds < DiffernceDistance)
    		{
    			RootComponent->AddLocalOffset(FVector(0.f, 0.f, +SumUpSteppingSpeed * DeltaSeconds));
    		}
    		else
    		{
    			RootComponent->AddLocalOffset(FVector(0.f, 0.f, +DiffernceDistance));
    		}
    	}
    	else if ((HitDetailsMultiLineTrace.bBlockingHit && HitDetailsMultiLineTrace.Distance > MaxStepHeight) || HitDetailsMultiLineTrace.Actor == nullptr && HitDetailsMultiLineTrace.Distance != -1.0f)
    	{
    		GravitySpeed -= 1000.0f*DeltaSeconds;
    		if (GravitySpeed*DeltaSeconds > -DiffernceDistance)
    		{
    			RootComponent->AddLocalOffset(FVector(0.f, 0.f, GravitySpeed*DeltaSeconds));
    		}
    		else
    		{
    			RootComponent->AddLocalOffset(FVector(0.f, 0.f, -DiffernceDistance));
    		}
    	}
    	else
    	{
    		GravitySpeed = 0.0f;
    		SumUpSteppingSpeed = 0.0f;
    	}
    }
    
    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)
    {
    	//Re-initialize hit info
    	FHitResult HitDetails = FHitResult(ForceInit);
    
    	FVector End = ((Direction * 1000.f) + Start);
    	// additional trace parameters
    	FCollisionQueryParams TraceParams(FName(TEXT("InteractTrace")), true, NULL);
    	TraceParams.bTraceComplex = true; //to use complex collision on whatever we interact with to provide better precision.
    	TraceParams.bReturnPhysicalMaterial = true; //to provide details about the physical material, if one exists on the thing we hit, to come back in our hit result.
    
    	if (Visibility)
    		DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1, 0, 1);
    
    	if (GetWorld()->LineTraceSingleByChannel(HitDetails, Start, End, ECC_Visibility, TraceParams))
    	{
    		if (HitDetails.bBlockingHit)
    		{
    		}
    	}
    	return HitDetails;
    }
    
    FHitResult AVirtualRealityPawn::CreateMultiLineTrace(FVector Direction, const FVector Start, float distance, bool Visibility)
    {
    	FHitResult HitDetailsMultiLineTrace;
    	HitDetailsMultiLineTrace.Distance = -1.0f;//-1 not exist, but to know if this Objekt not Initialized(when all Traces not compatible)
    
    	FHitResult HitDetailsFromLineTraceCenter = CreateLineTrace(Direction, Start, Visibility);
    	FHitResult HitDetailsFromLineTraceLeft = CreateLineTrace(Direction, Start + FVector(0, -distance, 0), Visibility);
    	FHitResult HitDetailsFromLineTraceRight = CreateLineTrace(Direction, Start + FVector(0, distance, 0), Visibility);
    	FHitResult HitDetailsFromLineTraceFront = CreateLineTrace(Direction, Start + FVector(distance, 0, 0), Visibility);
    	FHitResult HitDetailsFromLineTraceBehind = CreateLineTrace(Direction, Start + FVector(-distance, 0, 0), Visibility);
    
    	bool BlockingHitAndSameActor = (HitDetailsFromLineTraceCenter.bBlockingHit)
    		&& (HitDetailsFromLineTraceCenter.Actor == HitDetailsFromLineTraceLeft.Actor&& HitDetailsFromLineTraceLeft.Actor == HitDetailsFromLineTraceRight.Actor
    			&& HitDetailsFromLineTraceRight.Actor == HitDetailsFromLineTraceFront.Actor&& HitDetailsFromLineTraceFront.Actor == HitDetailsFromLineTraceBehind.Actor);
    	//If you are falling
    	bool AllNothingHiting = HitDetailsFromLineTraceCenter.Actor == nullptr && HitDetailsFromLineTraceLeft.Actor == nullptr
    		&& HitDetailsFromLineTraceRight.Actor == nullptr && HitDetailsFromLineTraceFront.Actor == nullptr;
    
    	if (BlockingHitAndSameActor || AllNothingHiting)
    		HitDetailsMultiLineTrace = HitDetailsFromLineTraceCenter;
    
    	return HitDetailsMultiLineTrace;
    }