简体   繁体   中英

How to make a cube fall smoothly down the Y-Axis in Open Gl, C++

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 eg 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 eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM