这是计算机图形学基础的一道单元练习题,看题的时候觉得没什么,写出来才发现其中大有门道,其中有几个值得关注的地方:
- 首先如果你是以窗口底部为地面的话,你会发现小球在第二次下落时无法回弹,这就很恶心了,做了很多无谓的尝试查了一些资料最后也只是找到了一个合适的位置让小球可以一直下落和回弹。
- 还有一个细节就是我初始化小球y坐标为9.0001,而其回弹的最高位置是9.0,如果初始化小球y坐标也是9.0,小球仍然会出现上面那种情况。
- 其次就是在模拟重力加速度以及放入实际的牛顿那个重力公式中的时候,方向很重要,注意是速度的方向在回弹和下落初的变换,重力加速度始终是向下的。
- 最后就是用
glutTimerFunc(2, timer, 0);
指定定时器回调函数让小球自己去动。计算自由下落公式的相隔时间是2ms。所以把计时器也设为2ms吧。效果还不错。
为了看看是不是真的自由下落没有损失,我还在起始点和终点画了两条红线便于观察:
代码:
#include <windows.h>
#include <GL/freeglut.h>
#define G 9.8
bool direction = true;
double t = 0.002;
struct Ball{//球的结构体
GLdouble y;
GLdouble vy;
};
Ball ball;
void init(void){
//初始化球体属性
ball.y = 9.00001 ;
ball.vy = 0.0 ;
glClearColor(0.0,0.0,0.0,0.0);
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glColor3f(1.0,0.0,0.0);
glBegin(GL_LINES);
glVertex2f(-5.0,9.0);
glVertex2f(5.0,9.0);
glVertex2f(-5.0,-3.0);
glVertex2f(5.0,-3.0);
glEnd();
glColor3f(1.0,1.0,0.0);
glTranslated(0,ball.y,0); //将绘图中心移动到球体的中心
glutSolidSphere(0.5,50,50); //绘制一个球体
if(direction){
ball.y = ball.y-(ball.vy*t+0.5*G*t*t); //根据牛顿运动定律计算出球的位移公式
ball.vy = ball.vy + G*t; //根据牛顿运动定律计算出球体的速度
if(ball.y <=-3.0){
direction = false; //触发转向条件,改变direction的值,使球体运动方向改变
}
}else{
ball.y = ball.y + (ball.vy*t-0.5*G*t*t);
ball.vy = ball.vy-G*t;
if(ball.y >= 9.0){
direction = true;
}
}
glPopMatrix();
//交换前后缓冲区
glutSwapBuffers();
}
void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(2,timer, 0);
}
void reshape(int w,int h){
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-15,15,-15*(GLfloat)h/(GLfloat)w,15*(GLfloat)h/(GLfloat)w,-15,15);
else
glOrtho(-15*(GLfloat)h/(GLfloat)w,15*(GLfloat)h/(GLfloat)w,-15,15,-15,15);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc,char** argv){
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowSize(600,600);
glutInitWindowPosition(450,100);
glutCreateWindow("小球自由落体");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
//永动机
glutTimerFunc(2, timer, 0);
glutMainLoop();
return 0;
}