#include <pAPI.h>
List of all members.
Public Member Functions |
|
void | Seed (const unsigned int seed) |
Set the random number seed. |
|
void | TimeStep (const float new_dt) |
Specify the time step length. |
|
void | CallActionList (const int action_list_num) |
Execute the specified action list on the current particle group. |
|
void | DeleteActionLists (const int action_list_num, const int action_list_count=1) |
Delete one or more consecutive action lists. |
|
void | EndActionList () |
End the creation of a new action list. |
|
int | GenActionLists (const int action_list_count=1) |
Generate a block of empty action lists. |
|
void | NewActionList (const int action_list_num) |
Begin the creation of the specified action list. |
|
Protected Member Functions |
|
void | InternalSetup (PInternalState_t *Sr) |
PInternalState_t * | getInternalState () const |
Protected Attributes |
|
PInternalState_t * | PS |
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 in immediate mode (not creating or calling an action list), particles are created with attributes from the current state. However, 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 (unlike OpenGL).
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.
void CallActionList | ( | const int | action_list_num | ) |
Execute the specified action list on the current particle group.
Call the action functions as specified when this action list was created with NewActionList(). The actions are executed with the state values in effect when the action list was created, except the context's current value of dt is used, not the value of dt when the list was created.
CallActionList() is the only function other than actions that can be stored in an action list. This allows action lists to become atomic operations in more complex action lists. When calling CallActionList() during the creation of a new action list, action_list_num does not need to indicate an existing action list.
It is an error for action_list_num to not indicate an existing (generated) action list.
void DeleteActionLists | ( | const int | action_list_num, | |
const int |
action_list_count = 1
|
|||
) |
Delete one or more consecutive action lists.
Deletes action_list_count action lists, with action_list_num being the list number of the first one. The lists must be numbered sequentially, and must all exist. This removes the specified action lists from existence.
action_list_num | The handle of the first action list to delete | |
action_list_count | How many action lists to delete |
void EndActionList | ( | ) |
End the creation of a new action list.
Obviously, it is an error to call EndActionList() without a corresponding call to NewActionList().
int GenActionLists | ( | const int |
action_list_count = 1
|
) |
Generate a block of empty action lists.
Returns the action list number of the first allocated list. All list numbers are in sequential order starting with the first list. Valid action list numbers are non-negative.
action_list_count | How many action lists to create |
void NewActionList | ( | const int | action_list_num | ) |
Begin the creation of the specified action list.
The action_list_num must have already been generated using GenActionLists. Most calls other than actions and state setting calls cannot be made between a call to NewActionList() and the corresponding call to EndActionList(). If called on an action list that has previously been defined, the previous contents of the action list are destroyed and the action list will be created anew. This is as with glNewActionList() in OpenGL.
void Seed | ( | const unsigned int | seed | ) |
Set the random number seed.
The Particle API uses a pseudo-random number generator. The returned number is a function of the numbers already returned. If you start two threads, each with a ParticleContext_t they will both generate the same particles if given the same commands. If this is not desired, call Seed() on both of them with different seed values. The API currently uses the C standard library random number generator, whose state is per-thread, so all contexts in the thread share the same random number seed.
void TimeStep | ( | const float | new_dt | ) |
Specify the time step length.
The Particle System API uses a discrete time approximation to all actions. This means that actions are applied to the particles at a particular instant in time as if the action's effect accumulated over a small time interval, dt, with the world being constant over the interval. The clock is then "ticked" by the length of the interval and the actions can then be reapplied with the particles having their updated values. This is the standard method of doing almost all time-varying simulations in computer science.
How does the time step, dt, relate to the application's frame rate? The easiest method is to apply the actions once per frame. If the application prefers to keep time in terms of seconds, dt can be set to (1 / frames_per_second). But more often, it is easier for a time unit to be one frame instead of one second. In this case, dt should be 1.0, which is the default.
For higher quality, the application can apply particle actions more than once per frame. This provides smoother, more realistic results in many subtle ways. Suppose the application wanted to compute three animation steps for each rendered frame. Set dt to 1/3 its previous value using TimeStep(), then loop three times over all the action code that gets executed per frame, including the calls to Move. If using action lists, this can be simply a loop over the CallActionList() call. The run-time results should be about the same, but with fewer discrete approximation artifacts. Depending on how much non-particle work is done per frame, increasing the number of time steps per frame may or may not affect the frame rate very much.
In terms of numerical integration, particle actions can be thought of as the first derivative of unknown functions dictating the particle attributes (such as position) over time. In order to compute the particle attributes these derivative functions must be integrated. Since closed form integration doesn't make sense for most actions, Euler's method is used instead. Euler's method is simply the method just described � the evaluation of the derivative functions at a particular time and then incrementing the current particle values by these derivative results times dt. In Euler's method, the smaller the dt, the more accurate the results.
Unlike with other state setting calls, action lists execute using the current dt value set by TimeStep(), rather than the time step value that was current when the action list was created. Making action lists independent of time step size allows the time step to be changed without recompiling the action list.
In general, it is folly to call TimeStep() in between other actions of a simulation frame. For example, calling Bounce(); TimeStep(); Move(); can cause cause particles to pass through the bounce domain instead of bouncing off it.