10
votes

I have an opengl arbitrary rotation matrix and would like to remove the X & Y axis, leaving me with only the Z axis?

Is this possible? Any pointers on how to do it?

2
What do you mean by "remove"? Rotations are orthonormal transformations, i.e. there is the constraint that the base vectors of the rotation must be perpendicular to each other. - datenwolf
The matrix supplied rotates around all 3 axis. I normally just pass this to glMultMatrixf directly but in certain circumstances I only want to rotate on the Z axis but still with the supplied matrix. - Paul S
I don't know how to tell you this, but a rotation is always around a single axis, the rotation axis; this rotation axis can be extracted from the matrix by determining its eigenvalue. What you probably have is a matrix composed of several individual rotations, i.e. some kind of Eurler angle, however this composite rotation still has only ONE axis. However you have a problem then: Euler angles are not unambigous, i.e. even with a fully defined set of Euler angles you still need some additional information to exactly determine a rotation. Omitting an additional value doesn't help. - datenwolf
@datenwolf: Agreed, The matrix is a combination of rotations, I guess my question is can I extrapolate one of those rotations from the resultant matrix? - Paul S

2 Answers

7
votes

Just thinking out loud here, but can't you use the matrix to rotate a vector like (1,0,0), then do atan2(y,x) to see how much it's rotated and then build a new matrix to rotate through the Z axis by that much?

4
votes

In a rotation that is only around the z-axis, the z axis should remain unchanged. So the above recommendation is sort of the reverse of what you want.

Let's assume you have an arbitrary OpenGL matrix:

    | r_xx r_xy r_xz t_x |
    | r_yx r_yy r_yz t_y |
M = | r_zx r_zy r_zz t_z |
    |  0    0    0    1  |

Where the t_i elements are translations and the r_jk elements are components of rotation. You want a matrix that looks like this:

| cos(th) sin(th)  0  t_x |
|-sin(th) cos(th)  0  t_y |
|  0       0       1  t_z |
|  0       0       0   1  |

Unless the matrix has scaling factors or is close to a singularity, you should be able to get this by just zeroing out the z parts of the matrix and then re-normalizing the columns. Since an OpenGL matrix is column major order:

double xLen = sqrt(M[0]*M[0] + M[1]*M[1]); // Singularity if either of these
double yLen = sqrt(M[4]*M[4] + M[5]*M[5]); //  is equal to zero.

M[0]/=xLen; M[1]/=xLen; M[2]=0; // Set the x column
M[4]/=yLen; M[5]/=yLen; M[6]=0; // Set the y column
M[8]=0; M[9]=0; M[10]=1;        // Set the z column
//Don't change the translation column