Particle System

This is my first tutorial about game programming. Maybe it’s not the right place to start for beginners but I think you can understand this tutorial quite easily. It’s nothing very hard to understand but you’ll have to have some knowledge about math, specially about vectors.

The tutorial is still a work in progress although I’ll present here the core of this tutorial. As soon as I complete this tutorial, I’ll put here.

Introduction

The best way to explain what a particle system is, is by giving an example: imagine that it’s raining (well, if it’s really raining outside, just go to your window :)), can you see all the drops falling? Imagine that you are playing a game where you fire a rocket, in its tail you see smoke and when the rocket hits a player, there’ll be body parts all over the place. All these objects of the same kind (drops, smoke, body parts) are particles and some sort of program controls this particles, creating, moving and destroying them. This program is the particle system.

Most games have implemented some kind of particle system, some more advanced, others more simple. When creating one particle system, there are some important things to consider:
– will this particle system design only for this game/program or will it be used in the future?
– is speed an issue?
– is memory an issue?

These questions are extremely important and before you continue you should have answers to all of them. Particle systems should be very flexible if you plan to use it in different games/programs. Thus the data structures you choose to your system must be flexible. But the main concern is about speed and memory. The more particles you have the more the system will run slow and grow in memory.

Well, after this introduction, let’s get into business.


The Particles

As the name indicates, a particle system has one or more particles. Each particle has a set of attributes that can change over time. In the next table I’ve some attributes that I’ll use on the particles of my system. You may add other attributes that you think that may fit.

Particle attributes:
– Previous position
– Current position
– Direction
– Speed
– Color
– Delta color
– Alpha
– Delta alpha
– Size
– Delta size
– Age
– Lifetime

I think that the name of each attribute is clearly self explanatory. I’ll talk about the delta ones that you might not understand clearly. These delta attributes (color, alpha and size) are the attributes, that will be added to the correspondent non-delta attributes, over time.

Here is the correspondent code to what is described before:

struct Particle {
  Vector3D m_prevPosition; // Previous position of the particle.
  Vector3D m_position;     // Position of the particle.
  Vector3D m_direction;    // Direction of the particle.
  float    m_speed;        // Speed of the particle.

  RGBColor m_color;       // Color of the particle.
  RGBColor m_colorDelta;  // Color to add over time.
  float m_alpha;          // Transparency of the particle.
  float m_alphaDelta;     // Transparency to add over time.

  bool active;      // Indicates if the particle is active.

  float m_age;      // Age of the particle.
  float m_lifetime; // Life time of the particle. Age at which the
                    // particle dies.

  float m_size;       // Size of the particle.
  float m_sizeDelta;  // Size to add over time.
};

You could create a class for your particles that would update their values but I thought that that wouldn’t be necessary for this case. Therefore, the particle system will take care of all updates of the particles.

Now let’s see the particle system.


The Particle System

The particle system must to have the means to configure and update the particles in the system. In this system I created some functions to set the attributes of the class. I think the code is quite well commented and it will be easy for you to read it and understand it. I’ll just explain some things I put there and the reason why I did this way.

First thing is the list of particles in the system. There are usually two ways to deal with the particles within the system, one using arrays and the other one using lists. If you store the data for each particle in an array, it will be of a fixed size (maximum number of particles) and sometimes you’ll reserve more memory than necessary (e.g. in the case you need only 100 particles and your particle data array is declared to more than the 100 particles needed.) In the other hand, using a list instead of an array, the process of dealing with the data becomes a more slow but you can control the amount of memory used by creating and destroying particles. The choice is up to you! Later I’ll do a simple test with real values to compare the differences.

typedef std::list Particles;  // Declare a list of particles.
Particles m_particles; // List of particles of the system.

I also created a second list of particles that will contain references to dead particles. Why should I have a list for dead particles? The answer is: for optimization purposes! In a particle system, particles born and die very fast (in most cases) and we must be always allocating and deallocating memory for these particles. With this list we make use of dead particles and the allocation process doesn’t have to be done. We only set the attributes for the particle and delete the reference of this particle from the dead particles list. Later I’ll present here the differences between using this additional list and not using it, for you to compare.

Particles m_deletedParticles; // List of deleted particles of the system. (For speed increase purposes)

Two important things to mention are the emitter function and the physics function. The emitter function is where you program the emitter of your system. Think of the emitter as the start point of the particles. Imagine that you have a hose spraying water… The end of the hose is the emitter that emits the drops of water (particles). The emitter sends the particles with a direction and speed, and it’s convenient that you add some randomness to create something more real. All the physics in the system are computed in the physics function. The purpose of this function is to simulate the physics that we want on the system, gravity, wind, it’s up to you. Modifying these two functions, you can create other effects with your particle system.

