opengl — Как заставить куб плавно падать по оси Y в Open Gl, переполнение стека

Я пытаюсь создать очень простой физический симулятор для школьного проекта, все, чего я хочу, это иметь куб, который падает росой под действием силы тяжести, и когда он падает на пол, он будет подпрыгивать и так далее, пока у куба не будет энергии и он просто перестанет двигаться, например отдых на полу. Я еще не добавил обнаружение столкновений, но большинство других вещей работают нормально, единственная проблема, с которой я столкнулся, это то, что куб не падает плавно, он очень нервный, например. он падает и ускоряется, затем замедляется, а затем снова ускоряется, и я понятия не имею, почему.

Я включил код ниже:

timestep++;
velo += 0.005;
cout << velo << "\n";
glTranslatef(0.0, -velo, 0.0);//timestep * gravity, 0.0);

Я также включил весь программный код только в том случае, если это где-то еще пробмем, приведенный выше фрагмент находится в верхней части функции отображения.

#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();
}

0

Решение

Есть пара проблем, которые я вижу с вашим кодом:

Предполагая фиксированный временной шаг
Ваша функция отображения не гарантированно будет вызываться через равные промежутки времени. По сути вы даете скорость вашего куба в «метрах на кадр (m/f) «вместо» метров в секунду (m/s) «. (Я использую метры здесь как общую единицу расстояния)

Итак, некоторая базовая математика говорит мне, что m/f = m/s * s/f, Другими словами, вы хотите масштабировать величину перемещения куба за кадр по фактическому временному шагу с момента последнего кадра.

Проблема скорости
То, как ваш код написан, ваш velo переменная на самом деле представляет позицию, и вы обновляете ее каждый кадр с числом 0,005, которое, я думаю, является вашим ускорением. Если вы хотите, чтобы что-то ускорялось под действием силы тяжести, вам нужно сохранить два значения: его положение и его скорость. Затем в каждом кадре вам нужно обновить скорость, добавив ускорение, и позицию, добавив скорость.

Вот код, который делает обе эти вещи

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;
}

Обратите внимание, что когда я обновляю свою скорость с ускорением, я масштабирую ее с помощью deltaTime, а когда я обновляю свою позицию со скоростью, я делаю то же самое. Опять же, предыдущий анализ модулей — это простой способ запомнить это: deltaTime сообщает количество миллисекунд, прошедших с последнего кадра, поэтому его единицы измерения «s / f». velo должны иметь единицы измерения «м / с», чтобы сделать движение плавным с течением времени. Количество для обновления позиции этого кадра составляет m / s * s / f = m / f. Эти единицы имеют смысл, они измеряют расстояние на кадр.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]