简体   繁体   English

如何在Open Gl,C ++中使多维数据集平滑地沿Y轴下降

[英]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 )". 本质上,您是以“每帧米( m/f )”为单位,而不是“米每秒( 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 . 因此,一些基本数学告诉我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. 速度问题编写代码的方式, velo变量实际上表示位置,并在每个帧中用数字0.005更新它,我认为这意味着要加速。 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. 请注意,当我用加速度更新速度时,如何通过deltaTime缩放该比例,以及当我用速度更新位置时,我也执行相同的操作。 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". 同样,以前的单位分析是记住这一点的简便方法: deltaTime告诉您自上一帧以来经过的毫秒数,因此其单位为“ s / f”。 velo should have units "m/s" to make the motion smooth over time. velo应该具有“ m / s”单位,以使运动随时间平滑。 The amount to update the position this frame is m/s * s/f = m/f. 更新此帧位置的数量为m / s * s / f = m / f。 Those units make sense, they measure a distance per frame. 这些单位很有意义,它们测量每帧的距离。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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