Download

The character's head is looking at the player but only relative to the world.

This is the script i use:


FRotator UMy_AnimInstance::Get_Look_At_Rotation(FVector start_location, const float clamp_angle, const float rotation_factor, FVector offset, bool& b_touching_limit)
{
	if (!riftHMD)
		riftHMD = GEngine->HMDDevice.Get();

	if (!player_controller)
		player_controller = GetWorld()->GetFirstPlayerController();

	if (!player_camera_manager)
		player_camera_manager = player_controller->PlayerCameraManager;
	
	if (!riftHMD || !player_camera_manager)
		return FRotator::ZeroRotator;

	FVector local_head_mount_location;
	FQuat head_mount_orientation; //Not using it, just there to use the below function.
	riftHMD->GetCurrentOrientationAndPosition(head_mount_orientation, local_head_mount_location);

	FVector camera_location = player_camera_manager->GetCameraLocation();
	FRotator player_rotation = player_controller->GetControlRotation();

	FVector world_head_mount_location = player_rotation.RotateVector(local_head_mount_location) 
                                                               + camera_location + offset;

	FVector direction = world_head_mount_location - start_location;
	direction.Normalize();
	FRotator rotation = direction.Rotation();
	FVector right_vector = FRotationMatrix(rotation).GetScaledAxis(EAxis::Y);
	right_vector *= -1.0f;
	
	FRotator final_rotation = FRotator::ZeroRotator;

	final_rotation.Yaw = FMath::Clamp(right_vector.Rotation().Yaw 
                                                            * rotation_factor, -clamp_angle, clamp_angle);

	final_rotation.Roll = FMath::Clamp(rotation.Pitch*-1 * rotation_factor, -clamp_angle, clamp_angle);

	b_touching_limit = FMath::Abs(final_rotation.Yaw) == clamp_angle 
                                    || FMath::Abs(final_rotation.Roll) == clamp_angle;
        
        //Checks if there is too drastic movement since last rotation.
	if (!last_rotation.Equals(final_rotation, 0.1f)) 
	{
		final_rotation = RLerp(last_rotation, final_rotation, 1.0f - lerp_alpha, true);
		lerp_alpha -= GetWorld()->DeltaTimeSeconds/20;
	}
	else
	{
		lerp_alpha = 1;
	}

	last_rotation = final_rotation;

	return final_rotation;
}

FRotator UMy_AnimInstance::RLerp(FRotator A, FRotator B, float Alpha, bool bShortestPath)
{
	FRotator DeltaAngle = B - A;

	// if shortest path, we use Quaternion to interpolate instead of using FRotator
	if (bShortestPath)
	{
		FQuat AQuat(A);
		FQuat BQuat(B);

		FQuat Result = FQuat::Slerp(AQuat, BQuat, Alpha);
		Result.Normalize();

		return Result.Rotator();
	}

	return A + Alpha*DeltaAngle;
}


*start_location is the head’s location.
It work’s great when this character is at rotation 0 0 0 inside the world.
But when i rotates it, it get messed up, i even tried to rotate the root in my 3d package program so i can leave it at 0 0 0 in unreal, but still the same issue.
I’m using blender so the forward axis is not X, therefor i need to rotate the head to it’s right side before it looks at the player.
This character is looking at the OculusRift head mounted device on the player ( riftMHD ).

I’m using animation blueprint to rotate the head.

There is a Tick event in the left side:
Capture.PNG

Capture2.PNG

This is like i need to give him the current local rotation of the head_socket for the calculation, but as i see i can get only the world location:

How can i access this Socket component to read that relative rotator variable?
https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/USkeletalMeshSocket/index.html

*Edit: Ok i can get the relative transforms via the GetSocketTreansform node, but still, can’t find how to use it correctly to solve this issue.
98248992b03dbd1475ecaf04959b3e7e02e790c1.png

Any idea anyone?..

And why is it have to be so complex? in Unity3D they have this LookAt() function that just works :expressionless:

Ok if anyone interested, i’v solved it by using the neck’s bone socket world rotation to rotate the head in the right direction no matter how the character is rotated in the world.

I am interested, can you post the blueprint with the neck bone, thanks!

Np.
4684ca3c8b89bb642ac5582352de14da6ab26cd0.png

and the GetLookAtRotation function is the one above with some changes:
it basically this:


final_rotation.Yaw += (right_vector.Rotation().Yaw + neck_rotation.Yaw);

instead of this:


final_rotation.Yaw += right_vector.Rotation().Yaw

But it only fixes the Yaw issue and it getting messed up and i try to implement it to the other axes.
And i can’t seem to understand how to clamp it like i did before.

I had this one:


final_rotation.Yaw = FMath::Clamp(right_vector.Rotation().Yaw, -clamp_angle, clamp_angle)

and it worked well, but it won’t work well when adding the new value to the clamp function.

Can anyone please help me with it?