Examples

download zipped archive of all examples

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 animation and rendering using data parallel computation”, Karl Sims (available via NYU network/proxy)
  • “Particle Systems, a Technique for Modeling a Class of Fuzzy Objects”, Reeves (available via NYU network/proxy)
  • How my Dog learned Polymorphism
  • Particle Systems (Siggraph)
  • Particle System API, by David K. McAllister
  • Particle Systems by Allen Martin
  • Physically Based Modeling, Particle System Dynamics by Andrew Witkin
  • 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.


    2 Responses to “Particle Systems”  

    1. 1 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

    2. 2 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.

    Leave a Reply