Two methods of finding angle between vectors gives different answers!

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!

I’ve asked elsewhere, and received lots of views but no answers. I know not many work with quaternions much so maybe nobody knows…

From my readings, it does appear that in Unity, the way to rotate a vector using a quaternion is quaternion times vector (the multiplication operator being overloaded to do the right thing, in theory). But the quaternion’s rotation amount an how much the vector rotated seem to be two degrees different! That is not what we call “close enough for government work”!

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?
            
        }
    }
}

You are calculating two different things. You can test this by changing v to any other vector. Now if you run your code you will get a very different angle using Vector3.Angle but exactly the same angle as before (35.81708) from Quaternion.ToAngleAxis.

Vector3.Angle treats both vectors as directions and so you are calculating a sort-of ‘sweep’ angle between v and w from the world origin, while the quaternion is not concerning itself with v or w and just gives you an angular representation of r, and since r did not change you get the same angle.

When you multiply w = r * v, w is just v rotated by r. What this means is that the rotation r is applied to each axis of vector v. I think. I don’t understand the math. You can see it here: Unity Quaternion Source Reference. Look for this operator override
public static Vector3 operator*(Quaternion rotation, Vector3 point)

The rotation of each of those two vectors have nothing to do with the angle between them. It does not create a new vector w that has been sweeped 35.81708 degrees to a different location.

I hope this makes sense. I rewrote it like 3 times

I don’t quite understand (and I’m a mathematician!). If you rotate v by the quaternion rotation r to get w, the angle between v and w should be the angle of rotation encoded in r. If r represents “rotation by theta about axis u”, then w=r*v should mean w and v are in a plane perpendicular to u and the angle between w and v, in that plane, should be theta. But for some reason, w seems to be v rotated by a different number than theta, one that is about 2.4 degrees different.

if you change your vector v

Vector3 v = new Vector3(1, Mathf.Sqrt(2), 1.5f); // I removed the - from z

and run the code again, the difference is about 27.2 degrees. Yet, we rotated with the same r.

I think that there is no axis u here. To my untrained eye it just looks like it is applying the rotation to vector v in place. But my brain melted when I looked at the code. Sorry.


Edit
I think - dangerous, but hear me out - that, still, the vector w is not a new position, but euler angles that you would apply to the rotation of a transform, instead of regarding it as a new, rotated position. Remember, when we apply rotations to a transform in the inspector, those are represented as a Vector3, and we are not changing the position of the transform when we change those rotations. I’m spit-balling here.

Incidentally I put it aside for a while (13 days according to this forum) and thought about it again.

Unity is doing it right, I was thinking wrong!

It became more obvious when I took a vector like (1,1,0), 45 degrees from the horizontal plane.

Rotate it 45 degrees around y axis using a quaternion equal to Quaternion.Euler(0,45,0).

New vector is not 45 degrees from old but closer to 25.

It’s a cone with vertex at the origin, containing the (1,1,0) vector, opening upward. The cone rotates 45 degrees, but the vector effectively changes 45 degrees if projected into the horizontal plane, but only 25 degrees along an axis perpendicular to the original vector and the new vector. This axis goes at an oblique angle.

So it turns out, a quaternion that is a 45 degree rotation can make vectors rotate anything from 0 to 45 along some axis. E.g. the vector pointing straight up would rotate 0 degrees. My intuition that a quaternion that was a 45-degree rotation causes every vector to rotate to one 45 degrees from it was wrong. Only those perpendicular to the quaternion’s axis of rotation are rotated 45 degrees.

So now, I understand quaternions (or rather, 3d rotations) a little better. I know rotations in more than two dimensions are sometimes hard to picture. I happen to know that it gets even stranger in 4 dimensions or above, based on my reading! (no longer is the composition of two rotations always a single rotation like in 2 or 3 dimensions). It’s related to a theorem that quaternions are as high above the reals as you can get and still have the associative property of multiplication as well as invertablilty.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms