The best way I found to create a rotation matrix with all three axes is with quaternions. The following code is C#:
Initialize
The Quaternion class has four properties: W, X, Y and Z. "W" is the angle, and the other represent the axis. I will only use unit quaternions, meaning the rotation is around one of the three axes only. You initialize an identity quaternion by setting them to (1, 0, 0, 0). I create one for each rotation like so:
var rotx = new Quaternion(Rotation.X, 1, 0, 0); var roty = new Quaternion(Rotation.Y, 0, 1, 0); var rotz = new Quaternion(Rotation.Z, 0, 0, 1);
The quaternion's constructor initializes those arguments as:
double r = (angle * (Math.PI / 180)); W = (float)Math.Cos(r / 2); double s = Math.Sin(r / 2); X = (float)(x * s); Y = (float)(y * s); Z = (float)(z * s);
Multiply
Next, we combine them all into one quaternion:
var rot = rotx * roty * rotz;
The method that multiplies two quaternions is defined as follows:
public static Quaternion operator *(Quaternion a, Quaternion b)
{
var c = new Quaternion();
c.W = a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z;
c.X = a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y;
c.Y = a.W * b.Y - a.X * b.Z + a.Y * b.W + a.Z * b.X;
c.Z = a.W * b.Z + a.X * b.Y - a.Y * b.X + a.Z * b.W;
return c;
}
Rotate
To get the matrix I needed to pass to OpenGL, I created another class called "Matrix", which is a 4x4 matrix containing a 16 element array. Then a method takes the quaternion and adds the rotation to this matrix. It took a while to find a way to do this that worked with OpenGL, but I finally found it in the .net framework.
var matrix = new Matrix();
matrix.Rotate(rot); //"rot" being the quaternion from before.
public void Rotate(Quaternion rotation)
{
float x2 = rotation.X + rotation.X;
float y2 = rotation.Y + rotation.Y;
float z2 = rotation.Z + rotation.Z;
float xx = rotation.X * x2;
float xy = rotation.X * y2;
float xz = rotation.X * z2;
float yy = rotation.Y * y2;
float yz = rotation.Y * z2;
float zz = rotation.Z * z2;
float wx = rotation.W * x2;
float wy = rotation.W * y2;
float wz = rotation.W * z2;
Values[0, 0] = 1.0f - (yy + zz);
Values[0, 1] = xy + wz;
Values[0, 2] = xz - wy;
Values[1, 0] = xy - wz;
Values[1, 1] = 1.0f - (xx + zz);
Values[1, 2] = yz + wx;
Values[2, 0] = xz + wy;
Values[2, 1] = yz - wx;
Values[2, 2] = 1.0f - (xx + yy);
}
No comments:
Post a Comment