Quaternion.Angle inaccurate

Hi, I found out that using Quaternion.Angle to compare 2 quaternions is much more inaccurate than anticipated. While for comparing floats typically a small epsilon would be sufficient, Quaternion.Angle delivers values such as 0.03 degrees for angles that are the same nearly 100%

Comparing 3 nearly identical angles (a,b,c) prints the following:

Angle a->c: 0[2,624672E-11]
Angle b->c: 0[8,443563E-14]
Angle a->b: 0,03956468[2,835323E-11]

where the first value is the result of Quaternion.Angle, while the number in the [ ] brackets is the sqared magnitude of the difference!

You can see that while a==b and b==c, a!=c by 0.04 degrees - which does not make sense (as it is a floating point accuracy error i would assume?)

Code for repro:

 public class QuaternionBugRepro : MonoBehaviour
  {
    private void Awake()
    {
      var a = new Quaternion(-0.0821930915f, -0.685053766f, 0.32071647f, -0.648911834f);
      var b = new Quaternion(0.082193099f, 0.685053766f, -0.32071647f, 0.648911774f);
      var c = new Quaternion(0.0821931064f, 0.685053825f, -0.3207165f, 0.648911834f);

      Debug.Log("Angle a->c: " + PrintDiff(a, c));
      Debug.Log("Angle b->c: " + PrintDiff(b, c));
      Debug.Log("Angle a->b: " + PrintDiff(a, b));
    }

    private string PrintDiff(Quaternion a, Quaternion b)
    {
      return Quaternion.Angle(a, b) + "[" + (a.Inverse() * b).eulerAngles.sqrMagnitude + "]";
    }
  }

Whats the best way to compare 2 quaternions, as apparently Quaternion.Angle is quite wrong?
Will you improve the accuracy of the Quaternion.Angle function?

Internally Quaternions consist of four small floating point numbers. The Euler angles are derived from this, and based on the source underlying quaternion values, can have more or less imprecision.

Depending on your use case you could just increase the epsilon, or else you could use another quantity, such as quatRotation * Vector3.forward and then compare the x and y magnitudes of the resultant two vectors for how close they are.

Aaargh, I spent ages investigating why this was wrong because the quaternion W values seemed to be larger than 1 (when calculating the angle delta). It turns out that your input quaternions aren’t normalised so are invalid - if you normalise them it all works fine!

2 Likes

@tonemcbride Wow thanks for investigating this. It actually makes a lot of sense now, I just did not think about normalizing. Maybe unity should generally try to keep quaternions normalized? Are there any best-practices when to normalize them in unity?

Unity does try to keep them normalized.

That is unless you instantiate them yourself via the 4-float constructor like you did in your example code.

Well I extracted those values with the debugger, I encountered those exact values using only unity functions - such as Quaternion.AngleAxis/LookRotation/Inverse/multiply and so on.

They were probably very close to normalised, they might just have been rounded off when you viewed them in the debugger.

I will investigate this further and reply here when I find out the culprit, however it happened in one of our integration tests that try to verify that 2 rotations are the same (or very close)

THANKS!

This made me crazy. I spent way too long on this… You literally saved my sanity