Hello there,
I’d like to to get the quaternion between 2 vectors from and to (like LookRotation), while fixing the rotation around a specific axis ( Y ).
How can it be done?
Use copies of the vectors with y set to 0. With everything “on the ground”, the spin will automatically be flat, around y. If you want to add that to the old spin, newYonlySpin*oldSpin should do it.
I dont understand.
I have :
from = 0, 0, -1
to = 0, 0, 1
up = 0, -1, 0
if I do : Quaternion.FromToRotation(from, to) * up
I get : 0,1,0 (because rotation seems to be made around X axis).
but I want 0, -1, 0 (rotation around Y axis)
You get a nice y-spin for anything except 180 degrees. But you’re right, Unity just feels like doing an “up and over” x-spin for 180(*). There’s no way to change that. You can just hand-check “if the angle is almost 180, use (0,180,0) for the rotation”. In practice that either never happens, or there are nicer ways depending on exactly your game.
(*)Bizarrely, printing it (eulerAngles) gives (0,180,180), which is an alternate way to write (180,0,0).
You could write your own FromToRotation.
Basically to get the from/to of 2 vectors you set the imaginary portion to the cross product of the 2 vectors, and the real (w) to the scaled dot product of them… and normalize all that for good measure.
You have to account for when the cross product is a zero vector, meaning they’re parallel. If this happens you then need to know if they’re opposing or the same. Same is of course no rotation, and opposing is 180 degrees around ANY axis (unity just happens to use x I guess…)
So allow passing in that vector:
public static Quaternion FromToRotation(Vector3 v1, Vector3 v2)
{
var a = Vector3.Cross(v1, v2);
double w = System.Math.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude) + Vector3.Dot(v1, v2);
if (a.sqrMagnitude < 0.0001f)
{
//the vectors are parallel, check w to find direction
//if w is 0 then values are opposite, and we should rotate 180 degrees around some axis
//otherwise the vectors in the same direction and no rotation should occur
return (System.Math.Abs(w) < 0.0001d) ? new Quaternion(0f, 1f, 0f, 0f) : Quaternion.identity;
}
else
{
return new Quaternion(a.x, a.y, a.z, (float)w).normalized;
}
}
public static Quaternion FromToRotation(Vector3 v1, Vector3 v2, Vector3 defaultAxis)
{
var a = Vector3.Cross(v1, v2);
double w = System.Math.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude) + Vector3.Dot(v1, v2);
if (a.sqrMagnitude < 0.0001f)
{
//the vectors are parallel, check w to find direction
//if w is 0 then values are opposite, and we should rotate 180 degrees around the supplied axis
//otherwise the vectors in the same direction and no rotation should occur
return (System.Math.Abs(w) < 0.0001d) ? new Quaternion(defaultAxis.x, defaultAxis.y, defaultAxis.z, 0f).normalized : Quaternion.identity;
}
else
{
return new Quaternion(a.x, a.y, a.z, (float)w).normalized;
}
}
I hope I have my math right… I ran some tests, I think it is.
Thanks guys for your help, I’ll give it a try!