Finding the difference between actor rotation and camera rotation?

So I’ve been trying to figure this pretty simple idea out. Basically what I have is a freelook camera. When I am freelooking, My controller rotates, but the actor stays at the same rotation (thus turning the camera, not the actor). The next step to this is for animation purposes, I need to know how much the camera rotated. In my mind, the simple way to do this is like this…

Of course, this doesn’t work, and for a while I couldn’t figure out why.

Then I realized that the controller’s yaw rotation is between -180 and 180.
The actor’s yaw rotation is between 0 and 360.

How can I find the difference between these two values?

This also brings me to ask what the point of having them clamped to different values is?

This is pretty easy.

  1. Convert the camera orientation to a normalized look vector. If you’re only interested in one axis, such as yaw, zero out the other components.
  2. Convert the character orientation to a normalized vector.
  3. Get the dot product of the two vectors.
  4. Get an inverse cosine of the dot product. This is the theta value between the two vectors.
  5. Keep in mind that if the vectors are the same or 180 degrees apart, the dot product is going to fail.

Here’s my implementation in C# which I used for my own game engine:

/// <summary>
/// Gives you the COUNTER-CLOCKWISE angle, starting from the base vector and ending at the end vector.
/// Note: The parameter order matters.
/// </summary>
/// <param name="baseVector">The starting unit vector</param>
/// <param name="endVector">the end unit vector</param>
/// <returns>A radian angle between the vectors</returns>
public static Angle FindAngleBetween(Vector3 baseVector, Vector3 endVector)
{

	if (baseVector == Vector3.Zero || endVector == Vector3.Zero)
	{
		throw new Exception("Both the base vector and end vector need to have a non-zero vector length.");
	}

	//The angle between two vectors can either be between 0->180 or 180->360.
	//the resulting angle is going to be dependent on the calling order. We will
	//always wind counter-clockwise from vector A until we get to vector B.

	Vector3 A = baseVector;
	Vector3 B = endVector;
	A.Normalize();
	B.Normalize();

	//check the two known edge cases for cross product
	if (A == -B)
		return new Angle(MathHelper.Pi);
	else if (A == B)
		return new Angle(0);

	//I need to be viewing the angles so that A->B is a counter-clockwise rotation.
	
	Angle Atheta;
	if (A.Y < 0)
	{   //bottom quadrants
		float Adot0 = MathHelper.Clamp(Vector3.Dot(A, Vector3.Left), -1.0f, 1.0f);
		Atheta = new Angle(System.Math.Acos(Adot0) + MathHelper.Pi);
	}
	else
	{   //top quadrants
		float Adot0 = MathHelper.Clamp(Vector3.Dot(A, -Vector3.Left), -1.0f, 1.0f);
		Atheta = new Angle(System.Math.Acos(Adot0));
	}

	Angle Btheta;
	if (B.Y < 0)
	{   //bottom quadrants
		float Bdot0 = MathHelper.Clamp(Vector3.Dot(B, Vector3.Left), -1.0f, 1.0f);
		Btheta = new Angle(System.Math.Acos(Bdot0) + MathHelper.Pi);
	}
	else
	{   //top quadrants
		float Bdot0 = MathHelper.Clamp(Vector3.Dot(B, -Vector3.Left), -1.0f, 1.0f);
		Btheta = new Angle(System.Math.Acos(Bdot0));
	}

	return System.Math.Acos(MathHelper.Clamp(Vector2.Dot(baseAngle.Vector2, endAngle.Vector2), -1, 1));
}

I cannot get this to work. I still feel like there’s an even easier way that I am missing.

I found the easy way!

Just negate the control rotation, combine rotations, and boom!