I am trying to create a very simple physics simulator for a school project, all i want it to do is have a cube that falls dew to gravity and when it hits a floor it will bounce and so on until the cube has no energy and it will just stop moving e.g. rest on the floor. I haven't added the collision detection in yet but most other things work fine the only problem i have is that the cube doesn't fall smoothly its very jumpy e.g. it falls and speed up then slows down and then speeds up again and i have no idea why.
I have incluided the code below:
timestep++;
velo += 0.005;
cout << velo << "\n";
glTranslatef(0.0, -velo, 0.0);//timestep * gravity, 0.0);
I have also included the entire program code just incase it is a probem somewhere else the extract above is just at the top of the display function
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLFrame.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#include <stdio.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#include <iostream>;
using namespace std;
void display();
void specialKeys(int, int, int);
void animate();
double rotate_y = 0;
double rotate_x = 0;
// Gravity Varibles
int timestep = 0;
float gravity = 0.0098;
float velo = 0.0f;
int main( int argc, char* argv[] )
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL );
glutCreateWindow("DANIELS CUBE");
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glutDisplayFunc(display);
glutSpecialFunc(specialKeys);
glutIdleFunc(animate);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutMainLoop();
return 0;
}
void animate()
{
glutPostRedisplay();
}
void display()
{
//Clears the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Changes the way the polygons are drawn so it looks like a wire frame
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
///////////
// CUBE ///
///////////
// Resets the transformation matrix
glLoadIdentity();
glScalef(0.2, 0.2, 0.2);
// Rotates the cuube around the x by 'rotate_x'
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
// Rotates the cuube around the y by 'rotate_y'
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
// move dew to gravity
timestep++;
velo += 0.005;
cout << velo << "\n";
glTranslatef(0.0, -velo, 0.0);//timestep * gravity, 0.0);
// Defines the folowing verticys as this polygon
glBegin(GL_POLYGON);
//Changes color
glColor3f( 1.0, 0.0, 0.5 );
// Adds verted to polygon
glVertex3f( -0.5, -0.5, -0.5 ); // F1
glColor3f( 0.0, 1.0, 0.0 );
glVertex3f( -0.5, 0.5, -0.5 ); // F2
glColor3f( 0.0, 0.0, 1.0 );
glVertex3f( 0.5, 0.5, -0.5 ); // F3
glColor3f( 1.0, 0.0, 1.0 );
glVertex3f( 0.5, -0.5, -0.5 ); // F4
// Closes the polygon
glEnd();
glBegin(GL_POLYGON);
glColor3f( 1.0, 1.0, 1.0 );
glVertex3f( 0.5, -0.5, -0.5 ); // Back1
glVertex3f( 0.5, 0.5, -0.5 ); // Back2
glVertex3f( 0.5, 0.5, 0.5 ); // Back3
glVertex3f( 0.5, -0.5, 0.5 ); // Back4
glEnd();
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.0, 1.0 );
glVertex3f( 0.5, -0.5, -0.5 ); // F1
glVertex3f( 0.5, 0.5, -0.5 ); // F2
glVertex3f( 0.5, 0.5, 0.5 ); // F3
glVertex3f( 0.5, -0.5, 0.5 ); // F4
glEnd();
glBegin(GL_POLYGON);
glColor3f( 0.0, 1.0, 0.0 );
glVertex3f( -0.5, -0.5, 0.5 ); // F1
glVertex3f( -0.5, 0.5, 0.5 ); // F2
glVertex3f( -0.5, 0.5, -0.5 ); // F3
glVertex3f( -0.5, -0.5, -0.5 ); // F4
glEnd();
glBegin(GL_POLYGON);
glColor3f( 0.0, 0.0, 1.0 );
glVertex3f( 0.5, 0.5, 0.5 ); // F1
glVertex3f( 0.5, 0.5, -0.5 ); // F2
glVertex3f( -0.5, 0.5, -0.5 ); // F3
glVertex3f( -0.5, 0.5, 0.5 ); // F4
glEnd();
glBegin(GL_POLYGON);
glColor3f( 1.0, 0.0, 0.0 );
glVertex3f( 0.5, -0.5, -0.5 ); // F1
glVertex3f( 0.5, -0.5, 0.5 ); // F2
glVertex3f( -0.5, -0.5, 0.5 ); // F3
glVertex3f( -0.5, 0.5, -0.5 ); // F4
glEnd();
////////////
// Floor //
//////////
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glLoadIdentity();
// Rotates the cuube around the x by 'rotate_x'
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
// Rotates the cuube around the y by 'rotate_y'
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
for( GLfloat i = -2.5; i < 2.5; i += 0.25 )
{
glVertex3f(i, -1.0, 2.5);
glVertex3f(i, -1.0, -2.5);
glVertex3f(2.5, -1.0, i);
glVertex3f(-2.5, -1.0, i);
}
glEnd();
// Flushes the buffers
glFlush();
// Draws what has just been done on the screen
glutSwapBuffers();
}
void specialKeys( int key, int x, int y )
{
if( key == GLUT_KEY_RIGHT )
{
rotate_y += 5;
}
else if( key == GLUT_KEY_LEFT )
{
rotate_y -= 5;
}
else if( key == GLUT_KEY_UP )
{
rotate_x += 5;
}
else if( key == GLUT_KEY_DOWN )
{
rotate_x -= 5;
}
glutPostRedisplay();
}
There are a couple problems I see with your code:
Assuming fixed timestep
Your display function isn't guaranteed to be called at evenly spaced intervals. Essentially you're giving your cube's velocity in "meters per frame (m/f
)" instead of "meters per second (m/s
)". (I'm using meters here as a general distance unit)
So, some basic math tells me that m/f = m/s * s/f
. In other words, you want to scale the amount you move the cube per frame by the actual timestep since the last frame.
Velocity problem
The way your code is written, your velo
variable actually represents the position, and you update it each frame with the number 0.005 which I think is what you mean to be your acceleration. If you want to have something accelerating due to gravity, you need to store two values, its position and its velocity. Then each frame, you need to update the velocity by adding the acceleration, and the position by adding the velocity.
Here's some code that does both of these things
int lastTime=0;
void display() {
int time = glutGet(GLUT_ELAPSED_TIME); // Time since the start of the program
if (lastTime>0) { // Don't move anything the first frame
int deltaTime = time-lastTime; // millis elapsed since the last frame
velo += -0.005*deltaTime; // Gravity accelerates downwards
pos += velo*deltaTime; // Position updated by velocity
glTranslateF(0.0, pos, 0.0); // Actually position the square in the correct location
}
lastTime = deltaTime;
}
Notice how when I update my velocity with the acceleration I scale that by deltaTime, and when I update my position with the velocity I do the same. Again, the unit analysis from before is an easy way to remember this: deltaTime
tells you the number of milliseconds elapsed since the last frame, so its units are "s/f". velo
should have units "m/s" to make the motion smooth over time. The amount to update the position this frame is m/s * s/f = m/f. Those units make sense, they measure a distance per frame.