Search code examples
c++openglparticle-system

Explanation of openGL particle effect


So I have this code that produces fireworks using what appears to be a particle effect, but I don't understand what is going on in the code. Could someone explain it to me, particularly the initialize function and the draw blast blast function. If you could annotate it with notes that would be super.

/* fireworks.c - simulate fireworks with particle systems */

#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#ifdef WIN32
//to correct ASCI deviations in Microsoft VC++ 6.0

#define M_PI (3.1415926535897932384626433832795)

double drand48()
{   return (rand()%10000)/10000.0; }

//end of corrections
#endif


#define MAX_POINTS 5000
int numPoints;
GLfloat curx, cury;
GLfloat x[MAX_POINTS], y[MAX_POINTS];
GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
GLfloat red, green, blue;
int step; int length;

void initialize()
{ int j; double temp, temp2;

numPoints = drand48()*(MAX_POINTS-1);
curx = -0.5 + drand48();
cury = 0.0 + drand48();

red = 0.5 + 0.5*drand48();
green = 0.5 + 0.5*drand48();
blue = 0.5 + 0.5*drand48();
glPointSize(1.5); 
step = 0;
length = 700 + 300*drand48();


/* initialize the blast */
for (j=0 ; j<numPoints ; j++ ) {
x[j] = curx;
y[j] = cury;
temp = drand48();
temp2 = drand48()*2.0*M_PI;
xacc[j] = (cos(temp2) * temp)/length;
yacc[j] = (sin(temp2) * temp)/length;
}

}

void draw_blast(void)
{ int i;
double glow = (length - step) / (double)length;
glColor3f(red*glow, green*glow, blue*glow);
glBegin(GL_POINTS);
for (i=0;i<numPoints;i++) {
x[i] += xacc[i];
y[i] += yacc[i];
glVertex2f(x[i], y[i]);
}
glEnd();
glFlush();
glutSwapBuffers();
}

void display(void)
{ int i;
glClear(GL_COLOR_BUFFER_BIT);
if (step < 0.9*length) {
for (i=0; i<numPoints; i++)
yacc[i] -= 0.02 / length; // gravity
draw_blast();
}
step ++;
if (step > length) initialize();
}

void idle(void)
{
glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) { 
case 27: exit(0); break;
}
}

void reshape (int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION); 
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0,
-1.0*(GLfloat)h/(GLfloat)w, 1.0*(GLfloat)h/(GLfloat)w,
-1.0, 1.0);
else
glOrtho(-1.0*(GLfloat)w/(GLfloat)h, 1.0*(GLfloat)w/(GLfloat)h,
-1.0, 1.0,
-1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (800, 800);
glutInitWindowPosition(0, 0);
glutCreateWindow ("Fireworks");

glClearColor (0.0, 0.0, 0.0, 0.0);
initialize();

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutMainLoop();

return 0; 
}

Solution

  • Yes, it is a particle system. However - not a particularly efficient one.

    Let's go through it step by step:

    GLfloat x[MAX_POINTS], y[MAX_POINTS];
    GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
    

    x and y hold the particles' positions. xacc and yacc hold their velocities.

    In initialize:

    numPoints = drand48()*(MAX_POINTS-1);
    

    This sets a random number of particles...

    curx = -0.5 + drand48();
    cury = 0.0 + drand48();
    red = 0.5 + 0.5*drand48();
    green = 0.5 + 0.5*drand48();
    blue = 0.5 + 0.5*drand48();
    glPointSize(1.5); 
    step = 0;
    length = 700 + 300*drand48();
    

    ... with a random center position, color, and radius (length).

    for (j=0 ; j<numPoints ; j++ ) {
    

    This starts the initialization for every particle.

    x[j] = curx;
    y[j] = cury;
    

    Sets the particle's position the the center position.

    temp = drand48();
    temp2 = drand48()*2.0*M_PI;
    xacc[j] = (cos(temp2) * temp)/length;
    yacc[j] = (sin(temp2) * temp)/length;
    

    Sets a random direction of the particle (temp2) and a random velocity based on the system's radius (temp / length).

    In drawBlast():

    double glow = (length - step) / (double)length;
    glColor3f(red*glow, green*glow, blue*glow);
    

    Slowly fades the particles' color to black.

    x[i] += xacc[i];
    y[i] += yacc[i];
    

    Advance the particle by their velocity. This assumes a constant frame rate.

    glVertex2f(x[i], y[i]);
    

    Draw the particle as a point.

    In display():

    yacc[i] -= 0.02 / length; // gravity
    

    Accelerate every particle downwards. I.e. simulate that the particles fall.