Problems with camera movement

I am attempting to create a simple 3D world and then move around in it in only the x-y direction, no rotation. It should appear as if the world stays still while the viewpoint moves around.

World = Six sided rectanglular grid which encloses the viewpoint. (works) Also draw a
small flat rectangular quad around a specific center coordnate set back and to the left of the viewpoint. (works)

I am running through the following process everytime I detect mouse movement or arrow-key presses.

//PseudoCode

redraw(float x, float y, float z)
{
xTrans += x;
yTrans += y;
zTrans += z;

glClear();
glMatrixMode(GL_MODELVIEW);

/* This should draw the background   
   centered around origin, right? */

/#/ glLoadIdentity()
draw_the_background();

/* This should shift the origin to
   the center of the quad and then draw 
   it there, right?

/#/ glLoadIdentity()
/#/ glTranslatef_to_squares_center_coord();
draw_the_rectangular_quad();

/* This should set the viewpoint at the
current x, y, z position right? /
glLoadIdentity();
glTranslatef(xTrans, yTrans, zTrans);

glxSwapBuffers();
}

When I run this code and attempt to move around, nothing happens. The scene remains motionless. However if I take out the
the lines marked by a ‘/#/’ it works. I don’t understand this. This is no good if I want to draw more than one object in my world.

I have been through the redbook and online tutorials. There must be something simple I am not seeing.

All help is greatly appreciated.

I will be checking back frequently so please post a question if something is unclear.

-J0ey4

Originally posted by J0ey4:
//PseudoCode

redraw(float x, float y, float z)
{
xTrans += x;
yTrans += y;
zTrans += z;

If you translate every redraw of a frame, the coordinates could become huge.

glClear();
glMatrixMode(GL_MODELVIEW);

If you don’t change from MATRIX you don’t have to recall it every frame.

/* This should draw the background   
   centered around origin, right? */

/#/ glLoadIdentity()

This one is needed to reset all previous MODEL_MATRIX transformations(i.e. glTranslate()/glRotate()).

  draw_the_background();
/* This should shift the origin to
   the center of the quad and then draw 
   it there, right?

yes

/#/ glLoadIdentity()
/#/ glTranslatef_to_squares_center_coord();
draw_the_rectangular_quad();

/* This should set the viewpoint at the
current x, y, z position right? /
glLoadIdentity();
glTranslatef(xTrans, yTrans, zTrans);

glxSwapBuffers();
}

If you want to draw more than one object you can repeat the same action:

glLoadIdentity ();// Draw first
glTranslatef(obj_x, obj_y, obj_z);
draw(obj);
glLoadidentity();// Draw next object

or if you want to draw more objects with a base translation (all objects are translated the same, i.e. then you translate individualy.)
See the code:

glLoadIdentity();
glPushMatrix();// push the current matrix
glTanslate(somex, somey, somez);
glPushMatrix();// push the translated matrix
glRotate(some_angle,some_axis);
draw(obj1);
glPopMatrix();//pop the previously
//translated matrix
draw(obj2);
glPopMatrix();// pop the first matrix. This
// one would equal to glLoadIdentity

Hope this helps a bit,

Daniel Palomo van Es.

[This message has been edited by DPalomo (edited 10-30-2000).]

Thanks for the post DPalomo, you raised some good points. But I think I messed up posting the psedocode. The code I am attempting to run and which will not move is the following:

redraw(float x, float y, float z)
{
xTrans += x;
yTrans += y;
zTrans += z;

glClear();
glMatrixMode(GL_MODELVIEW);

glLoadIdentity()
draw_the_background();

glLoadIdentity()
glTranslatef_to_squares_center_coord();
draw_the_rectangular_quad();

glLoadIdentity();
glTranslatef(xTrans, yTrans, zTrans);

glxSwapBuffers();
}

When I run this the scene is drawn the first time and then never moves. If I remove the first two “glLoadIdentity()” and the first “glTranslate()”. Then the translation appears to work. But in reality I am just drawing both objects around the origin and then moving to a point.

What I want to be able to do is draw the background around the origin. (So I load the Identity matrix and draw it)

Then I want to loop through a list of objects and draw each one relative to their center coordinates. (So I load the identity matrix for each one and then translate to the center coordinate, the above example only has one object for simplicity)

Then I want to move the camera to the viewpoint specified by xTrans, yTrans, and zTrans. (So I load the identity matrix and translate there.)

When I use the actual implementation of the pseudocode above, the scene is drawn correctly upon startup but no motion occurs?

Why?

All help is greatly appreciated.

I will be checking back frequently so please post a question if something is unclear.

-J0ey4

Try this…

It’s Borland…
Press + once or twice to move in Z and play with arrow…you can rotate and move back and forth

…/*


OpenGL by Marc-Antoine Lemay
1- Learning Process


*/

#include <windows.h>
#include <GL/Gl.h>
#include <GL/GLUT.h>
#include <math.h>
#include <iostream.h>
#include <conio.h>

float EFax=1;
float fCam=10;
float fHeading=0;
float fMHead;
float xpos=0;
float ypos=0;
float zpos=2;
float xmpos=0;
float ympos=0;
double PI=3.1415;
int Mis=0;
float dist=1;

void init ( void )
{

glEnable ( GL_DEPTH_TEST );
glShadeModel ( GL_SMOOTH );

glClearColor ( 0.20, 0.20, 0.20,1.0 );

}

/* Main display function called by GLUT main loop */
void display( void )
{
// Clear previous screen and depth buffer
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

/* Add Everything to display*/

glMatrixMode ( GL_MODELVIEW );
glLoadIdentity();

glRotatef(-90,1,0,0); /* Rotation Around X to have Z as real world /
glRotatef(fHeading,0,0,1); /
Heading of you */
glTranslatef(-xpos,-ypos,-zpos); /POsition de toi/

glPushMatrix();
glColor4f(1,0,0,1); // X axis is RED
glBegin(GL_LINES);
glVertex3f(-10,0,0);
glVertex3f(10,0,0);
glEnd();
glColor4f(0,1,0,1); // Y axis is GREEN
glBegin(GL_LINES);
glVertex3f(0,10,0);
glVertex3f(0,-10,0);
glEnd();
glColor4f(0,0,1,1); // Z axis is BLUE
glBegin(GL_LINES);
glVertex3f(0,0,10);
glVertex3f(0,0,-10);
glEnd();
glPopMatrix();

glColor4f(1.0,1.0,1.0,1.0);
glPushMatrix();
glutWireSphere(2,16,16);
glPopMatrix();

glColor4f(1.0,0.0,1.0,1.0);
glPushMatrix();
glTranslatef(0,8,1);
glutWireSphere(2,16,16);
glPopMatrix();

glColor4f(0.0,1.0,1.0,1.0);

glPushMatrix();
glTranslatef(8,8,1);
glutWireSphere(2,10,10);
glPopMatrix();

glColor4f(0.0,0.0,1.0,1.0);
glPushMatrix();
glTranslatef(12,20,1);
glutSolidSphere(2,10,10);
glPopMatrix();

glColor4f(0.7,1.0,1.0,1.0);
glPushMatrix();
glBegin(GL_POLYGON);
glNormal3f(0,0,1.0);

   	glVertex3f(0,100,0);
	glVertex3f(50,100,0);
   	glVertex3f(50,0,0);
   	glVertex3f(0,0,0);
glEnd();
glPopMatrix();

if (Mis==1)
 {

ympos+=cos(2PIfMHead/360)(dist/4);
xmpos+=sin(2
PIfMHead/360)(dist/4);

glColor4f(1.0,0.0,0.0,1.0);
glPushMatrix();
	glTranslatef(xmpos,ympos,zpos);
	//glRotatef(fMHead,0,0,1);

	glutWireSphere(1,16,16);

// Sleep(250);

clrscr();
cout << xmpos << " " << ympos << "
";
cout << xpos << " " << ypos << "
";
cout << fHeading << " " << fMHead << "
";
cout << dist << " " << Mis;
glPopMatrix();
}

glutSwapBuffers ();

if (dist>=2.5)
Mis=0;

}

void explosion (void)
{
for (EFax=1;EFax<500;EFax+=1.5)
{
display ( );
}
EFax=.1;
}

/* Idle callback from GLUT main loop.
/
void idling ( void )
{
/
Variable to Increment */
if (Mis==1)
dist+=.000001;

if (dist>=100)
{dist=1;
Mis=0;
xmpos=xpos;
ympos=ypos;
}
glutPostRedisplay ( );
}

/*
Standard reshape function, also sets the viewing volume the first time
its called
*/
void reshape ( int w, int h )
{
glViewport ( 0, 0, w, h );
glMatrixMode ( GL_PROJECTION );
glLoadIdentity ( );
if ( h==0 )
gluPerspective ( 100, ( float ) w, 1.0, 5000.0 );
else
gluPerspective ( 100, ( float ) w / ( float ) h, 1.0, 5000.0 );

glMatrixMode ( GL_MODELVIEW );
glLoadIdentity ( );

}

#pragma argsused
void mouse ( int button, int state, int x, int y )
{

}

#pragma argsused
void motion ( int x, int y )
{

display ( );
idling ( );
}

#pragma argsused
/* Standard GLUT keyboard call back function. */
void keyboard ( unsigned char key, int x, int y )
{
clrscr();
cout << xmpos << " " << ympos << "
";
cout << xpos << " " << ypos << "
";
cout << fHeading << " " << fMHead << "
";

switch ( key ) {
case 27: // Escape key
exit ( 0 );
break;
case ‘+’:
zpos+=.25;
glutPostRedisplay ( );
break;
case ‘-’:
zpos-=.25;
glutPostRedisplay ( );
break;
case ‘f’:
Mis=1;
xmpos=xpos;
ympos=ypos;
fMHead=fHeading;
dist=1;
glutPostRedisplay ( );
break;

  case 'r':

     glutPostRedisplay ( );
     break;
  default:
     break;

}
}

