I have a unit vector representing the direction I want to "look" and a unit vector for up. They are orthogonal. How can I get the quaternion that represents that orientation from those two vectors?
2 Answers
If you have a method of getting the quaternion of the rotation matrix then just get the lookat matrix and use that method.
otherwise you can get the rotation R1
from (0,0,-1) to the look vector, This results in a lookat transformation with an arbitrary up.
then find that arbitrary up with R1*(0,1,0)
and then find the rotation between that and the resulting up with the look vector as the rotation axis.
Concatenate the results and that will be the final transformation.
Something like this should do it:
Quaternion CreateFromLookAxis(Vector3 forward, Vector3 up)
{
var m2 = Vector3.Normalize(forward); // Just in case.
var m0 = Vector3.Normalize(Vector3.Cross(up, m2));
var m1 = Vector3.Cross(m2, m0);
var r0 = m0.x + m1.y + m2.z;
var result = new Quaternion();
if (r0 > 0f)
{
var r1 = (float)Math.Sqrt(r0 + 1f);
result.w = r1 * 0.5f;
r1 = 0.5f / r1;
result.x = (m1.z - m2.y) * r1;
result.y = (m2.x - m0.z) * r1;
result.z = (m0.y - m1.x) * r1;
return result;
}
// else
if ((m0.x >= m1.y) && (m0.x >= m2.z))
{
var r1 = (float)Math.Sqrt(((1f + m0.x) - m1.y) - m2.z);
var r2 = 0.5f / r1;
result.x = 0.5f * r1;
result.y = (m0.y + m1.x) * r2;
result.z = (m0.z + m2.x) * r2;
result.w = (m1.z - m2.y) * r2;
return result;
}
// else
if (m1.y > m2.z)
{
var r1 = (float)Math.Sqrt(((1f + m1.y) - m0.x) - m2.z);
var r2 = 0.5f / r1;
result.x = (m1.x + m0.y) * r2;
result.y = 0.5f * r1;
result.z = (m2.y + m1.z) * r2;
result.w = (m2.x - m0.z) * r2;
return result;
}
// else
{
var r1 = (float)Math.Sqrt(((1f + m2.z) - m0.x) - m1.y);
var r2 = 0.5f / r1;
result.x = (m2.x + m0.z) * r2;
result.y = (m2.y + m1.z) * r2;
result.z = 0.5f * r1;
result.w = (m0.y - m1.x) * r2;
return result;
}
}