glRotatef() Transformation doesn't "stick"

Started by
10 comments, last by eggmatters 13 years, 6 months ago
Hi all,

I am trying to implement user input to navigate around a generated terrain. I am using SDL to create the window, and manage keystroke events. All of the drawing, rendering etc. is in OpenGL. My problem is this:
Instead of using gluLookAt(), I have written custom routines as indicated in the "red book" (Chapter 3 - Viewing Advanced try this section in 'Viewing Transformations' section of that chapter.) My glTranslatef() functions move the POV based on user input, BUT when you 'pivot' you point of view (Rotate about the y-axis) The view rotates around the POV. But - as soon as the keyup event occurs, the viewpoint "Snaps" back to wherever it was before the last tranformation occurred. So basically, it's like walking around, but whenever you spin, you are immediately forced back into the heading you had before you attempted to spin.
I am somewhat new to OpenGL but feel fairly comfortable with most of the concepts. I have attempted a wide variety of fixes to troubleshoot this to no avail. The following is my code, commented to try to illustrate what I'm trying to do. This code is merely proto-type for learning purposes and won't resemble anything I would do in production so any comments concerning optimization, design suggestions are certainly welcome, but I would really appreciate some help concerning this.

//following values are incremented / decremented per event keystrokefloat Ang = 0.0;float x_pos = 0.0;float y_pos = 0.0;float z_pos = 0.0;bool x_rot = false;bool y_rot = false;float x_input = 0.0;float y_input = 4.85;float z_input = 0.0; // This function actually builds the terrainvoid buildTerrain(){ // Here, an 80X80 array is generated with height values to use as vertices for my GL_QUADS    //implementing glList since these values are static.    glNewList(1, GL_COMPILE);    // Terrain rendering routine goes here       glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);    glBindTexture(GL_TEXTURE_2D, myTexture);//texture mapping for terrain    glBegin(GL_QUADS);//draws the polygons based the values obtained by the array generated above (or described rather.)        for(int x = 0; x<tWidth-1; x++){        for(int y = 0; y<tHeight-1; y++){            glTexCoord2f(0.0f, 0.0f);            glVertex3f(x+0, terrain[x+0][y+1], y+1);            glTexCoord2f(1.0f, 0.0f);            glVertex3f(x+1, terrain[x+1][y+1], y+1);            glTexCoord2f(1.0f, 1.0f);            glVertex3f(x+1, terrain[x+1][y+0], y+0);            glTexCoord2f(0.0f, 1.0f);            glVertex3f(x+0, terrain[x+0][y+0], y+0);                    }    }     glEnd();    glEndList();    }//Here is where I attempt to perform all of my transformations:void mainLoop() {    while(true) {        processEvents();//y,x,z *_input are incremented based on keypresses (the events are mapped in code below.)        y_input += y_pos;        x_input += x_pos;        z_input += z_pos;                // Graphical commands...//We are in the GL_MODELVIEW matrix mode here. This was the last matrix mode set in the function: setupOpenGL(). //I didn't provide that code since I'm fairly certain it's not relavant. It sets the perspective, lighting, loads textures, and fog.        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        glLoadIdentity();//x_rot set to "true" if the right arrow key is depressed, when true,the polygons above rotate counter clockwise.              if (x_rot) {            Ang += .5;           glRotatef(Ang, 0.0, 1.0, 0.0);                } // if x_rot is false, no rotation occurs but the viewing plans "snaps //back to the world coordinates it had before the rotate call (but after the translate calls.) //y_rot set to "true" if the left arrow key is depressed, when true,the polygons above rotate clockwise.          if (y_rot) {           Ang += .5;           glRotatef(Ang, 0.0, -1.0, 0.0);            }//This translate function sets the user at eye level with the rendered terrain. removing this does not affect the rotation bevavior        glTranslatef(-tWidth/2, -12, -tHeight/2);//This translation works as intended        glTranslatef(x_input, y_input, z_input);        glCallList(1); // <--(Render terrain from list)        SDL_GL_SwapBuffers();            }}// Handle SDL keypressesvoid handleKeys(SDL_keysym* keysym, bool state) {//the state variable is true if a key is pressed down, false when the key is released.    if (state) {       switch(keysym->sym) {         case SDLK_ESCAPE:                 endProgram(0);              break;         case SDLK_UP:             y_pos -= .10;             break;         case SDLK_DOWN:             y_pos += .10;             break;//x and z transformations are set similarly.//tell main() that a rotation is occuring.          case SDLK_RIGHT:             x_rot = true;             break;         case SDLK_LEFT:             y_rot = true;             break;       }    } else {         switch(keysym->sym) {            case SDLK_ESCAPE:                    endProgram(0);                 break;            case SDLK_UP:                y_pos = 0.0;                break;            case SDLK_DOWN :                y_pos = 0.0;                break;  //tell main() to stop rotating. Reset the Angle about which to rotate to zero.            case SDLK_RIGHT:                 Ang = 0;                 x_rot = false;                 break;            case SDLK_LEFT:                 Ang = 0;                 y_rot = false;                 break;            }     }          } // Process SDL eventsvoid processEvents() {    SDL_Event event;    while(SDL_PollEvent(&event)) {        switch(event.type) {            case SDL_KEYDOWN:                   handleKeys(&event.key.keysym, true );                break;            case SDL_KEYUP:                handleKeys(&event.key.keysym, false);                   break;            case SDL_QUIT   : endProgram(0); break;        }            }    }


