Particle Systems

A method of modeling "fuzzy" objects - e.g. fire, smoke, water

Introduced in 1983, in the Star Trek II "Genesis Effect"

Model complex objects not easily represented by ordinary surfaces - large masses of simple, dynamic particles are used.






Particles

Particles are usually treated as simple points with position, velocity, and color.

Individual particles are added to the system, move about, are affected by forces such as gravity, and eventually die out.






Particle Data

Example C data structure:

struct _particle
    {
     Vector3 position; 
     Vector3 tailPosition;
     Vector3 velocity;
     Vector3 color;
     float removeTime;
    };

struct _particle * particleArray;





Particle Class - Python

Example Python class:

class particle:
    def __init__(self, position=Vector([0,0,0])):
        self.position = position
        self.velocity = Vector([uniform(-3,3), 8, uniform(-3,3)])
        self.color = [uniform(.5,1), uniform(0,1), uniform(0,0.5)]
    def update(self, dt):
        self.position += self.velocity * dt
        self.velocity += gravity * dt

class particleSystem:
    def __init__(self):
        self.particles = []
    def addParticles(self, num):
        for i in range(0,num):
            self.particles.append(particle())
...





Particle Code

Particle system code has three major parts:






Genesis Effect






Genesis Effect






Rendering Particles

Particles can be drawn in different ways, for different visual effects.

The simplest way is using points or lines.


Example:






Other Primitives

Particles don't have to be rendered as just points or lines.

A common alternative to points & lines for particles is simple textured polygons. For smoke or clouds, the texture would look like a single puff.

In this case, one uses fewer particles, as each is much larger than a single point.






Cumulative Rendering

When drawing particles, we often want them to "add up" in some way to form a fuzzy effect, rather than looking like just a set of individual points or lines.

This can be done using blending. Disabling depth-buffer-writing in this case is useful, because we don't want the particles to obscure each other.






Cumulative Rendering

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE);
glBegin(GL_LINES);
for (int i=0; i < numParticles_; i++)
    {
    glColor3fv(particles_[i].color.vec);
    glVertex3fv(particles_[i].tailPosition.vec);
    glVertex3fv(particles_[i].position.vec);
    }
glEnd();
glDepthMask(GL_TRUE);
glBlendFunc(GL_ONE, GL_ZERO);
glDisable(GL_BLEND);

Example:






Forces

Particles can be affected by forces. This can be implemented in the same way as applying forces to ordinary solid objects.






Forces

dms::Vector3 gravityAccel = gravity_ * dt;
dms::Vector3 windAccel = wind_ * dt;
for (int i=0; i < numParticles_; i++)
    {
    particles_[i].velocity += gravityAccel;
    particles_[i].velocity += windAccel;
    particles_[i].tailPosition = particles_[i].position;
    particles_[i].position += particles_[i].velocity * dt;
    }

Examples:






Optimization

A particle system can have hundreds (or thousands) of individual particles.
Operations on each particle can add up and make things slow.
For real-time use, minimize the number of particles, and avoid, simplify, or pre-calculate any expensive operations.

Expensive operations include:






Grass






Trees



Creative Commons License
This document is by Dave Pape, and is released under a Creative Commons License.