Implementing a digital compass gives up to 180°


I’m trying to implement a digital heading compass using the current rotation of my camera:

void LateUpdate () 
   currentRotation = this.transform.rotation;
   currentHeading = Quaternion.Angle(Quaternion.identity, currentRotation);
   compassHeading.text = currentHeading.ToString("000") + "°";

It kind of works, since it gives the correct bearing until you reach 180° and after that point it starts to decrease the angle instead of keep adding it up until it reaches 359°. Since currentHeading returns a positive float regardless if I am turning East or West, there is probably one step I’m missing in my code.

Any help will be greatly appreciated.


Quaternion.Angle returns the angle between two rotations. Since it doesn’t know which of the two possible angles you might want, it always picks the tightest one - which will give you a result between 0 and 180.

What you should do is to compare the rotation to two other directions - the identity turned 90 degrees to the right, and the identity turned 90 degrees to the left, and use which of those you’re closest to to figure out where you’re facing:

Quaternion forward, rightward, leftward;

void Start() {
    forward = Quaternion.identity;
    rightward = Quaternion.Euler(0, 90, 0) * forward;
    leftward = Quaternion.Euler(0, -90, 0) * forward;

void LateUpdate() {
    Quaternion currentRotation = this.transform.rotation;
    float currentHeading = Quaternion.Angle(forward, currentRotation);

    float angleRight = Quaternion.Angle(rightward, currentRotation);
    float angleLeft = Quaternion.Angle(leftward, currentRotation);

    if (angleLeft < angleRight)
        currentHeading = 180 + (180 - currentHeading);

    compassHeading.text = currentHeading.ToString("000") + "°");

That works for me - putting it on a cube and replacing the compasHeading.text with a Debug.Log gives results between 0 and 359

Indeed it works. Thank you…

I would love to close this question but I still can’t do it.