|
Features

Animation With Cg
Particle
Systems
Sometimes,
instead of animating vertices in a mesh, you want to treat each vertex
as a small object, or particle. A collection of particles that behave
according to specific rules is known as a particle system. This example
implements a simple particle system in a vertex program. For now, focus
on how the system works; don't worry about its simplistic appearance.
At the end of this section, we will mention one easy method to enhance
your particle system's appearance. Figure 6-3 shows the particle system
example progressing in time.
The
example particle system behaves according to a simple vector kinematic
equation from physics. The equation gives the x, y, and z positions of
each particle for any time. The basic equation from which you will start
is shown in Equation 6-1:
P
final = P initial + vt +
1/2 at²
Equation 6-1. Particle Trajectory
where:
- P
final is the particle's final position,
- P
initial is the particle's initial position,
- v
is the particle's initial velocity,
- a
is the particle's acceleration, and
- t
is the time taken.
The
equation models the trajectory of a particle set in initial motion and
under the influence of gravity, but not otherwise interacting with other
particles. This equation gives the position of a particle for any value
of time, assuming that you provide its initial position, initial velocity,
and constant acceleration, such as gravity.
Initial
Conditions
The
application must supply the initial position and initial velocity of each
particle as varying parameters. These two parameter values are known as
initial conditions because they describe the particle at the beginning
of the simulation.
In
this particular simulation, the acceleration due to gravity is the same
for every particle. Therefore, gravity is a uniform parameter.
To
make the simulation more accurate, you could factor in effects such as
drag and even spin-we leave that as an exercise for you.
Vectorized
Computations
Modern
GPUs have powerful vector-processing capabilities, particularly for addition
and multiplication; they are well suited for processing vectors with up
to four components. Therefore, it is often just as efficient to work with
such vector quantities as it is to work with scalar (single-component)
quantities.
Equation
6-1 is a vector equation because the initial position, initial velocity,
constant acceleration, and computed position are all three-component vectors.
By implementing the particle system equation as a vector expression when
writing the Cg vertex program, you help the compiler translate your program
to a form that executes efficiently on your GPU.
Vectorize
your calculations whenever possible, to take full advantage of the GPU's
powerful vector-processing capabilities.
The
Particle System Parameters
Table
6-1 lists the variables used by the vertex program presented in the next
section. Each variable is a parameter to the vertex program, except for
the relative time (t) and final position (pFinal), which are calculated
inside the vertex program. Note that the y component of the acceleration
is negative-because gravity acts downward, in the negative y direction.
The constant 9.8 meters per second squared is the acceleration of gravity
on Earth. The initial position, initial velocity, and uniform acceleration
are object-space vectors.
|
|
| void
C6E2v_particle( |
float4
pInitial : POSITION,
float4 vInitial : TEXCOORD0,
float tInitial : TEXCOORD1, |
|
|
out
float4 oPosition : POSITION,
out float4 color : TEXCOORD0,
out float pointSize : PSIZE, |
|
|
uniform
float globalTime,
uniform float4 acceleration,
uniform float4x4 modelViewProj) |
{
float t = globalTime - tInitial;
| float4
pFinal =
|
pInitial
+
vInitial * t +
0.5 * acceleration * t * t; |
oPosition = mul(modelViewProj, pFinal);
color = float4(t, t, t, 1);
| pointSize
=
|
-8.0
* t * t +
8.0 * t +
0.1 * pFinal.y + 1; |
}
|
 |
 |
 |
Example 6-2. The C6E2v_particle Vertex Program
|
The
Vertex Program
Example
6-2 shows the source code for the C6E2v_particle
vertex program. This program is meant to work in conjunction with the
C2E2f_passthrough fragment
program.
Computing
the Particle Positions
In
this program, the application keeps track of a "global time"
and passes it to the vertex program as the uniform parameter globalTime.
The global time starts at zero when the application initializes and is
continuously incremented. As each particle is created, the particle's
time of creation is passed to the vertex program as the varying parameter
tInitial. To find out how long a particle has been active, you
simply have to subtract tInitial
from globalTime:
float
t = globalTime - tInitial;
Now
you can plug t into Equation 6-1 to find the particle's current position:
| float4
pFinal = |
pInitial
+
vInitial * t +
0.5 * acceleration * t * t; |
This
position is in object space, so it needs to be transformed into clip space,
as usual:
oPosition
= mul(modelViewProj, pFinal);
Computing
the Particle Color
In
this example, time controls the particle color:
color
= float4(t, t, t, 1);
This
is a simple idea, but it produces an interesting visual variation. The
color increases with time linearly. Note that colors saturate to pure
white (1, 1, 1, 1). You can try your own alternatives, such as varying
the color based on the particle's position, or varying the color based
on a combination of position and time.
Computing
the Particle Size
C6E2v_particle
uses a new vertex program output semantic called PSIZE.
When you render a point to the screen, an output parameter with this semantic
specifies the width (and height) of the point in pixels. This gives your
vertex program programmatic control of the point size used by the rasterizer.
The
point size of each particle varies as time passes. The particles start
out small, increase in size, and then gradually shrink. This variation
adds to the fireworks-like effect. As an extra touch, we added a slight
dependence on the particles' height, so that they get a little larger
on their way up. To accomplish all this, we use the following function
for the point size:
| pointSize
=
|
-8.0
* t * t +
8.0 * t +
0.1 * pFinal.y + 1; |
Figure
6-4 shows what the function looks like.
This
function is nothing special-we merely created the formula to achieve the
effect that we wanted. In other words, the formula does not have any real
physical meaning, aside from attempting to mimic the effect we had in
mind.
Dressing
Up Your Particle System
Although
the C6E2v_particle program
produces interesting particle motion, the particles themselves do not
look very appealing-they are just solid-colored squares of different sizes.
However,
you can improve the particle appearance by using point sprites.
With point sprites, the hardware takes each rendered point and, instead
of drawing it as a single vertex, draws it as a square made up of four
vertices, as shown in Figure 6-5. Point sprites are automatically assigned
texture coordinates for each corner vertex. This allows you to alter the
appearance of the particles from a square to any texture image you want.
By
rendering the points as point sprites, you can use the assigned texture
coordinates to sample a texture that supplies the shape and appearance
of each point vertex, instead of simply rendering each point vertex as
a square point. Point sprites can create the impression of added geometric
complexity without actually drawing extra triangles. Figure 6-6 shows
a more visually interesting example of a particle system, using point
sprites. Both OpenGL and Direct3D have standard interfaces for rendering
point sprites.
______________________________________________________
|