Particle systems are used in computer graphics for drawing fuzzy-shaped objects such as fire, clouds, and trails of dust. The basic idea for such systems is drawing a large number of small, moving particles and controlling their motion.
Here we consider the basic principles of modeling and drawing particle systems and demonstrating them by building a simple 2D particle system. In this chapter, we will cover the following topics:
By the end of this chapter, you will have a fully-featured project for experimenting with the particle system.
Objects such as clouds and fire have no distinct shape, so it is hard to draw them using polygons. The novel method for drawing such objects was proposed by William T. Reeves in his article, Particle Systems—a Technique for Modeling a Class of Fuzzy Objects (ACM Transactions on Graphics, April 1983). The idea is in using particle systems, which are controllable sets of particles—small independently moving objects, considered as elementary components of the rendered object.
Today, particle systems play an important role in 2D and 3D computer graphics as a tool for photorealistic rendering of real-world fuzzy objects. Also, they are widely used for experimental and creative coding graphics.
Particles are independent objects that move according to some rules such as gravity, force, and friction. Each particle has a number of attributes such as position, velocity, lifetime, size, and color that changes with time.
The most important property of each particle system is an interaction type between the particles. It determines the kinds of objects and behaviors, which can be represented by the particle system, and designates methods of its physical modeling.
The frequently used interaction types are as follows:
You can play with a particle system consisting of a fixed number of particles with infinite lifetime in the openFrameworks example, examples/math/particlesExample
. Use keys 1, 2, 3, and 4 for switching between several modes of the project; in these modes, particles will attract or repel from the mouse position, get attracted to some random points on the screen, or just fall like snowflakes.
Number of particles' pairs grow in a square law of particles' number. For example, if we have a particle system with 10,000 particles, there are 10,000 × 9,999 / 2 ~ 50 millions of particles' pairs. So performing direct calculations of all possible pairs' interactions is very inefficient, and methods such as geometric hashing are always used for computations' speedup.
In openFrameworks, there exists an excellent implementation of fluid mechanics in an addon, ofxMSAFluid
, by Memo Akten. You can download it from ofxaddons.com. See Appendix A, Working with Addons, for details on addons.
Particle systems are quite huge objects, so computing and rendering them can be a challenging task. In the next two subsections, we will consider various methods for doing it.
Usually, each particle in a particle system is constantly moving. Hence, before each rendering step, we need to recompute the position, velocity, size, color, and other attributes using the chosen physical modeling method. The algorithmic complexity of such recomputing linearly depends on the number of particles.
For achieving high-quality graphics, particle systems should consist of thousands and even millions of particles. So computing particles' physics is often a resource-consuming task that affects the structure of the whole project. There are several schemas of organizing such computing. They are as follows:
testApp::update()
function. This is the simplest method, which uses a single CPU's core. It lets us operate in openFrameworks with 10,000 to 40,000 particles at 60 FPS. This method is used in projects where the number of particles is in the specified range. Also, it is often used for prototyping a project.ofThread
class (see its usage in openFrameworks' example, examples/utils/threadExample
).The speedup in this case highly depends on a number of available cores and the speed of a separate core. A typical PC has 4 to 16 cores working at 2 to 3 GHz, and the Intel Xeon Phi coprocessor has 60 cores working at 1 GHz. So, in principle, it is possible to compute a million particles in real time.
Until now we have considered CPU-based methods. All other methods are GPU-based and let us operate easily with 100,000 to 1,000,000 particles (depending on the video card). Let us see these methods:
ofMesh
object and then apply the vertex shader for changing its position in time. This method is simple and works fast but is limited. It creates non-interactive particles that fly just by predefined trajectories (specified by the vertex shader). See Chapter 7, Drawing in 3D, and Chapter 8, Using Shaders, for details on the ofMesh
class and shaders.Such a method is implemented in the openFrameworks' example, examples/gl/gpuParticleSystemExample
.
Visually, a particle system is a large number of small homogeneous objects called particles, which are drawn using different color and size but have quite a simple shape. There are several ways to render a particle system on the screen:
ofCircle()
or ofTriangle()
. This way is the simplest, but works slowly, because each drawing command is sent separately in the video card. This method performs well only when the number of particles is small (from 1,000 to 10,000, depends on a video card).ofImage
or ofTexture
(see Chapter 4, Images and Textures). They represent all possible particles' shapes. We draw each particle using the image.draw( x, y, w, h )
function. This method is as slow as the previous one, but the resulting picture can be more expressive because it lets you create complex and blurred shapes. Also it is possible to use image sequences for creating animated particles such as flying moths (see the Using image sequence section in Chapter 5, Working with Videos).ofMesh
or ofVboMesh
(See details on using ofMesh
and ofVboMesh
in the Using ofMesh section in Chapter 7, Drawing in 3D). Compared to the previous methods, this method works much faster because all the drawing commands are stored in a single array and are sent to the video card at once. Using this method, you can draw 10,000 to 1,000,000 particles (depends on the video card).In this method, you need to tile all the desired particles' images in one "big" image, and then use the mesh
object for representing all the particles as quads with specified texture coordinates. Note, in this method, you need to specify four quad corners for each particle, which is a CPU-consuming task.
All the preceding methods can be used with CPU-based computing methods (single-core computing and multiple-core computing). Now we will consider the two most powerful methods that can be used successfully used with all the described methods of computing:
See openFrameworks' example, examples/gl/pointsAsTextures
, where this method is used for drawing particles with different sizes. (For changing sizes, it uses a vertex shader; see details about shaders in Chapter 8, Using Shaders).
The shader translates each particle in a quad that is rendered on the screen.
Note that a geometry shader can also draw particles not as sprites but as shapes consisting of a number of lines (for example, stars) and constantly change their shape for obtaining vivid particles. See an example of using the geometry shader in the The furry carpet example section in Chapter 8, Using Shaders.
Let's sum up all the described categories of interaction, modeling, and drawing. To make a project which draws a particle system, you need to specify its properties:
Having prepared this list, you should choose appropriate methods for physics computing and visualization:
ofCircle()
, ofTriangle()
, or image.draw()
)ofMesh
In the rest of the chapter, we will implement a simple but fully-featured particle system consisting of several thousands of particles. These particles will be independent, and we will compute them using a single CPU's core and draw them as circles.
The aim of this project is in exploring the beauty of patterns, generated by a particle system, having a circular symmetry. The style of particles' behavior and a set of control parameters is taken from our Kuflex's project, Abstract Wall (see kuflex.com for details about this project).
Let's begin with modeling and drawing just one particle.