by David K. McAllister,
December 30, 2008
The home page of the Particle System API is https://particlesystems.org. Check back occasionally for new versions and other new developments.
The Particle System Application Programmer Interface (API) is a set of functions that allow C++ programs to simulate the dynamics of particles. The Particle System API is intended for special effects in interactive and non-interactive graphics applications, not for scientific simulation, although principles of Newtonian physics have been used to implement the particle dynamics where applicable.
The API consists of four sets of functions:
Following are several basic concepts central to the Particle System API.
For the purposes of the Particle System API, a particle is not just a very tiny speck. Particles can be drawn as anything - water droplets, birds, tumbleweeds, boulders, etc.. The Particle System API is generally useful for operating on many similar objects that all move and change according to the same basic rules, no matter what the objects and rules are.
A particle in the abstract sense used by the API is merely an entity with a small set of attributes such as position and color that ultimately dictate the particle's behavior and appearance. Here are the particle attributes:
Position | location of the particle center | 3 floats |
Color | color (in any color space) | 3 floats |
Velocity | velocity vector (direction and speed) | 3 floats |
Up | up vector (together with velocity vector, yields an orientation frame) | 3 floats |
Rotational Velocity | direction of rotation of the up vector | 3 floats |
Size | how large the particle is for rendering (doesn't affect particle dynamics or collision) | 3 floats |
Mass | how large the particle is for dynamics computations (doesn't affect collision location) | 1 float |
Age | time since the particle's creation | 1 float |
PositionB | initial or target position for returning to (see Restore()) | 3 floats |
UpB | initial or target orientation for returning to (see Restore()) | 3 floats |
VelocityB | can be used as velocity from last frame for computing a side vector | 3 floats |
Actions are the core of the Particle System API. They are the functions in the API that directly manipulate particles in particle groups. They perform effects such as gravity, explosions, bouncing, etc. to all particles in the current particle group. A program typically creates and initializes one or more particle groups, then during each frame it calls particle actions to animate the particles then gets the particle data and draws the group of particles onto the screen.
The Particle System API uses a discrete time approximation to all actions. See TimeStep for information on improving simulation quality by varying the time step, dt.
Action lists are blocks of actions that are applied together to a particle group. An action list is conceptually similar to a script or procedure. Action lists are implemented and expressed similarly to display lists in OpenGL. An action list encapsulates the specifics of a particular effect and allows complex effects to be treated as primitives like actions. An action list can be called from within another action list.
Action lists also allow effects to be simulated much more efficiently because the entire set of actions is known at the start, and this knowledge can be used by the implementation of the Particle System API. For example, several actions can be applied to one set of particles before moving to the next set of particles, yielding better memory access patterns. Also, in future versions common sequences of actions might be detected and replaced by efficient code that handles all those actions in one pass.
To take advantage of the up to 50% performance increase of action lists, you need to order your actions carefully. The performance advantage is achieved when two or more actions that can be combined are ordered next to each other in the list. Actions that create or delete particles (Vertex(), Source(), Sink*(), and Kill*()) and actions that reorder particles (Sort()) cannot be combined. All other actions can be combined to yield the performance advantage. See Effects.cpp for several examples of efficient ordering.
A Domain is a representation of a region of 3D space. For example, the Source action uses a domain to describe the volume in which a particle's random initial position will be. The Avoid(), Sink() and Bounce() actions use domains to describe a volume in space for particles to steer to avoid, die when they enter, or to bounce off, respectively. Domains are used as parameters to many functions within the API. See the Domains section of this documentation for more.
Many functions in the Particle System API take arguments with default values. This is a feature of C++. For example, in Color(float r, float g, float b, float alpha = 1.0f)
, the parameter alpha has a default value of 1.0. This means that Color can be called with either three parameters or four. When called with three parameters, they are the values of r, g, and b; and alpha receives the default value, 1.0. Only parameters at the end of the parameter list can have default values. Likewise, when calling functions that have default values for parameters, all values specified will be applied to parameters starting with the left. This means that there is no way to specify a value for a parameter at the end of the list without specifying values for all parameters to its left.
The following sections describe each API call, divided into the four kinds of calls. Click the link in each section to go to the Doxygen documentation for that set of API calls.
The Doxygen documentation root is here.
These calls dictate the properties of particles to be created by Source or Vertex. When particles are created within a NewActionList / EndActionList block, they will receive attributes from the state that was current when the action list was created. When in immediate mode (not creating or calling an action list), particles are created with attributes from the current state.
List of Source State Setting Calls
Actions modify the position, color, velocity, size, age, and other attributes of particles. All actions apply to the current particle group, as set by CurrentGroup. Some actions will add particles to or delete them from the particle group, and others will modify the particles in other ways. Typically, a series of actions will be applied to each particle group once (or more) per rendered frame.
Remember that the amount of effect of an action call depends on the time step size, dt, as set by TimeStep. See TimeStep for an explanation of time steps.
Some functions have parameters with a default value of P_EPS. P_EPS is a very small floating point constant that is most often used as the default value of the epsilon parameter to actions whose influence on a particle is relative to the inverse square of its distance from something. If that distance is very small, the amount of influence approaches infinity. Since all actions are computed using Euler's method, this can cause unsatisfying results in which particles are accelerated way too much. So this epsilon parameter is added to the distance before taking its inverse square, thus keeping the acceleration within reasonable limits. By varying epsilon, you specify what is reasonable. Larger epsilon make particles accelerate less.
A particle group is first created using GenParticleGroups, which will create a sequentially-numbered set of particle groups and return the identifying number of the first generated particle group. You specify which group is current using CurrentGroup. Unless otherwise stated, all other commands operate on the current particle group. The maximum number of particles in the group is specified using SetMaxParticles. The particle group is then acted upon using the Actions.
After the actions have been applied, the particles are rendered. This is done at the same stage of the application's execution as drawing other geometry. To draw a particle group in OpenGL, the application calls GetParticles or GetParticlePointer functions to get the vertex data, then sends it to OpenGL. When a particle group is no longer needed, it is deleted using DeleteParticleGroups.
These calls create and operate on action lists, which are scripts of many actions to be applied together as a block to the current particle group. An empty action list is first created using GenActionLists, and is then filled or compiled by calling NewActionList, then calling Actions, then calling EndActionList. Once the action list is filled, it is run via CallActionList. Thus, an action list is sort of a higher-level action. Complex behaviors can be stored in an action list and then called later, even as part of another action list. Action lists cannot be edited. They can only be created or destroyed. To destroy an action list, call DeleteActionLists. When particles are created within a NewActionList / EndActionList block, they will receive attributes from the state that was current when the action list was created.
When in immediate mode (not creating or calling an action list), particles are created with attributes from the current state. However, the time step length, dt, uses the value that is current when CallActionList is executed, not the value of dt when the action list was created. This allows dt to be modified without recompiling action lists. Maybe this isn't a good idea. If it should be the other way in the future, let me know.
Click here for my To Do list. Feel free to do anything on it.
Click here for my change log.
Click here to visit the Particle System API home page.