Particle Systems

Examples

New examples on Github!

download zipped archive of all examples

noc noc noc noc noc noc

polymorphism, inheritance, basic particle system, textured particle system, multiple particle systems, particles plus forces

Related

Great Moments in
Computer Graphics History


 
The term “particle system” was coined in 1983 by William T. Reeves as he worked to create the “Genesis” effect at the end of the movie, Star Trek II: The Wrath of Khan.

“A particle system is a collection of many many minute particles that together represent a fuzzy object. Over a period of time, particles are generated into a system, move and change from within the system, and die from the system.”
– Reeves Particle Systems: a Technique for Modeling a Class of Fuzzy Objects.

Particle Systems

A particle system is a collection of independent objects, often represented by a simple shape or dot. It can be used to model many irregular types of natural phenomena, such as explosions, fire, smoke, sparks, waterfalls, clouds, fog, petals, grass, bubbles, and so on. In a system, each particle will have its own set of properties related to its behavior (for example, velocity, acceleration, etc.) as well as its look (for example, color, shape, image, etc.).

One of my favorite examples of a particle system in action is Karl Sims’ “Particle Dreams”, a short video visualizing different complex phenomena (snowstorms, waterfalls, and a “Self-Breathing Head,”) by applying behavior rules to thousands of tiny particles. (Note this was made in 1988!).

We are going to look at implementation strategies for coding a particle system. How do we organize our code? Where do we store information related to invididual particles vs. information related to the system as a whole? The examples we’ll look at focus on managing the data associated with a particle system. The examples will use simple shapes for the particles and apply only the most basic behaviors (gravity, etc.). However, by using this framework and building in more interesting ways to render the particles and compute behaviors, you can achieve lots of different effects.

The particle object. We first need to declare our class and decide what instance variables we want to have:

class Particle {
  PVector loc;
  PVector vel;
  PVector acc;
  float r;
  float timer;

This is nothing really new, just some variables to keep track of location, velocity, acceleration, and size. However, we are adding an important element, a timer to keep track of the particle’s life. Our particles, sadly, will not live forever.

//function to update location
void update() {
  vel.add(acc) ;
  loc.add(vel) ;
  timer -= 1.0;
}

In the above method, the timer counts down each cycle. We would probably want to improve this and keep track of how fast the timer should count in a separate variable, but this will do for now.

We also want to include a method that tells us if the object is alive or dead based on the state of the timer. That way the system can know whether it needs to keep it around.

boolean dead() {
  if (timer < = 0.0) {
    return true;
  } else {
    return false;
  }
}

You can imagine easily what else would be included here: constructors, a “render” method, etc. And in fact, we could stop here and just make an array of these particles, call methods on them in a for loop and be done with it. However, we want to go a step further and introduce not only a “Particle” class, but a “ParticleSystem” class, i.e. a class that manages the collection of particles itself. Our main program, therefore, doesn’t necessarily require any references to individual particles specifically.
It references the systems themselves, which in turn manage the particles.

To do this efficiently, we want to take a look at how we can have store a variable collection of objects.

Resizable arrays

Most of our examples up until now (with the exception of a few) have used standard java arrays to keep track of ordered lists of information. We might have an array of 10 objects, looping through them each cycle to update locations, render them, etc. However, in the case of a standard array we are limited to having 10 and only 10 objects. There are certainly alternatives (using a very large array and having a separate variable to keep track of how much of the array we should use at any given time), but it would be much more useful if we could dynamically size the array at run-time. In the case of a particle system, this will really help.

To accomplish our goal of having a resizeable array, we will use the java class ArrayList, which can be found in java.util. This class is not part of the Processing reference and in order to know how to use an ArrayList instance, we must consult the java API.

Using an ArrayList is conceptually similar to a standard array, but the syntax will be quite different. Here is some code (that assumes the existance of a class “Particle”) demonstrating the same functionality, first with an array, and second with an ArrayList. (Note we would never actually write the code below, it’s just meant to illustrate the differences between arrays and ArrayLists)

int MAX = 10;
// Declaring the array
Particle[] parray = new Particle[MAX];
// Declaring the arraylist
ArrayList plist = new ArrayList() ;
 
// The following code you would usually find in setup
for (int i = 0; i < parray.length; i++) {
  parray[i] = new Particle() ;
}
 
for (int i = 0; i < MAX; i++) {
  plist.add(new Particle()) ;
}
 
// The following code you would usually find in draw
for (int i = 0; i < parray.length; i++) {
  Particle p = parray[i];
  p.run() ;
  p.render() ;
}
 
for (int i = 0; i < plist.size() ; i++) {
  Particle p = (Particle) plist.get(i) ;
  p.run() ;
  p.render() ;
}
traer.physics
You might be interested in checking out this terrific Processing physics library. It has an implementation of a particle system class with real-time physics and many other features. I encourage you to experiment with using this library as well as writing your own, discovering the pros and cons of both.

Note that in this last for loop, we have to make sure to cast the object we pull out of the ArrayList. The ArrayList doesn't keep track of the type for things stored inside -- it's our job to remind it!

A Particle System Class

The main piece of the particle system class will be the ArrayList as it will contain all the particles in the system. However, some other "global" variables for a particle system might be required, such as an origin point for where particles are birthed, an image reference for a particle texture, etc.

class ParticleSystem {
 
