Sign in to follow this  
eggmatters

OpenGL glRotatef() Transformation doesn't "stick"

Recommended Posts

eggmatters    110
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 keystroke
float 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 terrain
void 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 keypresses
void 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 events
void 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!

Share this post


Link to post
Share on other sites
jpetrie    13159
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.

Share this post


Link to post
Share on other sites
eggmatters    110
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!

Share this post


Link to post
Share on other sites
onfu    311
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"?

Share this post


Link to post
Share on other sites
eggmatters    110
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.

Share this post


Link to post
Share on other sites
jyk    2094
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.

Share this post


Link to post
Share on other sites
eggmatters    110
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.

Share this post


Link to post
Share on other sites
eggmatters    110
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!

Share this post


Link to post
Share on other sites
onfu    311
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.

Share this post


Link to post
Share on other sites
jyk    2094
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*().

Share this post


Link to post
Share on other sites
onfu    311
the X and Z might not be correctly laid out either in what I wrote...I just figured it'd be enough to get it on the right track.

Of course since its returning to identity each frame you need to do a lot more than I posted there.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By pseudomarvin
      I assumed that if a shader is computationally expensive then the execution is just slower. But running the following GLSL FS instead just crashes
      void main() { float x = 0; float y = 0; int sum = 0; for (float x = 0; x < 10; x += 0.00005) { for (float y = 0; y < 10; y += 0.00005) { sum++; } } fragColor = vec4(1, 1, 1 , 1.0); } with unhandled exception in nvoglv32.dll. Are there any hard limits on the number of steps/time that a shader can take before it is shut down? I was thinking about implementing some time intensive computation in shaders where it would take on the order of seconds to compute a frame, is that possible? Thanks.
    • By Arulbabu Donbosco
      There are studios selling applications which is just copying any 3Dgraphic content and regenerating into another new window. especially for CAVE Virtual reality experience. so that the user opens REvite or CAD or any other 3D applications and opens a model. then when the user selects the rendered window the VR application copies the 3D model information from the OpenGL window. 
      I got the clue that the VR application replaces the windows opengl32.dll file. how this is possible ... how can we copy the 3d content from the current OpenGL window.
      anyone, please help me .. how to go further... to create an application like VR CAVE. 
       
      Thanks
    • By cebugdev
      hi all,

      i am trying to build an OpenGL 2D GUI system, (yeah yeah, i know i should not be re inventing the wheel, but this is for educational and some other purpose only),
      i have built GUI system before using 2D systems such as that of HTML/JS canvas, but in 2D system, i can directly match a mouse coordinates to the actual graphic coordinates with additional computation for screen size/ratio/scale ofcourse.
      now i want to port it to OpenGL, i know that to render a 2D object in OpenGL we specify coordiantes in Clip space or use the orthographic projection, now heres what i need help about.
      1. what is the right way of rendering the GUI? is it thru drawing in clip space or switching to ortho projection?
      2. from screen coordinates (top left is 0,0 nd bottom right is width height), how can i map the mouse coordinates to OpenGL 2D so that mouse events such as button click works? In consideration ofcourse to the current screen/size dimension.
      3. when let say if the screen size/dimension is different, how to handle this? in my previous javascript 2D engine using canvas, i just have my working coordinates and then just perform the bitblk or copying my working canvas to screen canvas and scale the mouse coordinates from there, in OpenGL how to work on a multiple screen sizes (more like an OpenGL ES question).
      lastly, if you guys know any books, resources, links or tutorials that handle or discuss this, i found one with marekknows opengl game engine website but its not free,
      Just let me know. Did not have any luck finding resource in google for writing our own OpenGL GUI framework.
      IF there are no any available online, just let me know, what things do i need to look into for OpenGL and i will study them one by one to make it work.
      thank you, and looking forward to positive replies.
    • By fllwr0491
      I have a few beginner questions about tesselation that I really have no clue.
      The opengl wiki doesn't seem to talk anything about the details.
       
      What is the relationship between TCS layout out and TES layout in?
      How does the tesselator know how control points are organized?
          e.g. If TES input requests triangles, but TCS can output N vertices.
             What happens in this case?
      In this article,
      http://www.informit.com/articles/article.aspx?p=2120983
      the isoline example TCS out=4, but TES in=isoline.
      And gl_TessCoord is only a single one.
      So which ones are the control points?
      How are tesselator building primitives?
    • By Orella
      I've been developing a 2D Engine using SFML + ImGui.
      Here you can see an image
      The editor is rendered using ImGui and the scene window is a sf::RenderTexture where I draw the GameObjects and then is converted to ImGui::Image to render it in the editor.
      Now I need to create a 3D Engine during this year in my Bachelor Degree but using SDL2 + ImGui and I want to recreate what I did with the 2D Engine. 
      I've managed to render the editor like I did in the 2D Engine using this example that comes with ImGui. 
      3D Editor preview
      But I don't know how to create an equivalent of sf::RenderTexture in SDL2, so I can draw the 3D scene there and convert it to ImGui::Image to show it in the editor.
      If you can provide code will be better. And if you want me to provide any specific code tell me.
      Thanks!
  • Popular Now