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