typedef void (*EmitterFunction)(Vector3D *emitterPos, Vector3D *emitterDir,
 Vector3D *particlePos, Vector3D *particleDir);

typedef void (*PhysicsFunction)(float time, Vector3D *pos, Vector3D *direction, float *speed);

Update of the system

Now let me explain the update method (I’ll not explain the method of the creation of the particles since it just sets the attributes of each particle he creates.)

The position of each particle is given by its direction times its speed times the time elapsed since the last update. If more forces act on the particle (gravity, wind, etc.), these will modify the particle’s position. The life of each particle will be decreased by the amount of time that has elapsed since last update. Other attributes of the particles are updated. Their size, color and alpha (transparency).

// If there is any physics acting on
if (m_physics)
  m_physics(time, &(part->m_position), &(part->m_direction), &(part->m_speed));

part->m_position.m_x += (part->m_direction.m_x) * (part->m_speed) * time;
part->m_position.m_y += (part->m_direction.m_y) * (part->m_speed) * time;
part->m_position.m_z += (part->m_direction.m_z) * (part->m_speed) * time;

// Let's update the particle's age.
part->m_age += time;

// Let's update the particle's color.
part->m_color.r += part->m_colorDelta.r * time;
part->m_color.b += part->m_colorDelta.b * time;
part->m_color.g += part->m_colorDelta.g * time;

// Let's update the particle's transparency.
part->m_alpha += part->m_alphaDelta * time;

// Let's update the particle's size.
part->m_size += part->m_sizeDelta * time;

When the age of a particle reaches its lifetime, the particle dies. When this happens, we add this dead particle to the dead particles list (remember? to increase the speed) and delete its reference from the active particles list instead of deleting the particle.

if(part->m_age >= part->m_lifetime) {
  part->active = false;                // We mark the particle has dead.
  i=m_particles.erase(i);              // We erase this particle from the system.
  m_deletedParticles.push_back(part);  // Add this particle to the  list of dead particles.
  m_numParticles--;                    // Update the number of particles in the system.
}

The system calculates how many particles it has to create by multiplying the number of particles to create per second with the amount of time elapsed and adding the m_particlesRest. Sometimes, we get values like 1.5 particles to create and of course we can’t create half particle so we save the decimal part into the m_particlesRest variable to use it in the next update. If there is any dead particles, we use them avoiding the allocation of memory. Their values are initialized (color, lifetime, etc.) and their initial position is set according to the emitter’s function.

// We are going to see how many particles we have to create.
float nPartCreate = m_particlesPerSec * time + m_particlesRest;
// We create only an integer number of particles.
unsigned int numParticlesToCreate = (int)nPartCreate;
// The remaining part is saved to subsequent calculus.
m_particlesRest = nPartCreate - numParticlesToCreate;

// If we have to create particles
if(numParticlesToCreate > 0)
  createParticles(numParticlesToCreate);  // we create the particles needed.

There is no collision detection in this particle system. It will complicate things a bit and I wanted to present something simple. I may add it in the future.

Another thing that should be present in the particle system is the use of billboards for each particle. A billboard is a polygon (normally a quad) that is always parallel to the screen. We’ll see this in a later tutorial.

I programmed two simple effects with this particle system, some snow and a simple particle jet. With time I’ll present more effects. By the way, send me some effects of your own 😉

These two effects are really simple to create:
– To create snow you just have to give some random values to the emitter’s position and throw the particles with a negative direction in the y axis (-y). In the physics we put some gravity acting on the particles.
– The emitter function of particle jet, throws the particles with a direction up in the air adding some randomness to create a more “fantastic” effect. The position of the emitter also varies a little. The physics here are the same as in the snow effect. Just add some gravity and it will do the trick 😉

Screen shot

particle_system

Download here the code for this tutorial.

That’s it for now. Hope you enjoyed it! Improve it, create amazing effects with it and share them with me (I also like to learn things ;)). Let me know if you have bugs/questions/comments/suggestions.

Before I go, I want to thank Diogo Andrade for some tips he gave me and for bits of code from his engine that I used in this particle system.

See you in the next tutorial!

References:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=01 – Setting Up An OpenGL Window
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06 – Texture Mapping
http://www.spellcasterstudios.com/users/diogo.andrade/ludiEngine3d_V3.2.zip – LudiEngine3d V3.2
http://www.gamedev.net/reference/articles/article1043.asp – Particle Chamber
http://www.gamedev.net/reference/articles/article1042.asp – Advanced Particle Systems
Vectors Tutorial (Mathematics Section)

Tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *