/* 在一个盒子里生成粒子 */
#define MAX_NUM_PARTICLES 1000 /* 最大粒子数 */
#define INITIAL_NUM_PARTICLES 25 /* 初始粒子数 */
#define INITIAL_POINT_SIZE 5.0 /* 初始粒子大小 */
#define INITIAL_SPEED 1.0 /* 粒子初始速度 */
#define TRUE 1
#define FALSE 0
#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>
void myDisplay();
void myIdle();
void myReshape(int, int);
void main_menu(int);
void collision(int);
float forces(int, int);
void myinit();
/* 全局变量 */
//int num_particles ; /* 粒子的数目 */
/* 粒子结构体 */
typedef struct particle
{
int color; /* 颜色 */
float position[3]; /* 位置 */
float velocity[3]; /* 速度 */
float mass; /* 质量 */
} particle;
particle particles[MAX_NUM_PARTICLES]; /* 粒子系统 */
/* 粒子系统的初始状态 */
int present_time;
int last_time;
int num_particles = INITIAL_NUM_PARTICLES;
float point_size = INITIAL_POINT_SIZE;
float speed = INITIAL_SPEED;
int gravity = FALSE; /* 不考虑重力 */
bool elastic = FALSE; /* 不考虑弹性恢复 */
bool repulsion = FALSE; /* 不考虑排斥力 */
float coef = 1.0; /* 完全弹性碰撞 */
float d2[MAX_NUM_PARTICLES][MAX_NUM_PARTICLES]; /* 粒子距离数组 */
GLsizei wh = 500, ww = 500; /* 初始窗口的大小 */
GLfloat colors[8][3]={{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}, {0.0, 1.0, 1.0}, {1.0, 0.0, 1.0}, {1.0, 1.0, 0.0},
{1.0, 1.0, 1.0}};
/* 每当改变窗口大小或移动窗口时就会调用reshap回调函数 */
void myReshape(int w, int h)
{
/* 调整裁剪视见体 */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2.0, 2.0, -2.0, 2.0, -4.0, 4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(1.5,1.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0);
/* 调整视口并重绘 */
if(w<h) glViewport(0,0,w,w);
else glViewport(0,0,h,h);
/* 为绘制程序使用的窗口设置大小(全局变量) */
ww = w;
wh = h;
}
void myinit()
{
int i, j;
/* 设置粒子的随机的位置和速度 */
for(i=0; i<num_particles; i++)
{
particles[i].mass = 1.0;
particles[i].color = i%8;
for(j=0; j<3; j++)
{
particles[i].position[j] = 2.0*((float) rand()/RAND_MAX)-1.0;
particles[i].velocity[j] = speed*2.0*((float) rand()/RAND_MAX)-1.0;
}
}
glPointSize(point_size);
/* 把清屏颜色设置为灰色 */
glClearColor(0.5, 0.5, 0.5, 1.0);
}
void myIdle()
{
int i, j, k;
float dt;
present_time = glutGet(GLUT_ELAPSED_TIME);
dt = 0.001*(present_time - last_time);
for(i=0; i<num_particles; i++)
{
for(j=0; j<3; j++)
{
particles[i].position[j]+=dt*particles[i].velocity[j];
particles[i].velocity[j]+=dt*forces(i,j)/particles[i].mass;
}
collision(i);
}
if(repulsion) for(i=0;i<num_particles;i++) for(k=0;k<i;k++)
{
d2[i][k] = 0.0;
for(j=0;j<3;j++) d2[i][k]+= (particles[i].position[j]-
particles[k].position[j])*(particles[i].position[j]-
particles[k].position[j]);
d2[k][i]=d2[i][k];
}
last_time = present_time;
glutPostRedisplay();
}
float forces(int i, int j)
{
int k;
float force = 0.0;
if(gravity&&j==1) force = -1.0; /* 简单的重力 */
if(repulsion) for(k=0; k<num_particles; k++) /* 排斥力 */
{
if(k!=i) force+= 0.001*(particles[i].position[j]-particles[k].position[j])/(0.001+d2[i][k]);
}
return(force);
}
void collision(int n)
/* 检测粒子与立方体的碰撞并在必要的时候使粒子发生反弹 */
{
int i;
for (i=0; i<3; i++)
{
if(particles[n].position[i]>=1.0)
{
particles[n].velocity[i] = -coef*particles[n].velocity[i];
particles[n].position[i] = 1.0-coef*(particles[n].position[i]-1.0);
}
if(particles[n].position[i]<=-1.0)
{
particles[n].velocity[i] = -coef*particles[n].velocity[i];
particles[n].position[i] = -1.0-coef*(particles[n].position[i]+1.0);
}
}
}
void main_menu(int index)
{
switch(index)
{
case(1):
{
num_particles = 2*num_particles;
myinit();
break;
}
case(2):
{
num_particles = num_particles/2;
myinit();
break;
}
case(3):
{
speed = 2.0*speed;
myinit();
break;
}
case(4):
{
speed = speed/2.0;
myinit();
break;
}
case(5):
{
point_size = 2.0*point_size;
myinit();
break;
}
case(6):
{
point_size = point_size/2.0;
if(point_size<1.0) point_size = 1.0;
myinit();
break;
}
case(7):
{
gravity = !gravity;
myinit();
break;
}
case(8):
{
elastic = !elastic;
if(elastic) coef = 0.9;
else coef = 1.0;
myinit();
break;
}
case(9):
{
repulsion = !repulsion;
myinit();
break;
}
case(10):
{
exit(0);
break;
}
}
}
void myDisplay()
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POINTS); /* 绘制所有的粒子 */
for(i=0; i<num_particles; i++)
{
glColor3fv(colors[particles[i].color]);
glVertex3fv(particles[i].position);
}
glEnd();
glColor3f(0.0,0.0,0.0);
glutWireCube(2.2); /* 绘制一个盒子的线框图 */
glutSwapBuffers();
}
void main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("particle system");
glutDisplayFunc(myDisplay);
myinit ();
glutCreateMenu(main_menu);
glutAddMenuEntry("more particles", 1);
glutAddMenuEntry("fewer particles", 2);
glutAddMenuEntry("faster", 3);
glutAddMenuEntry("slower", 4);
glutAddMenuEntry("larger particles", 5);
glutAddMenuEntry("smaller particles", 6);
glutAddMenuEntry("toggle gravity",7);
glutAddMenuEntry("toggle restitution",8);
glutAddMenuEntry("toggle repulsion",9);
glutAddMenuEntry("quit",10);
glutAttachMenu(GLUT_MIDDLE_BUTTON);
glutIdleFunc(myIdle);
glutReshapeFunc (myReshape);
glutMainLoop();
}