F = m * A

A = dV/dt

V = dP/dt

- F- net force acting on a body. Vector quanity, in the usual force units like Newtons (or cursed pounds).
Force is quite useful when bodies interact (like with collisions),
because all interactions produce equal and opposite forces--if you push
on me with force F, I push on you with force -F (negative F) (Newton's Third Law).

- m- mass of the body. Usually just a constant.

- A- "acceleration" of a body. Also a vector. Units are
bizarre--m/(s*s) ("meters per second squared"). For gravity,
whose force is proportional to mass, the gravitation acceleration is
then a constant, so if you only care about gravity, it's common to skip
over force andjust start with the fixed gravitational acceleration.

- V- velocity of a body. Yet another vector. Units are m/s.
- P- position of the body, like you'd pass to glVertex3f. Also a vector, measured in meters.
- t- simulation or animation time, in seconds.

glBegin(GL_POINTS);So fill up the array of particles. Draw them every frame. This is easy, but they're just floating in space.

for (unsigned int i=0;i<particles.size();i++) {

glColor4fv(particles[i].color);

glVertex3fv(particles[i].P);

}

glEnd();

Now you just need to move the particles--just change their positions. This is actually quite easy, and comes straight from the definitions above:

- Pick a "timestep"--a small interval of time to simulate. In the differentials above, this is "dt".
- V = change in P / change in time. Change in time==dt. So solving for P, dt*V==change in P. Thus we just run

P+=dt*V;

This alone will give you particles travelling in straight lines (Newton's First Law).

- Compute the net force on the particle (see below). Now F=m*A, so A=F/m (or for gravity, A=constant).
- A = change in V / change in time. So solve for V, dt*A==change in V. Thus we run

V+=dt*A;

This will allow the particles to respond to arbitrary forces, yet still have inertia. It looks darn good, and it's easy!

One place where virtually all normal integrations fail is for short-duration sharp impacts. The problem is that the force changes extremely rapidly, changing the velocity in a jump. Of course, we can fake this pretty easily for coordinate-aligned reflection planes:

if (P.x<0) {P.x=0; V.x=-elasticity*V.x;}Or for an arbitrary plane with outward-facing normal N and on-plane point O:

float dist=dot(P,N)-dot(O,N);Elasticity controls how elastic the collision is--how much velocity is retained after the bounce. elasticity==0.0 means particles do not bounce, like blobs of clay (or organs). elasticity==1.0 means particles rebound with exactly as much velocity as they started with.

if (dist<0) {

P-=dist*N; /* move P to the plane surface */

V=elasticity*reflect(V,N);

}

But usually computing the net force is easy--just sum up all the forces. Forces can be as interesting as you like:

- Drag: force is directed backwards, with magnitude proportional to the square of the velocity, such as

F=-stickiness*area*V*length(V); (so length(F) == length(V)^{2}). - Drift: force is directed in a random direction with fixed magnitude.
- Magnetic, electrostatic, gravitational, etc. All you need is an equation. And people are pretty forgiving about not-quite-right (or totally fictitious) forces, as long as their magnitudes are reasonable.

For example:

- Motion. Nothing looks weirder than an object's position
spontaneously changing--like an object warping from place to
place. A *huge* number of character animation systems are
"jumpy"; the character just warps from an animation in one orientation
to another.

- Time. Note that this really should be proportional to actual elapsed time, not something bogus like "frame count". Frame times can vary dramatically between your machine and mine. *Most* games from the 386 era are unplayable today because the designers basically assumed the system could only draw a reasonable number of frames per second, like 30, but a Core2 gets 30,000 fps, so the animations and game logic run 1000x too fast! Making simulation time a function of actual time is better than just limiting the framerate, because it lets a 100Hz-monitor guy actually see 100fps.

- Use GL_LINES, and connect up the point's *old* location with its *new* location. This gives nice motion blur to the points, and works well with a Verlet integrator.
- glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); and write to "gl_PointSize" in your GLSL code. Then compute the point size (diameter, in pixels) based on the distance from the camera. Voila--perspective-correct points!
- gl_PointSize=pixels_per_radian*point_diameter/distance(camera,pointcenter);

- Switch to alpha blending to simulate less-than-one-pixel point sizes (important for faraway points).
- Turn on "point sprites" and texture the points. You'll
magically get a gl_TexCoord[0] in your fragment program that varies
from 0-1 across the point's surface. This works really nicely
with a central-bump "splat" texture (see example code!).

glEnable(GL_POINT_SPRITE_ARB);

glTexEnvi(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE_ARB,GL_TRUE);