I’m trying to get the angle between two quaternions. The quaternions are equal to each other. Unity engine Quaternion.Angle is determining 51.683 degrees.
That quaternion is not normalized. As I understand it, quaternions can do strange things if not normalized. Basically I never touch quaternion components directly because they’re very difficult to understand. What is it you’re really trying to do?
Try this instead. It has an angle of 0.
Quaternion a = Quaternion.Euler(10, 20, 30);
Quaternion b = a;
Debug.Log(Quaternion.Angle(a, b));
Unity reports the quaternion as (0.0f, 0.3f, 0.0f, -0.9f) . So that’s the actual rotation, I’m not manually creating the rotation.
Very similar to this:
Do I need to resort to Euler angles instead of Quaternions for this?
Or do I need to check myself if the quaternions are close, then assume the angle is 0?
The result was 0.03956468. Surprised me, actually.
If I massaged that to give X a non-zero value (such as 0.1f, 90f, 0f), then the angle given is 0.
I suspect there’s some sort of a cross product using colinear vectors at play in the Angle() function, but it’s hard to tell what’s going on without the source code.
I see. I just tried the same code and I’m getting the results you’d expect, between 0 and 3 degrees for something moving in my game (unscaled for time, that’s per frame).
However, you’re dividing by Time.deltaTime? I think you mean to multiply by Time.deltaTime. Edit: never mind about that, I misunderstood.
And I was just using Euler angles to produce a known good quaternion in a frame of reference I understand better. I have no idea why constructing a quaternion like that doesn’t work.
It’s not quite that bad. You have to remember that all the math here is being done in radians and Unity is converting to degrees. The floating point error here is actually 0.0007 radians. That is a very, very tiny error, but since you’ve multiplied by 180/pi it’s gotten bigger.
It’s a limitation of floating point hardware of using using 32-bit floats, there’s nothing that can be done about it. The rule of thumb is to never expect any floating point math to be exactly the result you’d expect, only that it will be very close. And 0.0007 away from the expected result is very, very close.
Thanks. Plugging your values into the Dot function: 00 + 0.30.3 + 00 + 0.90.9 = 0.9. So these values aren’t fully normalized.
Acos(1) = 0. This would’ve given you 0 degrees.
Acos(0.9) = 0.451. Multiply that by 2f * 57.29578f and you get 51.68.
FYI - it appears that Quaternion.ToString only prints the first decimal value, so you’re not getting the full x,y,z,w values. You’ll need to print out these values separately to get more accurate results.
I dug around for the source code for Quaternion.Euler, and ran across this code. It appears to be a mess of casting double to float, take the float result to do more calculations, re-cast to float, etc. You lose a LOT of precision that way.
Thanks for the info here. It wouldn’t seem like a big deal. But in my case I’m setting an animator speed based on it’s estimated angularVelocity. A value of 0.04 every frame means if you’re staring at the gameobject which isn’t rotating, the animation would be playing very slowly, but it’s still detectable. The solution must be to discard values that are close to zero.
I just tried to prove to myself what was happening. True, the debug.log(quaternion) prints the floats to only one decimal. That explains why I was getting a rediculous high angle of 51.
Here is more detailed info on what happens a particular frame:
The current and last rotations are equal.
Using purely double math, the angle would be 0.
But using the floats, the angle could become 0.05.
I’m sure your solution would work. (Note I was not really creating a Quaternion to begin with. I just did it for the sole purpose of troubleshooting the issues I was having with the floating point precisions).