Sorry for the amount of code I posted. This issue is really nagging me and I have tried the following means to correct it:
use push/pop matrix to retain the rotated view. As anticipated, this achieved the opposite effect.
Change the Matrix mode to GL_PROJECTION for the rotation transformations only. This worked but the x y and z coords for my translation (even though I switched back to GL_MODELVIEW and called glLoadIdentity(). I was skeptical of this however since the red book and all other sources I've read concerning viewing transformations make absolutely no mention of changing the matrix mode when using rotate as a viewing transformation.

Whew. Sorry for the diatribe but any ideas would help. Thanks!
Advertisement
At the beginning of mainLoop, you call glLoadIdentity. This loads the identity matrix on the current stack, wiping any previous values on the stack. You then only apply a rotation if x_rot or y_rot are true. So once you let go of the key and cause those variables to be false, the rotation is not applied any longer.

To fix this, you should be accumulating the rotation amounts into variables like you do with the x/y/z position and applying them via glRotatef always.

In other words, change x_rot and y_rot to floats that represent rotation about those axes. In the key down handling, add some value to x_rot or y_rot, depending. In mainloop, call glRotatef(x_rot, 1,0,0) and glRotate(y_rot,0,1,0) without guarding them with if statements.
Thanks,

That makes sense. I had attempted to do something like that, but still had the if statements surrounding the rotation blocks, I believe. And it works. Thank you. Now this begs another question:
Now, my forward / backward translation occurs along the "world" z axis. I will research this but, without using gluLookAt(), what is the best recommended method for "re-aligning" the Z-axis to now be the POV once a rotation is complete? Should I alter the GL_PERSPECTIVE matrix? This makes sense, but is it costly or not the correct way to achieve this?
Thanks much for your help!
I'll take a wild stab at the new problem,
Could you just convert your view rotation (y axis?) to radians, use it to come up with a vector along x/z that becomes "forwards/backwards"?
to onfu: That's what I was thinking of doing. Just create a callable routine that will do just that. Another option would be changing the viewport to orient towards that new vector, although the vector computation would still be required. It would probably be easiest to keep it in the MODELVIEW matrix. This seems like a pretty straightforward transformation. What is industry standard for this sort of thing? The "red book" uses a flight simulator as an example but it doesn't mention anything about re-orienting your axes for rotational changes - kind of implying that openGL does that for you.
Quote:Original post by eggmatters
to onfu: That's what I was thinking of doing. Just create a callable routine that will do just that. Another option would be changing the viewport to orient towards that new vector, although the vector computation would still be required. It would probably be easiest to keep it in the MODELVIEW matrix. This seems like a pretty straightforward transformation. What is industry standard for this sort of thing? The "red book" uses a flight simulator as an example but it doesn't mention anything about re-orienting your axes for rotational changes - kind of implying that openGL does that for you.
You don't need to modify any matrices or transforms (particularly not the viewport or projection transforms) in order to move your object in the direction it's facing.

Typically, when using the fixed-function pipeline you would specify the position of your object using glTranslate*(). The position itself you can store and update in any way you see fit. It's common to update a position as follows (e.g.):
position += forward_direction * speed * time_delta;
So all you need is a forward direction vector.

Depending on your needs, you can easily construct the forward direction vector using trig as suggested previously. For other cases, you may want to build a transform representing the object's orientation and extract the direction vectors (side, up, and forward) from that transform.
Sounds good. I'll update the forward direction vector (go forward using keypress) to be the vector the POV is facing after a rotation translation by taking onfu's advice.
Almost there. Trying to update the translate vectors to be the components of the rotated angle. My trig, albeit rusty, is pretty good. I'm not afraid of the math and all. But, can some kind soul point me in the direction of a good 3D tutorial in OpenGL, or Game programming in general? Would much appreciate. Thanks!
rough pseudo code should be something like:

camRadians = gameCamera.yRotate*(Math.PI/180);
moveVectorX = moveSpeed*Math.cos(camRadians);
moveVectorZ = moveSpeed*Math.sin(camRadians);

//(move forwards)
glTranslatef(moveVectorX,0,moveVectorZ);

//(move backwards)
glTranslatef(-moveVectorX,0,-moveVectorZ);

-------------

probably some proper tweaking needed since I'm going off memory more to do with how I move game objects around in my 2D engine.
Quote:Original post by onfu
moveVectorX = moveSpeed*Math.cos(camRadians);
moveVectorZ = moveSpeed*Math.sin(camRadians);

//(move forwards)
glTranslatef(moveVectorX,0,moveVectorZ);

//(move backwards)
glTranslatef(-moveVectorX,0,-moveVectorZ);
This is unlikely to work the way you expect it to. What you would typically do here would be to store the position of the camera, update that position using the 'moveVector' variables calculated above, and then submit the position as the argument to glTranslate*().

This topic is closed to new replies.

Advertisement