0
\$\begingroup\$

Ok, am I misunderstanding how Unity quaternions work, or is there a bad (about 2 degrees difference!) floating point error?

The TLDR is I use a quaternion r to rotate vector v and put the result in w. I then compute the angle between v and w (I looked at Unity's code for Vector3.Angle, and it looks correct to me, and the floating point error on the value of 180/pi is not enough to make more than a fraction of a degree difference) and I computed angle-axis of r itself (this time the code is internal and I can't see it). I expect the results to be the same, but they differ by a couple degrees.

What am I missing? I'd think if this is a bug, it'd be noticed and fixed by now!

Log output

v = (1.00, 1.41, -1.50)

r = (0.12768, 0.23930, 0.14488, 0.95155)

w = (-0.20, 1.91, -1.26)

angle = 33.43961

angle = 35.81708

axis = (0.42, 0.78, 0.47)

using UnityEngine;

namespace Deplorable_Mountaineer.Core.Utils {
    public class VectorsAndRotations : MonoBehaviour {
        private void Start() {
          
            //make a vector
            Vector3 v = new Vector3(1, Mathf.Sqrt(2), -1.5f);
            Debug.Log($"v = {v}");

            //Make a rotation, first 20 degrees about z axis (roll), then
            //10 degrees about x axis (pitch), and then 30 degrees about
            //y axis (yaw).
            Quaternion r = Quaternion.Euler(10, 30, 20);
            Debug.Log($"r = {r}");

            //w is v rotated by the rotation r
            Vector3 w = r*v;
            Debug.Log($"w = {w}");
            
            //If v and w are vectors, what is the angle between them?  
            //method 1
            float angle = Vector3.Angle(v, w);
            Debug.Log($"angle = {angle}");

            //method 2, since we know that w = r*v, find the angle of rotation encoded in r.
            //this way also gives the axis, perpendicular to the plane containing both vectors.
            Vector3 axis;
            r.ToAngleAxis(out angle, out axis);
            Debug.Log($"angle = {angle}");
            Debug.Log($"axis = {axis}");
            
            //why are they different?
            
        }
    }
}
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

The angle of a quaternion is measured in the plane perpendicular to its axis of rotation.

The angle between two vectors is measured in the plane containing those two vectors.

If those aren't the same plane, then you're measuring two different angles, and getting correct answers for both, just for different questions.

Think of it this way: a vector parallel to a quaternion's axis - like the north pole of the Earth acted on by the planet's spin - won't be changed at all when it's rotated by it. So measuring the angle between the before and after versions would give you a value of zero - a 100% error! As your input vector gets closer and closer to perpendicular to the axis of rotation - descending in latitude in the Earth example - it gets transformed more and more, so the angle you measure gradually increases. Until you reach the equator, fully perpendicular, where the vector is transformed by the quaternion by the maximum amount, and both angles are measured in the same plane.

In this case Dot(v, axis) == Dot(w, axis) ≈ 0.814 != 0, so your vectors are not perpendicular to the axis of rotation and do not experience the maximum angular change under this rotation.

tl;dr: a quaternion's angle is an upper bound for the angle you'll measure between vectors before & after rotation, and we should only expect them to be exactly equal when the vector is perpendicular to the axis of rotation.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .