Click to See Complete Forum and Search --> : OpenGL Camera Movement problem


tlsn2
November 26th, 2006, 08:10 AM
Hey all,

I am trying to do a very simple task in openGL and glut.
I've built a viewer that allows me to control the camera movement in my 3D generated world. I want to add this simple feature, I want to be able to press the 's' key and let my camera to get back to its origin point. I want to actually see the movement and not just to "jump" to the origin point.
For some reason I cant make this happen, no matter what I do I cant make the screen render after every iteration. Can someone please take a short look and tell me what am I doing wrong:

//in main
glutKeyboardFunc ( myKeysFunc );

//Keys events func
void myKeysFunc( unsigned char key, int x, int y )
{
if (key=='q')
{
cout << endl << "GoodBye..." << endl;
exit(0);
}

....

if(key == 's')
{
goToPosition(2.3, 5, 3, 0, -1, 0);
}

glutPostRedisplay();
printf("Xcoor = %f, Ycoor = %f, Zcoor = %f, lookX = %f, lookY = %f, lookZ = %f, upX = %f, upY = %f, upZ = %f\n", Xcoor,Ycoor,Zcoor,lookX,lookY,lookZ, Xup, Yup, Zup);
}


//Camera movement func
void goToPosition(float newX, float newY, float newZ,
float newLookX, float newLookY, float newLookZ)
{
int xDistance1 = newX - Xcoor;
int yDistance1 = newY - Ycoor;
int zDistance1 = newZ - Zcoor;

int xDistance2 = newLookX - lookX;
int yDistance2 = newLookY - lookY;
int zDistance2 = newLookZ - lookZ;

cout << endl << endl;
for (int i = 0; i < FRAMES; ++i)
{
Xcoor += (float)xDistance1/FRAMES;
Ycoor += (float)yDistance1/FRAMES;
Zcoor += (float)zDistance1/FRAMES;
lookX += (float)xDistance2/FRAMES;
lookY += (float)yDistance2/FRAMES;
lookZ += (float)zDistance2/FRAMES;

cout << "Xcoor: " << Xcoor << " ";
glutSwapBuffers();
glutPostRedisplay();
sleep(100);
}
cout << endl << endl;
}

Zachm
November 26th, 2006, 11:57 AM
I think you are assuming that for each iteration of the following code

for (int i = 0; i < FRAMES; ++i)
{
Xcoor += (float)xDistance1/FRAMES;
Ycoor += (float)yDistance1/FRAMES;
Zcoor += (float)zDistance1/FRAMES;
lookX += (float)xDistance2/FRAMES;
lookY += (float)yDistance2/FRAMES;
lookZ += (float)zDistance2/FRAMES;

cout << "Xcoor: " << Xcoor << " ";
glutSwapBuffers();
glutPostRedisplay();
sleep(100);
}


The scene is redrawn, but no function you called inside the loop actually does that !

glutSwapBuffers() just swaps the buffers without drawing anything.
glutPostRedisplay() just lets the glut event handling system know that the current window needs to be redrawn.

But it won't be drawn right now, not until the next run through the main loop, after the quoted above loop will finish running.

You are trying to create an animation and it doesn't happen in zero time - your idea of how to do it is not bad but try to think in a "state machine" sort of way - like glut :). Define a boolean flag that determines if camera is moving to it's home position, set it to TRUE when 's' is pressed and on each run through the main loop, check if the flag is true, and if so, advance the camera a little bit towards the home position and check if there yet - and if so - set the flag back to FALSE. It would also be wise to block manual movement while auto-movement to home position is in progress.

Good luck :)

tlsn2
November 27th, 2006, 09:54 AM
Hey Zachim and friends,

First of all let me thank you for your quick and bright reply, It sure starighten this all "state machine" issue for me.

But, I still have this little problem, I don't know where to put that if condition you were talking about. Meaning, I followed your instructions and created that boolean flag, but where should I put the condition to see if the flag is up? Currently, I put it inside the renderFunction of the window, but for some reason the render function is being called only upon a input event (mouse or keyboard). How can I make this one trully animation that I can stand still while the screen renders itself automatically until the camera is went back to its origin point? How can I manually call the render func or schedule an automatic call every several milliseconds?

Please help me on that silly matter,

Thanks a lot !!!
Tal.

Zachm
November 27th, 2006, 06:19 PM
Did you register the display callback function glutDisplayFunc() ?

The function you register here is called every frame, so if there's a condition that needs checking on each frame, put the check inside this registered function (or call from this function to the object / function checking it).

You can also register a timer function to limit max frames per second by using glutTimerFunc() - try googling - there's plenty of usage examples & tutorials on the web.

For instance, you can define a global variable

bool bMovingToHomePos = false;


In your keyboard callback function update it when necessary:


void myKeysFunc( unsigned char key, int x, int y )
{
.
.
.
if (key=='s')
{
bMovingToHomePos = true;
}
.
.
.


And on the display callback function check for it's state and update scene as necessary:


void DisplayFunc()
{
CheckStateAndUpdateCamera();

DrawScene(); //...
}



I've added some code - didn't check if it works - it's surely NOT the best implementation but it's just for clarifying the idea:



void CheckStateAndUpdateCamera()
{
if (bMovingToHomePos )
{
if (distance(homeX, homeY, homeZ, Xcoor, Ycoor, Zcoor) <= 1.0)
{
Xcoor = homeX;
Ycoor = homeY;
Zcoor = homeZ;
bMovingToHomePos = false;
}
else
{
AdvanceTowardsHome(homeX, homeY, homeZ, ;hLookX, hLookY, hLookZ);
}
}
}

void AdvanceTowardsPosition(float newX, float newY, float newZ,
float newLookX, float newLookY, float newLookZ)
{
float xDistance1 = newX - Xcoor;
float yDistance1 = newY - Ycoor;
float zDistance1 = newZ - Zcoor;

float xDistance2 = newLookX - lookX;
float yDistance2 = newLookY - lookY;
float zDistance2 = newLookZ - lookZ;

normalizeVector(xDistance1, yDistance1, zDistance1);
normalizeVector(xDistance2, yDistance2, zDistance2);

Xcoor += xDistance1
Ycoor += yDistance1;
Zcoor += zDistance1;
lookX += xDistance2;
lookY += xDistance2;
lookZ += zDistance2;
}

void normalizeVector(float &x, float &y, float &z)
{
float length = sqrt(x*x+y*y+z*z);
if (fabs(length) > 0)
{
x /= length;
y /= length;
z /= length;
}
}

float distance(float x1, y1, z1, x2, y2, z2)
{
return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1) );
}


Please note:
1. Using distance function to check the distance between 2 points
2. Normalizing vectors to unit (1.0) length.
3. The function AdvanceTowardsPosition() advances the camera towards a position - 1.0 units in world scale.
4. Don't forget to update your camera location with gluLookAt().
5. This code is VERY not efficient - some calculations can be done only once but are done here for each frame of the animation - think how they can be reduced.

Good luck :)