[Need help] Vector riddle

Hello Devs,

I am trying to trace 4 debug lines, each of them starting from each corner of the character’s view point (game is a FPS) and ending at the middle of the screen, making a type of crosshair. Problem is, when I look up or down, the trace lines are moving from their respective corners and by looking directly upward, the lines are all aligned horizontally, simulating one line going from the left to right in the middle of the screen. I understand why but I cannot find a solution for it.

Here’s the code :



// Get the aim starting and ending positions
FVector AimStart;
FRotator AimRotation;
GetActorEyesViewPoint(AimStart, AimRotation);
FVector AimEnd = AimStart + AimRotation.Vector() * ScanDistance;

// Trace the line for scan
DrawDebugLine(GetWorld(), AimStart + AimRotation.Vector().UpVector * ScanOffset1 + GetActorRightVector() * ScanOffset1, AimEnd + AimRotation.Vector().UpVector * ScanOffset2 + GetActorRightVector() * ScanOffset2, FColor::Cyan); // Top right
DrawDebugLine(GetWorld(), AimStart - AimRotation.Vector().UpVector * ScanOffset1 + GetActorRightVector() * ScanOffset1, AimEnd - AimRotation.Vector().UpVector * ScanOffset2 + GetActorRightVector() * ScanOffset2, FColor::Cyan); // Bottom right
DrawDebugLine(GetWorld(), AimStart - AimRotation.Vector().UpVector * ScanOffset1 - GetActorRightVector() * ScanOffset1, AimEnd - AimRotation.Vector().UpVector * ScanOffset2 - GetActorRightVector() * ScanOffset2, FColor::Cyan); // Bottom left
DrawDebugLine(GetWorld(), AimStart + AimRotation.Vector().UpVector * ScanOffset1 - GetActorRightVector() * ScanOffset1, AimEnd + AimRotation.Vector().UpVector * ScanOffset2 - GetActorRightVector() * ScanOffset2, FColor::Cyan); // Top left


To explain further what is happening, when looking upward the “AimRotation.Vector()” isn’t in the Z direction but is going behind the character and it’s UpVector is 0.

What I would like to have is 4 trace lines that never moves from their respective corners.

Any help is much appreciated, as always, cheers!

Unless I’m misunderstanding your intent, wouldn’t this be something which goes into the HUD? Just put a crosshair graphic in the hud and you’re set…

I agree, wouldn’t this be far easier done in the hud?

No, I want it to be ingame, so the crosshair isn’t static and it merges with the objects in the game.
For example, if you aim at an object which is near, you will see the crosshair going through that object, in other terms, the crosshair will be cut by the object.
I hope I’m not too unclear!

uh, okay… it’s weird that you’d want a crosshair to clip with world objects. Would/should players be able to see the crosshairs of other players?

Couldn’t you just create a textured quad (or billboard) and then project it into world space from the cameras view-projection matrix? There’s gotta be a function which translates a position in screen space into a ray in 3D world space and you just have to set the distance along that ray… and if you render a textured billboard, you only need one ray instead of 4.

A bit odd to not use another solution, I agree.

However to answer the question, I would make use of AActor::GetActorRightVector() and AActor::GetActorUpVector(). If you take a line from the Actor’s location with the aiming point as direction then it will move as the camera moves because the aim direction itself moves thus causing the direction to change. In this case you’d want to make use of the returned traced actor, such that the lines start from the actor’s position with the actor’s right vector and up vector as direction vectors and a scale factor of X and -X to go up/down and right/left.

Something like this, assuming you have an action mapping that handles your left mouse click, you can put that there, that would go on your character class.


	FHitResult HitResult;

	if( Controller )
	{
		if( GetWorld()->LineTraceSingle(HitResult, GetActorLocation(), GetActorLocation() + GetControlRotation().Vector() * 1000, ECollisionChannel::ECC_Visibility, NULL) )
		{
			AActor* pTracedActor = HitResult.GetActor();
			if (pTracedActor)
			{
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorRightVector() * 1000.f, FColor(255, 0, 0), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorRightVector() * -1000.f, FColor(0, 255, 0), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorUpVector() * 1000.f, FColor(0, 255, 255), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorUpVector() * -1000.f, FColor(255, 255, 0), true, 100.f);
			}
		}
	}

Something you should know is that DrawDebugLine as its name implies is to be used for debugging purposes as it’s quite slow in general. :slight_smile:

uh, okay… it’s weird that you’d want a crosshair to clip with world objects. Would/should players be able to see the crosshairs of other players?

Couldn’t you just create a textured quad (or billboard) and then project it into world space from the cameras view-projection matrix? There’s gotta be a function which translates a position in screen space into a ray in 3D world space and you just have to set the distance along that ray… and if you render a textured billboard, you only need one ray instead of 4.
[/QUOTE]

I’m still using draw line because I’m not very knowledgeable of the engine and to answer your question, it’s a single player game and other players shouldn’t see the other’s crosshair.

A bit odd to not use another solution, I agree.

However to answer the question, I would make use of AActor::GetActorRightVector() and AActor::GetActorUpVector(). If you take a line from the Actor’s location with the aiming point as direction then it will move as the camera moves because the aim direction itself moves thus causing the direction to change. In this case you’d want to make use of the returned traced actor, such that the lines start from the actor’s position with the actor’s right vector and up vector as direction vectors and a scale factor of X and -X to go up/down and right/left.

Something like this, assuming you have an action mapping that handles your left mouse click, you can put that there, that would go on your character class.


	FHitResult HitResult;

	if( Controller )
	{
		if( GetWorld()->LineTraceSingle(HitResult, GetActorLocation(), GetActorLocation() + GetControlRotation().Vector() * 1000, ECollisionChannel::ECC_Visibility, NULL) )
		{
			AActor* pTracedActor = HitResult.GetActor();
			if (pTracedActor)
			{
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorRightVector() * 1000.f, FColor(255, 0, 0), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorRightVector() * -1000.f, FColor(0, 255, 0), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorUpVector() * 1000.f, FColor(0, 255, 255), true, 100.f);
				DrawDebugLine(GetWorld(), pTracedActor->GetActorLocation(), pTracedActor->GetActorLocation() + pTracedActor->GetActorUpVector() * -1000.f, FColor(255, 255, 0), true, 100.f);
			}
		}
	}

Something you should know is that DrawDebugLine as its name implies is to be used for debugging purposes as it’s quite slow in general. :slight_smile:
[/QUOTE]

I changed it to DrawLine functions :slight_smile: but the solution you gave me isn’t good for my context since the crosshair has a distance so I’d end up hitting nothing very often.

Bump /10char

I believe the issue is that


AimRotation.Vector().UpVector

is going to give you the world up vector (0,0,1), and not the up vector relative to your facing. Using GetActorUpVector() doesn’t solve this problem, because it’s based on the capsule component, and the up vector doesn’t move as your view moves.
If instead of using AimRotation.Vector().UpVector and GetActorRightVector() to get your Up and Right vectors, you use FirstPersonCamera->GetUpVector() and FirstPersonCamera->GetRightVector(), you should get the behavior you want.

Tyvm sir! Works like a charm now!