Determining angles from Modelview Matrix

I do a number of translations and rotations to set the view for my scene. Think of a camera on the end of a multi-jointed robotic arm. I translate and rotate through each segment until I have my camera set. This all works fine but for some other things I’m doing, I need to know the resulting angle of the camera in world coordinates in relation to the x and z axis.

I have managed to do this by getting a copy of the matrix with glGetFloatv(GL_MODELVIEW_MATRIX,&mv[0]) and then copying the points (0,0,0) and (0,1,0) and using their translated locations to determine the angle. This works but due to the math, only returns an angle from 0 to 90 for any orientation. To go back and adjust this for the particular x, y, and z directions is becoming quite cumbersome.

I was wondering if there’s an easier way to take the modelview matrix and extract the angles.

Any thoughts would be greatly appreciated.

you could convert the modelview matrix to a quaternion and extract the rotation from it. quaternions have alot of math involved though. look for exiting classes.

If you invert the modelview matrix, you will end with a matrix that has the reference system axis in their columns (and the origin: the translated position done with accumulated glTranslatef is in the last column)

| Ux Vx Wx Tx |
| Uy Vy Wy Ty |
| Uz Vz Wz Tz |
| 0 0 0 1 |

Then if you compare those axis with the identity axis, you will have the angles. Here is the pseudocode:

float mdlv[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mdlv);
Matrix4 mat(mdlv); //This matrix constructor loads the float array transposed. Have this in mind, because OpenGL is column major.

Vector3 i(1,0,0);
Vector3 j(0,1,0);
Vector3 k(0,0,1);

Vector3 u,v,w;
u = mat.GetColumn(0).xyz();
v = mat.GetColumn(1).xyz();
w = mat.GetColumn(2).xyz();

//You can avoid the next 3 lines if you are really sure that your modelview matrix has no scales (glScalef applications)

float alpha, beta, gamma;
alpha = acos(u.Dot(i)) * 180.0f / (floatM_PI;
beta = acos(v.Dot(j)) * 180.0f / (float)M_PI;
gamma = acos(w.Dot(k)) * 180.0f / (float)M_PI;

A more efficient solution is take the modelview’s 3x3 left-upper submatrix and transpose it (remember normalize the axis before the dot products)
Transposing a non-scaled rotation matrix has the same effect than inverting it, but is much more efficient.

NK47, thanks for the suggestion but I think that’s more involved than what I was trying to do.

Ffelagund, thanks for the info. I think that’s exactly what I was looking for. I figured there had to be some way to extract the angles from the matrix. I won’t have time to work on this until this afternoon so I may have some follow up questions later.

Thanks again,

I forgot to say that this only true if the 3x3 submatrix is orthonormal (has not scales), so its unnecessary normalize the axis because they must already be, for the previous step.

I’ve had some time to play around with your approach and I’ve found the code can be simplified down to this since I’m not doing any scaling.

viewAngleX = acos(mv[0]) / PI * 180.0f;
viewAngleY = acos(mv[5]) / PI * 180.0f;
viewAngleZ = acos(mv[10]) / PI * 180.0f;

This is much more efficient than what I was doing before but still results in angles from 0 to 180. The problem is that I need to know the exact position the camera is looking at. If I start with a translate about the X axis of 200 degrees, I need to be able to determine the camera is looking 200 degress and not just 160.

I thought that I could examine all 3 angles and determine the orientation but there is still ambiguity. If you rotate about the X axis by 200 degrees you will get the same results as rotating about the X axis by 160 degrees followed by rotating about the z axis by 180 degrees.

Any thoughts on this?

Thanks again for your input.

If you use the method I wrote up, you can get the camera view vector instantly
The camera’s view vector is the third column (W vector), and the camera position is the fourth (T)
Try to think in axis vectors rather than in angles :slight_smile:

P.D: The method you last posted will only work in certain cases (to be precise, only will work when the camera’s axis be aligned with the world axis). I suggest you avoid it, because if you have a camera that has some axis swapped, your method wont work at all.