I’ve looked around and the general consensus is “make a lookat matrix, convert to quaternion”. But this just doesn’t seem to work. I get a rotation but it’s not one that correlates properly to the direction vector. I’m no maths whizz and I barely understand quaternions (though other parts of the program that manipulate quaternions are working great) and so I can’t determine the problem.
Thinking it might be a problem to do with left vs. right handed matrices, I’ve tried swapping the column and row numbers but it had no effect. It’s not perpendicular to what I am after or inverted on X or anything; it’s just pointing in a seemingly random direction.
I have a velocity which I normalize and then I want to turn this forward vector into a quaternion for use in my rendering pipeline. The idea is that the projectile will point in the direction of movement rather than north, as missiles rarely do such a thing.
The math isn’t that bad, so long as you don’t try to visualize 4-dimensional quaternion space…
A quaternion stores an axis of rotation and an angle. The quaternion for a rotation should be normalized. Generally, the real component of the quaternion is related to the angle, while the imaginary parts store the axis (and the angle…). The real component is cosine of the angle, while the imaginary part is the unit vector along the axis multiplied by the sine of the angle.
Assuming the forward vector and the original direction are unit vectors, the cosine of the angle is the dot product of them. Also, original cross forward is perpendicular to the two vectors (i.e. along the axis of rotation) and has magnitude of the sine of the angle. The resulting quaternion, then, has the dot product in the real part and the cross product in the imaginary parts.
If this doesn’t work, then try swapping the order in which you cross the vectors.
Here are is some piece of code converting a quaternion to a rotation matrix and vector/angle to quaternion. Actually the vector in the second code part is the rotation axis.
template<class T>
void Quaternion<T>::getRotationMatrix(Matrix4<T>& matrix)
{
T len = this->length();
T s = (len > (T)0) ? ((T)2 / len) : (T)0;
T xs = x * s, ys = y * s, zs = z * s;
T wx = w * xs, wy = w * ys, wz = w * zs;
T xx = x * xs, xy = x * ys, xz = x * zs;
T yy = y * ys, yz = y * zs, zz = z * zs;
matrix.get(0,0) = (T)1 - (yy + zz); //11
matrix.get(0,1) = xy - wz; //12
matrix.get(0,2) = xz + wy; //13
matrix.get(0,3) = (T)0; //14
matrix.get(1,0) = xy + wz; //21
matrix.get(1,1) = (T)1 - (xx + zz); //22
matrix.get(1,2) = yz - wx; //23
matrix.get(1,3) = (T)0; //24
matrix.get(2,0) = xz - wy; //31
matrix.get(2,1) = yz + wx; //32
matrix.get(2,2) = (T)1 - (xx + yy); //33
matrix.get(2,3) = (T)0; //34
matrix.get(3,0) = (T)0; //41
matrix.get(3,1) = (T)0; //42
matrix.get(3,2) = (T)0; //43
matrix.get(3,3) = (T)1; //44
}
template<class T>
void Quaternion<T>::setRotation(Vector3<T>& axis, T& angle)
{
T len = length(axis);
if(len > (T)0.00001)
{
T scale = sin((T)(0.5) * angle) / len;
x = axis.x * scale;
y = axis.y * scale;
z = axis.z * scale;
w = cos((T)(0.5) * angle);
}
else
{
x = (T)0;
y = (T)0;
z = (T)0;
w = (T)1;
}
}