Course Links

Resources

External

The goal of this lab is to get you working with a simple particle system in WebGL via Three.js. Our particules will be handled by the CPU rather than the GPU, which simplifies things because we will not have to write any custom shaders. Otherwise they behave in similar ways.

Getting Started

To begin with, fork a copy of the starter code. This is structured much like our other Three.js programs, with an empty scene, camera, and lighting. It's just waiting to have content added to it.

Your first step is to create a set of particles to work with. They won't look like much at first, and they won't move. But it's a start! Add the following code to the base file inside createWorld. You can alter the color and the number of particles if you want, to see what kind of difference it makes..

        // create the particle variables
        var particleCount = 1800,
            pgeo = new THREE.Geometry(),
            pmat = new THREE.PointsMaterial({
            color: 'yellow',
            size: 10
            });

        // 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.Vector3(pX, pY, pZ);
            // add it to the geometry
            pgeo.vertices.push(particle);
        }

        // create the particle system
        particles = new THREE.Points(pgeo,pmat);

        // add it to the scene
        scene.add(particles);

The end result should look something like this:

program visualization

If you modify the render function to rotate the particle cloud slowly around the y axis, you will see that these square points are distributed in space.

Adding Motion

While a bunch of square particles hanging in space is something, it would be much nicer if they could move around. This means updating the position vector for each of the particles. You can do this in a loop within the render function.

        for (var p = 0; p < 1800; p++) {
            particles.geometry.vertices[p].x += Math.random()-0.5;
            particles.geometry.vertices[p].y += Math.random()-0.5;
            particles.geometry.vertices[p].z += Math.random()-0.5;
        }

Right after this loop, we should also tell the renderer that we made some changes.

        particles.geometry.verticesNeedUpdate = true;

If all went well, we should now have some motion! It's a bit jittery, to be sure -- your particles are demonstrating Brownian motion, like the molecules in a room full of air as they are buffeted by their neighbors..

It would be nice to make the particles behave a little more smoothly. We can do this by diving them a persistent velocity. If we add random adjustments to the velocity rather than the position, we'll get the effect we want. You can do this by making a vector of velocity vectors, one for each particle, and then changing render as described. You'll probably want the size of the velocity and its randomness to be much smaller than that of the position -- remember that the velocity is added to the particle 30 times a second! Values around 1/30 the size of the position numbers should do the trick. Adding velocity is an optional change -- only do it if you have time. The Brownian motion will suffice for the rest of the lab, and there are a few toher things we want to get to.

If you let your particles run for a while, you will notice that they eventually thin out and disappear. Like air molecules, particles under Brownian motion are subject to diffusion. Given enough time, they will all wander out of the camera frame. It would be better if we contained them within a finite volume. The easiest way to do this is to set up boundaries as a giant cube from -250 to +250 in each dimension. If a particle wanders out one face of the cube, it is moved so that it enters at the opposite face. This can be managed with a single line per position coordinate:

particles.geometry.vertices[p].x = (particles.geometry.vertices[p].x+750)%500-250;

Once you have done that, it is safe to add some systematic motion to one or more of the components. For example, if you add a small number to the z component each time, you will get a "hyperspace" effect. On the other hand, if you subtract a litle bit you will get something like falling snow.

Textured Particles

Everything we have done so far is all very well, but despite all the motions we're going to be limited in the effects we can create if our particles always look like little squares. The solution is to apply a texture to each point. Instead of a square, the renderer will paint a tiny image at each location. Typical particle textures use transparency to diffuse their boundaries, so that individual particles can merge together seamlessly.

Note that once we do this, the usual restrictions on texture images will apply -- it will work on repl.it but you won't be able to view the result from a local file. (Review the configuration notes if necessary.)

We'll use a small smoke particle for our texture: a puff of smoke Download a copy of the image by right-clicking on it. Then upload it to your repl, and add a line in the script to load the texture as you would for any other.

The next step is to make some changes to the texture's material (assuming particleTexture is the name of the variable holding the loaded texture):

pmat = new THREE.PointsMaterial({ map: particleTexture, color: 0xffffff, alphaMap: particleTexture, transparent: true, size: 5, depthWrite: false, blending: THREE.AdditiveBlending });

Notice that we have used the same image as both the main texture and the alpha (transparency) map. This is appropriate for fog, smoke, etc. but won't always be the case. The last two parameters control the mixing when two point textures happen to overlap -- if you have time, you might try removing them to see what happens.

Assuming all went well, your squares should now have been replaced by little white puffs. If you don't see anything, make sure that the texture image is in your project folder, and that you loaded it properly. Now you can play with your particles. What effects can you dream up?

Variations

With small variations to the basic file of this lab, you should be able to achieve any of the following effects. You are not required to do all of these -- see how many you can explore if you have the time!

Finish Up

You do not have to turn this lab in, but make sure that everyone in your group has a copy by the end of the lab. You may wish to use particle effects in your game.