#pragma argsused
/* Standard GLUT keyboard call back function. */
void Skeyboard ( int key, int x, int y )
{
clrscr();
cout << xmpos << " " << ympos << "
";
cout << xpos << " " << ypos << "
";
cout << fHeading << " " << fMHead << "
";

switch ( key ) {
case GLUT_KEY_UP:
ypos+=cos(2PIfHeading/360);
xpos+=sin(2PIfHeading/360);
glutPostRedisplay ( );
break;

  case GLUT_KEY_DOWN:
		ypos-=cos(2*PI*fHeading/360);
     xpos-=sin(2*PI*fHeading/360);
     glutPostRedisplay ( );
    break;
  case GLUT_KEY_RIGHT:
  	fHeading+=5;
     glutPostRedisplay ( );
    break;
  case GLUT_KEY_LEFT:
     fHeading-=5;
     glutPostRedisplay ( );
    break;

  default:
     break;

}
}

/* Main Loop

  • Open window with initial window size, title bar,
  • RGB display mode, and handle input events.
    /
    int main ( int argc, char
    * argv )
    {
    glutInit ( &argc, argv );
    glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE );
    glutInitWindowSize ( 300, 300 );
    glutCreateWindow ( “OpenGL Learning Process For Stupid Bored Students” );

init ( );

glutReshapeFunc ( reshape );
glutMouseFunc ( mouse );
glutMotionFunc ( motion );
glutKeyboardFunc ( keyboard );
glutSpecialFunc ( Skeyboard );
glutDisplayFunc ( display );
glutIdleFunc ( idling );
glutMainLoop ( );
return 0;
}

Thanks a lot for the code Marc-Antoine.

I loaded it up in VC++ 6.0 and started playing with it. One thing I noticed that seems strange to me. In the display() method the first thing you do after changing the orientation of the axises is translate to the new position (-xpos, -ypos, -zpos). Then you use calls to glVertex() with absolute coordinates such as (0.0, -10.0, 0.0) to draw the axises.

Does this mean that vertexes specified with glVertex3f() are always relative to the origin(identity matrix) regardless of the current modelview matrix?

I will be checking back frequently so if anything is unclear just post a question.

Any and all help is greatly appreciated.

-J0ey4

Correct, the coordinates of the object’s vertices are in object space. The translation is what converts the object space to world space.

Now I’m very confused, if that’s the case then why does the code for NeHe’s first tutorial work:

int DrawGLScene(GLvoid)
{
glClear();
glLoadIdentity();

/* Draw a triangle to the left of the 
   origin */			
glTranslatef(-1.5f,0.0f,-6.0f);

glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f, 1.0f, 0.0f);	
    glVertex3f(-1.0f,-1.0f, 0.0f);
    glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();


