There is definitely going to be float error no matter what.
+/- 0.001 is about where I’d expect it. Maybe a little smaller, but I have no expectation of accuracy beyond 4 sig fractional values (I consider the 1’s spot sig value even if 0, as unity often prefers degrees).
Quaternion.FromToRotation is unfortunately an internal operation, so I’m not 100% sure how they implement it. But I’m willing to bet somewhere in their they perform a scaling (multiplication, power, root, something like that) that shreds the sig value range down to the 3 sig values you see. Resulting in all operations after that to suffer from that same error.
An option you have is to implement your own calculation yourself for FromToRotation:
using UnityEngine;
using System.Collections;
public class TestScript02 : MonoBehaviour {
// Use this for initialization
void Start () {
var v1 = Vector3.up;
var v2 = VectorUtil.RotateAroundAxis(v1, 0.0005f, Vector3.right);
var q1 = Quaternion.FromToRotation(v1, v2);
var q2 = VectorUtil.FromToRotation(v1, v2);
Debug.Log(Vector3.Angle(v1, v2).ToString());
Debug.Log(q1.eulerAngles.ToDetailedString());
Debug.Log(q2.eulerAngles.ToDetailedString());
}
}
public static class VectorUtil
{
public static Quaternion FromToRotation(Vector3 v1, Vector3 v2)
{
var a = Vector3.Cross(v1, v2);
var w = Mathf.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude) + Vector3.Dot(v1, v2);
return new Quaternion(a.x, a.y, a.z, w);
}
public static Vector3 RotateAroundAxis(Vector3 v, float a, Vector3 axis, bool bUseRadians = false)
{
if (bUseRadians) a *= Mathf.Rad2Deg;
var q = Quaternion.AngleAxis(a, axis);
return q * v;
}
public static string ToDetailedString(this Vector3 v)
{
return System.String.Format("<{0}, {1}, {2}>", v.x, v.y, v.z);
}
}
Just got the q2 using my own implementation to return:
Vector3.Angle didn’t even get that level of precision.