views:

683

answers:

5

I've just started playing with OpenGl to render a number of structure each comprising a number of polygon. Basically I want to perform the equivalent of setting a camera at (0,0,z) in the world (structure) coordinates and rotate it about the x,y and z-axes of the world axes (in that order!) to render a view of each structure (as I understand it it common practice to do use the inverse camera matrix). Thus as I understand it I need to translate (to world origin i.e. (0,0,-z)) * rotateZ*rotateY*rotateX * translate (re-define world origin see below)

So I think I need something like:

//Called when the window is resized
void handleResize(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(9.148, (double)w / (double)h, 800.0, 1500.0);
}

float _Zangle = 10.0f; 
float _cameraAngle = 90.0f;

//Draws the 3D scene
void drawScene() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
    glLoadIdentity(); //Reset the drawing perspective

    glTranslatef(0.0f, 0.0f, -z); //Move forward Z (mm) units
    glRotatef(-_Zangle, 0.0f, 0.0f, 1.0f); //Rotate "camera" about the z-axis
    glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f); //Rotate the "camera" by camera_angle about y-axis
    glRotatef (90.0f,1.0f,0.0f,0.0f); // rotate "camera" by 90 degrees about x-axis
    glTranslatef(-11.0f,189.0f,51.0f); //re-define origin of world coordinates to be (11,-189,-51) - applied to all polygon vertices

glPushMatrix(); //Save the transformations performed thus far

glBegin(GL_POLYGON);


    glVertex3f(4.91892,-225.978,-50.0009);
        glVertex3f(5.73534,-225.978,-50.0009);
        glVertex3f(6.55174,-225.978,-50.0009);
        glVertex3f(7.36816,-225.978,-50.0009);
        .......// etc
glEnd();
glPopMatrix();

However when I compile and run this the _angle and _cameraAngle seem to be reversed i.e. _angle seems to rotate about y-axis (Vertical) of Viewport and _cameraAngle about z-axis (into plane of Viewport)? What am I doing wrong?

Thanks for taking the time to read this

+1  A: 

The z axis is coming from the center of the monitor into you. So, rotating around the z-axis should make the camera spin in place (like a 2D rotation on just the xy plane). I can't tell, but is that what's happening here?

Claudiu
+3  A: 

The short answer is: Use gluLookAt(). This utility function creates the proper viewing matrix.

The longer answer is that each OpenGL transformation call takes the current matrix and multiplies it by a matrix built to accomplish the transformation. By calling a series of OpenGL transformation function you build one transformation matrix that will apply the combination of transformations. Effectively, the matrix will be M = M1 * M2 * M3 . . . Mathematically, the transformations are applied from right to left in the above equation.

Your code doesn't move the camera. It stays at the origin, and looks down the negative z-axis. Your transformations move everything in model space to (11,-189,-51), rotates everything 90 degrees about the x-axis, rotates everything 90 degrees about the y-axis, rotates everything 10 degrees about the z-axis, then translates everything -z along the z-axis.

EDIT: More information

I'm a little confused about what you want to accomplish, but I think you want to have elements at the origin, and have the camera look at those elements. The eye coordinates would be where you want the camera, and the center coordinates would be where you want the objects to be. I'd use a little trigonometry to calculate the position of the camera, and point it at the origin.

In this type of situation I usually keep track of camera position using longitude, latitude, and elevation centered on the origin. Calculating x,y,z for the eye coordinates is simplyx = elv * cos(lat) * sin(lon), y = elv * sin(lat), z = elv * cos(lat) * cos(lat).

My gluLookAt call would be gluLookAt(x, y, z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

You could rotate the up on the camera by changing the last three coordinates for gluLookAt.

Mr. Berna
If I understand this correctly what you are basically doing is setting the camera coordinates (x,y,z) in world coordinates and pointing the camera at the redefined origin(0,0,0). Correct?
mark g
Yes, I think. Your use of the word "redefined" confuses me. gluLookAt() allows the programmer to work as if the model is in world coordinates. You specify camera coordinates in world space, and model coordinates in world space, and gluLookAt() takes care of the transformation for you.
Mr. Berna
I say redefined as I want to shift the actual world origin to a more convenient location situated roughly centrally relative to all my structures. But I could equally use centre= (11,-189,-51) with gluLookAt(), and not apply the translatethe structure coordinates. But now I have to figure out where the "rotated" up points from z and the angles.
mark g
You could use gluLookAt(x+11, y-189, z-51, 11, -189, -51, 0, 1, 0) to look at your center point. x, y, and z would be calculated from your stored values for longitude, latitude, and elevation in a volume centered at your center point. It should be easy to implement a user interface that can increment longitude, latitude, and elevation to move the camera around your model. You can calculate the vector for up, or you can hack it with with glRotate(angle, 0, 0, 1) just before gluLookAt().
Mr. Berna
A: 

It's possible that you are encountering Gimbal Lock. Try removing one of the rotations and see if things work the way they should.

While it's true that you can't actually move the camera in OpenGL, you can simulate camera motion by moving everything else. This is why you hear about the inverse camera matrix. Instead of moving the camera by (0, 0, 10), we can move everything in the world by (0, 0, -10). If you expand those out into matrices, you will find that they are inverses of each other.

I also noticed that, given the code presented, you don't need the glPushMatrix()/glPopMatrix() calls. Perhaps there is code that you haven't shown that requires them.

Finally, can you provide an idea of what it is you are trying to render? Debugging rotations can be hard without some context.

Daniel Yankowsky
I am trying to view some anatomical structures whose coordinates are contoured relative to a CT study (which defines the world frame). Essentially the local (viewing) coordinate frame is defined by rotating the world frame about each of the three axes.
mark g
A: 

Short answer :Good tip

Longer answer: Yes the order of matrix multiplication is clear... that's what I meant by inverse camera matrix to indicate moving all the world coordinates of structures into the camera coordinates (hence the use of "camera" in my comments ;-)) instead of actually translating and rotating camera into the world coordinates.

So if I read between the lines correctly you suggest something like:

void drawScene() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
    glLoadIdentity(); //Reset the drawing perspective
gluLookAt(0.0,0.0,z,11.0,-189.0,-51.0,0.0,1.0,0.0); //eye(0,0,z) look at re-defined world origin(11,-189,-51) and up(0.0,1.0,0.0)

    glRotatef(-_Zangle, 0.0f, 0.0f, 1.0f); //Rotate "camera" (actually structures) about the z-axis
    glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f); //Rotate the "camera" (actually structures!) by camera_angle about y-axis
    glRotatef (90.0f,1.0f,0.0f,0.0f); // rotate "camera" (actually structures) by 90 degrees about x-axis


glPushMatrix();

Or am I still missing something?

mark g
I edited my previous answer to address these items.
Mr. Berna
A: 

I think you are mixing axes of your world with axes of the camera,

GLRotatef only uses axes of the camera, they are not the same as your the world axes once the camera is rotated.

fa.