/* Draw a Square to the right of the
   origin */
glTranslatef(3.0f,0.0f,0.0f);

glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glEnd();

return TRUE;

}

If glVertex3f() always specify with respect to the origin and not the current position (matrix) then why does Nehe’s code work?

If it does specify to the current position
(matrix) then why does Marc-Antoinette’s code(above) work? They seem to be contradicting examples.

I’ll be checking back frequently, so if something is unclear post a question.

All help is appreciated, I think there is some central concept I’m, not getting.

-J0ey4

Ok, this NeHe code is a little confusing since it accumulates the object origin offsets of the two objects. I’ll rewrite that code with better comments.

int DrawGLScene(GLvoid)
{
glClear();
glLoadIdentity();

/* Draw a triangle to the left of the
world origin by moving the object origin*/

glTranslatef(-1.5f,0.0f,-6.0f);

glBegin(GL_TRIANGLES);
/* these coordinates are all in object space, not world space */
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();

/* Draw a Square to the right of the world origin by moving the object origin from where it was before (this produces an accumulated offset of (1.5,0,-6.0) */
glTranslatef(3.0f,0.0f,0.0f);

/* again these coordinates are again all with respect to the object origin */
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glEnd();

return TRUE;
}

Marc-Antoine’s code is obeying the same rules, it is just that code is not accumulating the object origin offsets. Instead it continually saves the origin (glPushMatrix) before moving it and resets the origin (glPopMatrix) after drawing the object.

[This message has been edited by DFrey (edited 11-01-2000).]

How my name passed from Marc-Antoine to Marc-Antoinette…???

Hehe, I just copied and pasted it from a previous post, sorry. I’ve corrected it.

Guys,

First of all I want to say thanks for all your help. I think I’m getting a better understanding here, but I have one more question. Before I list that let me write what I think happens.

Summary:

glLoadIdentity() synchronizes the object origin with the world origin. Any subsequent calls to glTransatef() are cumulative and move the world origin by the specified amounts. The object origin never moves but since we are moving the world around it appears as if it is. All glVertex()'s are relative to the object origin.

This being said we can load the identity matrix, push it, and then translate to different coordinates to draw. Popping the matrix brings the object origin back to the world origin.

Please make any nesscessary corrections to the above statements.

If all this is true then how does the very first part of Marc-Antoine’s display routine work? I’ll present it here and put questions in comments. Forget all the glut calls, all I’m concerned about is when the lines are drawn to represent the world origin.

void display( void )
{

glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

/*These synch up the world and object origins, correct? */
glMatrixMode ( GL_MODELVIEW );
glLoadIdentity();

/* These three calls in succession will cumulatively move the world origin away from the object origin, correct? */
glRotatef(-90,1,0,0);
glRotatef(fHeading,0,0,1);
glTranslatef(-xpos,-ypos,-zpos);

/*See the values */
cout<<xpos<<" “<<ypos<<” "<<zpos<<endl;

/* Push a copy of the current matrix to the stack? We don’t trnasform in this call, just save a copy of where we are, right? */
glPushMatrix();

/* Draw these lines relative to the object origin. But this is what confuses me. These lines always appear at the world origin regardless of what the values used in the previous transformation calls were. */
glColor4f(1,0,0,1); //X Axis is RED
glBegin(GL_LINES);
glVertex3f(-10,0,0);
glVertex3f(10,0,0);
glEnd();
glColor4f(0,1,0,1); // Y axis is GREEN
glBegin(GL_LINES);
glVertex3f(0,10,0);
glVertex3f(0,-10,0);
glEnd();
glColor4f(0,0,1,1); // Z axis is BLUE
glBegin(GL_LINES);
glVertex3f(0,0,10);
glVertex3f(0,0,-10);
glEnd();

/* Destroy the current matrix and replace it with the top matrix in the stack, right? But the current matrix and the top matrix in the stack should be identical, since we haven’t done any transformations since we pushed it. Why push it in the first place? */
glPopMatrix();

If the mistake can be found in my assumptions or my questions answered differently then I am answering them now I think my problem will be solved.

thanks so much for the help so far guys, I really appreciate it. Sorry about the mispelling Marc-Antoine.

-J0ey4