IntroductionFire, fountains, explosions, even stars. All these special effects can be implemented as particle systems. Yet they operate differently, and at times make you even wonder if they can even be the same code. This difference is the result of an extensible particle system, with which a simple change of parameters can just bring you an entire new visual. This article will bring to your attention some decisions you have to make while designing your own particle system, as well as introduce to you an extensible, possibly robust design. This article requires some basic knowledge of C++ Templates, as well as knowledge of the Policy/Containment/Aggregation pattern. Particle PropertiesBefore we delve into the actual particle system design, let's begin with the building block of all particle systems. The particle itself. A particle implementation could have the following properties:
Velocity of the particle, to determine its movement along the timeline. Lifespan of the particle, to determine how long a particle is visible, or dies out. Size of the particle (optional), to determine how big the particle is. Color of the particle (optional), to determine the color of a particle. Other optional properties would be acceleration of each individual particle, color step of each particle (changes in color along each step of time line), size step (same as color step), and possibility some angles for rotation as well. For the purpose of this article, we will design a particle structure with the basic properties, struct Particle { Point3D d_ptPos; Vector3D d_vVelocity; Color d_cColor; Size3D d_szSize; int d_nLife; }; where Point3D, Vector3D, Color and Size3D can be substituted with your favorite 3D Geometry library structures, as well as int for life to float. Inheritance or Parameterization?Now that we have the basic particle defined, we have to make decisions to allow for an extensible system. The system should be able to operate on the default particle structure, yet allowing you at the same time to support additional properties. There are a few approaches. One approach would be via inheritance of the particle structure (providing virtual functions like Init and Process for each particle. This approach, however, is costly, as each process and initialize of particle is via a virtual table lookup, and would amount to a huge, unnecessary overhead with the many particles. Another approach would be to subclass the particle system, or provide composition/aggregation. This approach is slightly better, except there still is a function call involved (for composition at least. You could argue you inline the function calls for the parent particle system's Init and Process, and always work with the derived class) Another approach would be via templates My preferred approach, though, is via templates, with particle as a template parameter. Most of the time, you already know what behavior each particle system need to exhibit before run-time. However, templates would run into issues like additional features/actions to act on each particle, which can be easily solved with the above two approach, with the extra overhead cost. This article will, however, teach you how to use a template approach, yet able to resolve those two issues, using the Policy concept [Modern C++ Design, Chapter 1]. A policy, as its name suggests, describes a set of rules and workings pertaining to a specific issue. It's a design pattern, and as such, could be used as a composition pattern, but its true power shine in templates usage. For more on policy pattern, I would recommend getting Modern C++ Design, by Andrei Alexandrescu. So let's start building the template particle system! |
|