Sunday, December 2, 2012

Rotations in 3D with Matrices

3D Rotation has always been a problem for me because I never really sat down and worked out the math to the point where I can be confident that it would work. Every page I read it on would confuse me and talk about rotations in general, gimbal lock, quaternions, Euler angles, etc. They focused more on the math concepts and less about the implementation. This post is all about just getting it done.

Quick summary: 3D programming uses matrices to turn the objects in the world. In order to rotate objects in OpenGL, for example, we need to manipulate the modelview matrix. Although I'm not all that knowledgeable about OpenGL, websites I have read have said that altering the projection matrix will mess with the lighting and things. I will show you a way to manipulate the matrix with matrices first, then with quaternions in a later post.

Usually, rotation about any line is accomplished by multiplying 7 4x4 matrices together to get the right matrix. To be clear, this matrix will only rotate points. If you are going to rotate vectors or lines, you have to rotate the definition points. The 7 matrices needed to rotate any vector about any line are:

  1. A translation matrix to move the rotation line so that it passes through the origin.
  2. A rotation matrix to rotate the line (axis) about the X-axis to the XZ-plane.
  3. A rotation matrix to rotate the line (axis) about the Y-axis to the Z-axis.
  4. A rotation matrix to rotate the desired angle about the Z-axis.
  5. The inverse of the matrix in step (3).
  6. The inverse of the matrix in step (2).
  7. The inverse of the matrix in step (1).
Step (1) is only needed if the line you want to rotate about doesn't already pass through the origin. You can see that the rotation just moves the line to the Z-axis and does the rotation about that. The thing about these matrices is that we can avoid using trigonometric functions of the angles by repeatedly setting up the following equation, solving for the cosine and sine terms, and then substituting them back into the matrix:

[1, 0,       0,        0;  * [x;  = [xp;
 0, cos(t), -sin(t), 0;     y;      yp;
 0, -sin(t), cos(t), 0;     z;      zp;
 0, 0,        0,       1]    1]       1]

The translation matrix is the equivalent of adding subtracting a vector from the origin to one of the points on the line. The "inverse" is the addition of this vector back to the point. This code assumes the rotation line starts at v0 and ends at v1, and the line itself is the vector v. The translation matrix and its "inverse" is as follows (in Matlab code):

T = [1,0,0,-v0(1);

Tinv =[1,0,0,v0(1);

The code for the rotation matrices are:

Rx = [1, 0,                           0,                          0;
          0, v(3) / sqrt(v(2)^2+v(3)^2), -v(2) / sqrt(v(2)^2+v(3)^2), 0;
          0, v(2) / sqrt(v(2)^2+v(3)^2),  v(3) / sqrt(v(2)^2+v(3)^2), 0;
          0, 0,                           0,                          1];

Ry = [sqrt(v(2)^2+v(3)^2), 0, -v(1),               0;
          0,                   1, 0,                   0;
          v(1),                0, sqrt(v(2)^2+v(3)^2), 0;
          0,                   0, 0,                   1];

Rz = [cos(t), -sin(t), 0, 0;
          sin(t),  cos(t), 0, 0;
          0,       0,      1, 0;
          0,       0,      0, 1];

Note: The Rx matrix depends on the term sqrt(v(2)^2+v(3)^2). This term vanishes when the line is coincident to the X-axis. If this is the case, then the Rx matrix will need to be the identity matrix.

Rotating the point consists of multiply the matrices to the left side of the point. Since rotation matrices are orthogonal matrices, the inverse of the matrix is the transpose. Transforming a point P to P' would be:

P' = Tinv * RxInv * RyInv * Rz * Ry * Rx * T * P

That's it! Happy rotating!

No comments:

Post a Comment