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