Weird Yaw Rotation - Top Down Angled Perspective Camera

Stumped myself on this one. Here is my yaw rotate function for having my character face the mouse pointer. It’s called in character tick. I utilize typical WASD to move around, when moving toward the cursor he walks forward, away and perpendicular he back peddles or strafes…

Except when moving downward ( negative on the X axis ), he often still faces the +X therefore back peddling. My camera relative to the player is boomed @ 800, rot -60 degrees downward (Y Axis) and is further negative on the X axis. So this happens when he’s facing the camera (or at least should be facing it).

void PlayerController::RotateToMouseCursor() {
	// get current mouse rotation
	FVector mouseLocation, mouseDirection;
	this->DeprojectMousePositionToWorld(mouseLocation, mouseDirection);

	// get reference to controllers character
	ACharacter *MyPc = this->GetCharacter();

	// get current rotation
	FRotator curRot = MyPc->GetActorRotation();

	// get target rotation
	FRotator targetRotation = mouseDirection.Rotation();

	//create and set the char to the new rotation, only yaw is needed
	FRotator newRot= FRotator(curRot.Pitch, targetRotation.Yaw, curRot.Roll);
	MyPc->SetActorRotation(newRot);
}

Anyone have any suggestions?

After doing some reading and testing in the various test types (attached, detached window). I can verify that I only have 180 degrees of rotation. I’m going to look into using a Quaternion.

EDIT: This is actually not a true statement. Playing in the standalone window didn’t allow my cursor to actually reach far enough down the screen to face the character negative of the X axis.

Hello boredcoding,

Please check this thread

Best regards,

Your post in that thread is what turned my eyes to quaternions.

I actually found that link and played with your previous solution to no avail. The character just floats around seemingly random when I use it directly.

http://s28.postimg.org/di6vct4fg/Untitled.jpg

I was able to derive this:
void AShooterPlayerController::RotateToMouseCursor(float DeltaSeconds) {
	FVector mouseLocation, mouseDirection;
	this->DeprojectMousePositionToWorld(mouseLocation, mouseDirection);

	FRotator targetRotation = mouseDirection.Rotation(); // get the mouse pointer rot

	FQuat q1 = FQuat(targetRotation); // convert mouse rot to a quaternion 
	FQuat q2(FVector(1, 0, 0), 0.2*DeltaSeconds); // rotate around axis (1,0,0) on angle 0.2*DeltaSeconds

	FQuat qr = q2*q1; // Get result quaternion
	ACharacter *MyPc = this->GetCharacter();
	qr.Normalize();
	MyPc->SetActorRotation(qr.Rotator());
}

But character still does not face the correct direction on the lower half of the screen.

After playing with this some more today I realized this is a direct correlation to the angle of the camera. When working with a boom of 800f and FRotator(-60, 0,0) I experience the issue. When I switch the FRotator(-90, 0, 0). The issue does not exist.

An offset of some type will be needed to “center” the x=0.0 back into the center of the viewport as if it were a 2d top down.

EDIT: After playing with with different camera angles I’ve noticed the characters yaw axis is actually based on the X position of the camera and not the character. The proper solution will be to move the camera’s piviot to (0,0,0).

Hello Boredcoding,

In your code your get mouse direction, it always points from camera in world space, that’s why your pawn looks forward. Also quaternion q2 has negligible rotation value, so it has no effect.

I slightly modified your code.

ACharacter* pPawn = GetCharacter();
if (!pPawn)
return;

FVector2D mousePos;
GetMousePosition(mousePos.X, mousePos.Y);

int32 width, height;
GetViewportSize(width, height);
mousePos.X /= width;

float ratio = mousePos.X*2-1; // let ratio is [-1;1]; ratio=-1 (left side of the screen); ratio=1 (right side of the screen)
ratio = ratio * PI / 2; // ratio is [-pi/2; pi/2]

FQuat q1 = FQuat(FVector(0, 0, 1), ratio); // relative rotation depended on mouse position
FQuat q2 = pPawn->GetActorRotation().Quaternion(); // current pawn rotation

FQuat qr = q2*q1;
pPawn->SetActorRotation(qr.Rotator());

Note: I assume that you get pawn rotation from WASD (so it can point backward relative camera) and add some turn (rotation) to the left or right depending on your mouse position. Am I right?

Best regards,

Here’s short video with display of the issue. After applying the above suggested changes, middle of screen left and right do properly spin a full 90 (as opposed to 90 being the bottom two corners). Also, this now behaves the same in traditional top down. I’ll play with trying this same setting to the Y axis once I wrap my head around this approach.

… Only been in C++ for about 2 weeks now, and have no real knowledge of 3d application implementation so still plenty to learn.

EDIT: The desired behavior is WASD movement with a facing always at the cursor in Isometric view.

Desired behavior:

Current behavior:

This is my desired behavior. I’d like to have this functionality in isometric view.
This was filmed with a boom of:

CameraBoom->RelativeRotation = FRotator(**-90.f,** 0.f, 0.f);

When I swithc the boom to

CameraBoom->RelativeRotation = FRotator(**-60.f,** 0.f, 0.f);

Mouse controls facing, WASD controlls the direction he moves.

To Recap things I’ve tried that (aren’t already in this thread):

// LookAtRotation implementation (just flips left and right)
void AShooterPlayerController::RotateToMouseCursor() {
	// get reference to controllers character
	ACharacter *MyPc = GetCharacter();
	if (!MyPc)
		return;

	FVector mouseLocation, mouseDirection;
	DeprojectMousePositionToWorld(mouseLocation, mouseDirection);
	FRotator adjRot = FRotationMatrix::MakeFromY(MyPc->GetActorLocation() - mouseLocation).Rotator();
	FRotator newRot = FRotator(0.f, adjRot.Yaw, 0.f);

	MyPc->SetActorRotation(newRot);

	UE_LOG(LogShooter, Warning, TEXT("MyPc->Yaw x: %s"), *newRot.ToString());
}


// spins him around his axis depending on Y distance from center screen.
	FORCEINLINE void AddToActorRotation(AActor* TheActor, const FRotator& AddRot) const
	{
		if (!TheActor) return;
		FTransform TheTransform = TheActor->GetTransform();
		TheTransform.ConcatenateRotation(AddRot.Quaternion());
		TheTransform.NormalizeRotation();
		TheActor->SetActorTransform(TheTransform);
	}

In another thread, and in conjunction with what I learned from this thread I was able to find a solution that helped resolve my issue.

Thanks for the pointers and info!