今天要实现的是利用OpenGL模拟三个物理学中常见的运动:自由落体,匀速之间,弹簧振子。

首先要实现一个空间三维向量类,看这篇文章:向量类的实现

然后主要要实现的是质点类,

/* Copyright: 2012, ustc All rights reserved. contact:k283228391@126.com File name: mass.h Description:Particle in Physical Author:Silang Quan Version: 1.0 Date: 2012.12.21 */ #ifndef MASS_H #define MASS_H #include "vector3d.h"  class Mass {     public:         Mass();         Mass(float _m,float _size){m=_m;size=_size;};         void init();         void simulate(float dt);         void checkBnd(float x1,float x2,float y1,float y2);         void setForce(Vector3D _force){force=_force;};         void setVel(Vector3D _vel){vel=_vel;};         virtual ~Mass();         inline Vector3D getPos(){return pos;};         inline Vector3D getVel(){return vel;};         inline Vector3D getForce(){return force;};         inline float getSize(){return size;};       protected:     private:     float size;                         //大小 	float m;							// 质量 	Vector3D pos;								// 位置 	Vector3D vel;								// 速度 	Vector3D force;								// 力 };  #endif // MASS_H 

简单解释一下:质点主要有大小,质量,速度,受力这四个属性。除了一些getset方法外,最关键的是simulate和checkBnd连个方法,分别是模拟运动和边界检测,实现起来也比较简单。

/* Copyright: 2012, ustc All rights reserved. contact:k283228391@126.com File name: mass.cpp Description:Particle in Physical Author:Silang Quan Version: 1.0 Date: 2012.12.21 */ #include "mass.h"  Mass::Mass() {     //ctor } void Mass::init() {     force=Vector3D::zero();     vel=Vector3D::zero(); } void Mass::simulate(float dt) {     Vector3D acl=force/m;     vel=vel+acl*dt;     pos=pos+vel*dt; } Mass::~Mass() {     //dtor } void Mass::checkBnd(float x1,float x2,float y1,float y2) {     if (pos.x - size < x1 || pos.x +size > x2) vel.x = -vel.x;     if (pos.y - size < y1 || pos.y + size > y2) vel.y = -vel.y; } 

在simulate函数中我们用到了运动学的公式:a=F/m,Vt=Vo+at.deltaS=at^2.

接下来我们就可以来进行模拟了!

首先在main.cpp中声明几个全局变量:

GLUquadricObj *mySphere; Mass constVelBall; Mass gravityBall; Mass springBall;

GLUquadricObj是二次曲面对象的声明类,后面三个是声明三个质点。

接下来是对三个质点的初始化:

void initMasses() {     constVelBall=Mass(5.0,3);     constVelBall.init();     constVelBall.setVel(Vector3D(3.0,5.0,0.0));      gravityBall=Mass(5.0,2);     gravityBall.init();     gravityBall.setVel(Vector3D(-1.0,0.0,0.0));     gravityBall.setForce(Vector3D(0.0,-2.0,0.0));      springBall=Mass(5.0,4);     springBall.init();     springBall.setVel(Vector3D(2.0,0.0,2.0)); }

然后是模拟检测:

void simulateCheck() {     Vector3D connectionPos = Vector3D(0.0f, 0.0f, 0.0f);     constVelBall.simulate(0.1);     constVelBall.checkBnd(-20,20,-20,20);     gravityBall.simulate(0.1);     gravityBall.checkBnd(-20,20,-20,20);      springBall.simulate(0.1);     Vector3D springVector = springBall.getPos() - connectionPos;     springBall.setForce(springVector*(-0.1)); }

这两个函数在main中进行调用。

还需要添加一个绘制质点的函数。我们用球体来代表质点,Mass中的size域就用来做半径。

void drawMass(Mass m) {     Vector3D tmp=m.getPos();     glPushMatrix();     glTranslatef(tmp.x,tmp.y,tmp.z);     gluSphere(mySphere,m.getSize(), 32, 16);     glPopMatrix(); }


最后来看渲染函数:

void renderGL() { 	// Clear the color and depth buffers. 	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 	// We don't want to modify the projection matrix. */ 	glMatrixMode( GL_MODELVIEW ); 	glLoadIdentity( ); 	// Move down the z-axis. 	glTranslatef(0.0f,0.0f,-35.0f);     glColor3ub(0, 0, 255);										// Draw In Blue 	glBegin(GL_LINES); 	// Draw The Vertical Lines 	for (float x = -20; x <= 20; x += 2.0f)						// x += 1.0f Stands For 1 Meter Of Space In This Example 	{ 		glVertex3f(x, 20, 0); 		glVertex3f(x,-20, 0); 	} 	// Draw The Horizontal Lines 	for (float y = -20; y <= 20; y += 2.0f)						// y += 1.0f Stands For 1 Meter Of Space In This Example 	{ 		glVertex3f( 20, y, 0); 		glVertex3f(-20, y, 0); 	} 	glEnd(); 	glColor3ub(0,255, 255); 	drawMass(constVelBall);     glColor3ub(255,0, 255);     drawMass(gravityBall);     glColor3ub(255,255,0);     drawMass(springBall); 	SDL_GL_SwapBuffers( ); }

先渲染一些网格,然后对质点进行渲染。

最后的效果就像这样:



×××