  ArrayList particles;    //an arraylist for all the particles
  PVector origin;        //an origin point for where particles are birthed
 
  ParticleSystem(int num, PVector v) {
    particles = new ArrayList() ;    //initialize the arraylist
    origin = v.get() ;              //store the origin point
    //add "num" amount of particles to the arraylist
    for (int i = 0; i < num; i++) {
      particles.add(new Particle(origin)) ;
    }
  }

Clearly, the next step is to write a method that calls methods on all the particles in the system. As we've seen from how an ArrayList works, this is fairly simple:

void run() {
  for (int i = 0; i < particles.size() ; i++) {
    Particle p = (Particle) particles.get(i) ;
    p.run() ;
  }
}

However, while we cycle through each particle, we want to check and make sure the particle is still alive; if it is not, we should remove it from the ArrayList. There is a problem here -- when an element is removed at a specified position in this list, any subsequent elements are shifted to the left (i.e. one is subtracted from their indices). This will result in skipping elements as they are deleted (if item N is deleted, item N+1 becomes item N and is not checked since the loop has already checked item N!) This is easily, solved, however, by going through the ArrayList backwards.

void run() {
  // Cycle through the ArrayList backwards b/c we are deleting
  for (int i = particles.size()-1; i >= 0; i--) {
    Particle p = (Particle) particles.get(i) ;
    p.run() ;
    if (p.dead()) {
      particles.remove(i) ;
    }
  }
}

Finally, we can implement additional functionality to our system, such as methods that will birth new particles and a method that will test if the entire system itself is dead:

void addParticle() {
  particles.add(new Particle(origin));
}
 
void addParticle(Particle p) {
  particles.add(p);
}
 
boolean dead() {
  if (particles.isEmpty()) {
    return true;
  } else {
    return false;
  }
}

Once we have finished implementing the particle class and the particle collection class, our main program code is nice and elegant. We only have to declare a ParticleSystem as a global variable, call the constructor in setup() to instantiate it, and then call the run function in draw() (as well as choose to call "addParticle()" whenever new particles should be created.)

ParticleSystem ps;
 
void setup() {
  size(200,200);
  ps = new ParticleSystem(1,new PVector(width/2,height/2,0)) ;
  smooth() ;
}
 
void draw() {
  background(255);
  ps.run();
  ps.addParticle();
}

OOP -- Inheritance

In the case of a particle system, we will often want to have systems containing different types of particles. In order to accomplish this, we would like to avoid writing a new class for every single particle. A better solution would be to create "subclasses" of our master particle class that could use the exiting data and functionality of a regular ol' particle, adding other features as necessary.

Object oriented programming allows us define classes in terms of other classes. In other words, a class can be a subclass (aka "child") of a super class (aka "parent"). This concept is known as "inheritance."

Take this very typical example, where we have a class containing a few instance variables, a constructor to fill them, and a method that increments the x and y variables randomly.

class Shape {
  float x;
  float y;
  float r;
 
  Shape(float x_, float y_, float r_) {
    x = x_;
    y = y_;
    r = r_;
  }
 
  void jiggle() {
    x += random(-1,1) ;
    y += random(-1,1) ;
  }
 
}

Now what if we create a subclass from Shape (let's call it "Square"). It will inherit all the instance variables and methods from shape. We write a new constructor with the name "Square", however, here we are executing the code from the parent class by calling "super".

class Square extends Shape {
 
  //inherits all instance variables from parent
  //we could add variables for only Square here if we so
 
  Square(float x_, float y_, float r_) {
    super(x_,y_,r_) ;
  }
 
  //inherits jiggle method from parent
 
   //adds a new render method
  void render() {
    rectMode(CENTER) ;
    fill(255) ;
    noStroke() ;
    rect(x,y,r,r) ;
  }
}

Here is another subclass with some additional functionality. It adds an instance variable to keep track of color (this is just to show how this is possible, most likely we would want the super class to include color). It also calls the parent jiggle method (with super), but adds some additional code.

class Circle extends Shape {
 
  //inherits all instance variables from parent + adding one
  color c;
 
  Circle(float x_, float y_, float r_, color c_) {
    super(x_,y_,r_) ;  // call the parent constructor
    c = c_;           // also deal with this new instance variable
  }
 
  //call the parent jiggle, but do some more stuff too
  void jiggle() {
    super.jiggle() ;
    r += random(-1,1) ;
    r = constrain(r,0,100) ;
  }
 
   //adds a new render method
  void render() {
    ellipseMode(CENTER) ;
    fill(c) ;
    noStroke() ;
    ellipse(x,y,r,r) ;
  }
}

Polymorphism

Polymorphism (i.e. many forms) refers to the concept that we can treat an object instance in multiple ways. A Circle is a Circle, but it is also a Shape so we can refer to it as either.

Shape c1 = new Circle(100,100,20,color(255)) ;
Circle c2 = new Circle(100,100,20,color(255)) ;

Both of the above lines of code are legal (!!). Even though we declare c1 as a Shape, we're really making a Circle object and storing it in the c1 reference. (We can safely call all the Shape methods on c1 b/c the rules of inheritance dictate that a Circle can do anything a Shape can). At run-time, however, java will determine that this object really truly is a Circle and run the proper methods. Amazing! This becomes particularly useful when we have an array. Here we can make an array of "Shapes", put both Circles and Squares into the array, but not have to worry about which are which -- that will all be taken care of for us!!

Shape[] s = new Shape[25];
for (int i = 0; i < s.length; i++) {
 int r = int(random(2)) ;
 //randomly put either circles or squares in our array
 if (r == 0) {
   s[i] = new Circle(100,100,10,color(255,0,0)) ;
 } else {
   s[i] = new Square(100,100,10) ;
 }
}

Later, we can run through the array like so. Again, even though some of the elements are circles and some are squares, we don't have to specify in our code since we can treat them all in the general form as "shapes".

for (int i = 0; i < s.length; i++) {
  Shape ashape = s[i];
  ashape.jiggle() ;
  ashape.render() ;
}

For a much better explanation of polymorphism, check out How my Dog learned Polymorphism.

  • http://wolispace.com/cow wolis

    Am I right in assuming that the term/concept of ‘particles’ in 3D initially came from the ‘Wrath of Khan’? Who would ahve thunk it.

    I have found.. in a purely textual world, that I have emulated ‘particles’ with objects that replcate themselves then iether die or continue growing. (find the vine).

    This is all rather facunating.. I have alot of research to do.

    While your doing nothing, why not drop in to my Creative Object World (cow) createa chair, paint it as limegreen and sit in it.

    http://wolispace.com/cow

  • Corina

    I would like to know more about the physics library that you have pointed to – traer.physics. Is it open source? Can I contact the authors? I want to use it in one of my projects and I need to find out more about it.

    Thanks for your help, I appreciate it.

  • utopiko

    Hi, Thanks for this great example. 

    I’m just having trouble understanding the two addParticle function… 
    First If I comment them, nothing happen, so its like their are not used…
    And second what is the difference between the two…

    Thanks again !

    void addParticle() {
    particles.add(new Particle(origin));
    }
     
    void addParticle(Particle p) {
    particles.add(p);
    }

  • shiffman

    Sorry for the confusion.  The functions are not used in all the examples.  The first one adds a Particle for you by creating one. The second one adds a particle that has previously been created (and passed in as an argument).  In my revamped examples and tutorials that I am close to publishing hopefully this will be made more clear!

  • utopiko

    Alright, thanks for answering. Let me know when your new tutorial comes out ! There is a lack of tutorials for newbies on particule around the Processing world…so yours will be welcome ! :)

  • utopiko

    Hey Daniel, I’m going to try and push my luck for more of your help ;)
    You can not even respond and I won’t take it bad, we are all busy and have all our own problems..
    (Also, if this sounds too much for a beginner, maybe you would be interested in helping me with the project, depending on your fees )

    But if you do, thank you. I promise I’ll give it back to the Processing community after ;)

    I’ve been playing with your Multiple Particle System, and there is still some features that I have trouble adding. 

    1. Create coloured particles that are born one color and died another. (right now you’ll see in my code that it just change the color continually)
    2. Change easily the size of my particles triangles…
    3. Reducing the number of particle emitted. For this I added a variable pChance when calling the Particle system, but its not quite enough.. 
    4. Create particle that scale down at the end. I try to play with pushMatrix, scale and popMatrix, put not so successful.

    5. And eventually, a more advance feature would be to add some kind of turbulence to the particles..

    Actually, I’m trying to create a similar animation I did in After effect as a mockup, you can see it here :
    http://dl.dropbox.com/u/3407220/feudou.m4v
    It doesn’t have to be exactly like that, but I want too simulate a Fire. 
    Eventually that fire will be stronger when someone tweet something specific, and it will get weaker if no one tweet.

    My processing code is here : 
    http://dl.dropbox.com/u/3407220/Feu_FondCentre.zip 

    ouff, thanks for reading ;)

  • Jim

    Thanks for this great lesson. 
    I’ve been playing around with a particle system very similar to yours. Now, I was wondering about particle interaction.
    Take this for example: how would you go about adding a line between particles? (how would the location of two particles, following in the arraylist, be returned?)