Creating Particles with Three.js

Introduction

Hello again. So by now you’ve got started with Three.js. If you’ve not you might want to go back. Assuming you have you’re probably thinking that you’d like to do something with particles. Let’s face it, everyone loves particles. And wouldn’t you know it, you can create them very easily using Three.js!

Creating a Particle System

Three.js treats a particle system like any other primitive shape in that it has geometry and position, scale and rotation properties. What it does is use the individual vertices of the geometry to position the particles. Why does it do that? A couple of reasons, I suspect: it means the whole system can be drawn in one go rather than thousands of draw calls to the WebGL context and also there are global properties for affecting all the particles at once.

Even though they are treated as part of the same object we can still style the particles individually in terms of their colour since Three.js sends through colour attributes to the shader when it’s drawing them. I won’t be doing that in this article, so if that’s something you’re interested in you should take a look at the example on the Three.js GitHub repo where vertex colours are used.

There is also a knock-on effect of having a particle system governed by the geometry vertices, which you may need to consider. Since under the hood Three.js reserves the correct amount of data to handle the particle system when it is rendered for the first time you can’t then add to and remove from the particle system easily. What you can do, if you need to, is drop the alpha of a particle to zero if you don’t need it at a certain point. But you should create the total number of particles required at the start.

To create a particle system we need the following code:

// create the particle variables
var particleCount = 1800,
    particles = new THREE.Geometry(),
    pMaterial = new THREE.ParticleBasicMaterial({
      color: 0xFFFFFF,
      size: 20
    });

// now create the individual particles
for (var p = 0; p < particleCount; p++) {

  // create a particle with random
  // position values, -250 -> 250
  var pX = Math.random() * 500 - 250,
      pY = Math.random() * 500 - 250,
      pZ = Math.random() * 500 - 250,
      particle = new THREE.Vertex(
        new THREE.Vector3(pX, pY, pZ)
      );

  // add it to the geometry
  particles.vertices.push(particle);
}

// create the particle system
var particleSystem = new THREE.ParticleSystem(
    particles,
    pMaterial);

// add it to the scene
scene.addChild(particleSystem);

If you run that, you’ll notice two things:

  1. The particles are squares
  2. They don’t move

Let’s fix both of those, one at a time.

Style++

When we created the ParticleBasicMaterial we just gave it a colour and a size. What we probably want to do is to give it an image instead so we have fine control over exactly what our particles look like.

Because as you’ve seen they are actually squares being drawn out we should make our texture square. To make it look more showbiz we’ll use additive blending, but to do that we need to make sure the background of the texture is black rather than transparent. The reason for this is that transparency and additive blending isn’t a supported combination right now as far as I understand it. But no matter because it’s going to look awesome.

Let’s update our ParticleBasicMaterial and the Particle System to get additive transparent particles. You can use my particle image if you like.

// create the particle variables
var pMaterial = new THREE.ParticleBasicMaterial({
  color: 0xFFFFFF,
  size: 20,
  map: THREE.ImageUtils.loadTexture(
    "images/particle.png"
  ),
  blending: THREE.AdditiveBlending,
  transparent: true
});

// also update the particle system to
// sort the particles which enables
// the behaviour we want
particleSystem.sortParticles = true;

That already looks a load better. Let’s introduce a little bit of physics to the scene and get the particles moving around.

Let’s Get Physical

By default our particles don’t move in 3D space, which is totally fine. But I’d like them to, and in this case we’re going to do two things. We’re going to rotate the whole particle system around the Y-axis. Since we positioned our particles between -250 and +250 in each axis they should be spread around 0, which means the particles will look to rotate around the middle of the system.

I’m assuming you have an animation loop in place, very much like the one I discussed in the Introduction to Shaders article. So in there we have one line to add:

// animation loop
function update() {

  // add some rotation to the system
  particleSystem.rotation.y += 0.01;

  // draw
  renderer.render(scene, camera);

  // set up the next call
  requestAnimFrame(update);
}

Now we actually should animate the individual particles. Let’s go with a simple raining particles feel. This will involve doing the following:

  1. Adding a velocity vector to each particle
  2. Add acceleration due to gravity to each particle’s velocity on each frame
  3. Adding the velocity to the particle’s position each frame
  4. Resetting a particle’s position and velocity when it goes out of view

Sounds like a lot, but actually it’s not that much code. First let’s add the velocity vector to the particles. We do this when we created the particles in the loop:

// create a velocity vector
particle.velocity = new THREE.Vector3(
  0,              // x
  -Math.random(), // y: random vel
  0);             // z

Next in our animation loop we’re going to pass over each particle and update its velocity and position as well as reset it should it go off the bottom of the screen:

// animation loop
function update() {

  // add some rotation to the system
  particleSystem.rotation.y += 0.01;

  var pCount = particleCount;
  while (pCount--) {

    // get the particle
    var particle =
      particles.vertices[pCount];

    // check if we need to reset
    if (particle.position.y < -200) {
      particle.position.y = 200;
      particle.velocity.y = 0;
    }

    // update the velocity with
    // a splat of randomniz
    particle.velocity.y -= Math.random() * .1;

    // and the position
    particle.position.addSelf(
      particle.velocity);
  }

  // flag to the particle system
  // that we've changed its vertices.
  particleSystem.
    geometry.
    __dirtyVertices = true;

  // draw
  renderer.render(scene, camera);

  // set up the next call
  requestAnimFrame(update);
}

See it running

Not world beating in terms of the physics applied, but it shows you how it can be done. You should totally create an awesome physics simulation and let me know.

The caveat that needs applying here is that in the animation loop I’ve gone ahead and done a loop through all the particles, which is something of a brute force approach to handling it. If you’re doing a lot of work in your animation loop you may see a big drop in frame rate since the browser is trying to do that work at 60fps (if it’s using requestAnimationFrame) so take the time to optimise your code and do the minimum amount of work in your loop.

Conclusion

Particles are awesome. Everyone loves them, and now you know how you can add them to your Three.js WebGL project. I hope as always that you’ve found this handy!

The usual stuff applies: here’s the source code and let me know what you think

Have fun!