Q: how to draw a disk (gluDisk) always facing the user?

Hi,

I have to draw a disk (gluDisk) at (x, y, z), which should always face directly to the user. To simplify the problem, my projection is always parallel to z-axis. I use the following working but ugly algorithm. Do you have a better algorithm for this purpose? Please help. Thanks.

GLint viewport[4];
GLdouble projM [16];
GLdouble modelViewMat[16];
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev(GL_PROJECTION_MATRIX, projM);
glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMat);

double wx, wy, wz;
gluProject (x, y, z, modelViewMat, projM, viewport, &wx, &wy, &wz);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev(GL_PROJECTION_MATRIX, projM);
glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMat);
gluUnProject (wx, wy, wz, modelViewMat, projM, viewport, &x, &y, &z);
glTranslated(x, y, z);

 gluDisk(m_pQuarObj, .radius, 2.*radius, 25, 1);
 glPopMatrix();

I used the gluProject and gluUnProject because I didn’t sucessfully compute the new position of (x, y, z) by using GL_MODELVIEW_MATRIX. I glGetDoublev first and then multiplied it with (x, y, z), but the result was not what I wanted.

Good god man!

Try this:

First get the modelview matrix.

It’s third row will be the camera vector in the disk’s coordinate system. It’ll be normalized too if you haven’t done any scaling. We want a rotation to take the unit z vector (which is the way the disk initially faces) in the direction of the camera.

To do this you’ll have to rotate around the axis that is the cross product of these two vectors v1 = (m[2],m[6],m[10]) and v2 = (0,0,1):

rotation axis = v1 x v2 = (m[6], -m[2], 0)

Rotate by an angle you can get from the dot product of v1 and v2 (v1 * v2 = |v1| |v2| cos(theta) ):

i.e. rotation angle = acos(m[10]);

so your total code is:

GLdouble m[16];
glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMat);
glPushMatrix();
glRotatef(acos(m[10]), m[6], -m[2], 0.0);
// Draw disk here
glPopMatrix();

Don’t forget to convert that angle to degrees, or it won’t work. It’s also possible that I need a minus sign in the angle.

Let me know if this works or if I made a math mistake. I haven’t actually tried this particular code.

– Zeno

Hi Zeno,

Thanks for this great information. I will try it next Monday. Do you happen to know the source that can help me better understand the modelview matrix? You mentioned that the 3rd row of it is the camera position for my disk coornidates. I wish I can also grasp this kind of knowledge. Thanks for your greap help.

Regards.

Tony

Do you happen to know the source that can help me better understand the modelview matrix? You mentioned that the 3rd row of it is the camera position for my disk coornidates. I wish I can also grasp this kind of knowledge. Thanks for your greap help.

There’s no real source, but here’s how you know. Initially, your camera position is a vector like c = (0,0,1).

Whatever rotations you apply to your objects via the modelview matrix move them with respect to this camera. From the object’s point of view, the camera gets rotated the opposite direction. So to get the camera’s position from the object’s point of view, we have to rotate it by the inverse of the rotation part of the modelview matrix.

If this is the modelview matrix:

m[0] m[4] m[8] m[12]
m[1] m[5] m[9] m[13]
m[2] m[6] m[10] m[14]
m[3] m[7] m[11] m[15]

The part that performs rotations is:

m[0] m[4] m[8]
m[1] m[5] m[9]
m[2] m[6] m[10]

The inverse of a rotation matrix is just the transpose, so this is:

m[0] m[1] m[2]
m[4] m[5] m[6]
m[8] m[9] m[10]

Note that any transformations you do other than rotations that can screw up these elements will cause this method not to work. Scaling for instance will mess it up.

If we multiply your camera vector (0,0,1) by this matrix, we get the vector (m[2], m[6], m[10]). This is where your objects think the camera is so you need to rotate your disk vector towards this vector as explained above.

– Zeno

Thanks Zeno for the detailed explanation. I have implemented your algorithm. The only modifications (minor) I made are

  1. to use -acos(m[10]) instead of acos(m[10]) (as you warned)
  2. to translate (in addition to rotation) to the particular location (x, y, z)

Then everything worked exactly as I wanted. Thanks for the teaching.

Tony

~ For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life. ~ (John 3:16)

Sweet, I’m glad it worked I’m always leery when I post code that I haven’t tested.

– Zeno