Particle Systems
CS 481/681 2007 Lecture, Dr. Lawlor
Mechanics
So. Sir Issac Newton. Specifically, mechanics:
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.
Physics for Particle Systems
The simplest place to apply Newton's laws is on "particles"--little
dots or points floating in space. Each particle has at least a
position (P), but also optionally a color, a velocity (V), a size,
etc. The easiest way to draw particles is something silly like:
glBegin(GL_POINTS);
for (unsigned int i=0;i<particles.size();i++) {
glColor4fv(particles[i].color);
glVertex3fv(particles[i].P);
}
glEnd();
So fill up the array of particles. Draw them every frame. This is easy, but they're just floating in space.
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!
Note: we are faking it
here somewhat. For a nonzero timestep, the velocity will change
over the timestep, so our resulting P's are not exact, especially if V
changes quickly. If accuracy is important, you can use the
second-order formula "P+=dt*V + 0.5*(dt*dt)*A;" or even something fancy
like a Verlet integrator.
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);
if (dist<0) {
P-=dist*N; /* move P to the plane surface */
V=elasticity*reflect(V,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.
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.
Once your particles fall offscreen (or just get wedged in one place for
too long), it's a good idea to stop drawing them. You can
actually reincarnate the particle at some source (a "fountain" of
particles), or
Easy ways to Screw Up Physics
People spend their entire lives watching these laws in action, and
they're amazingly good at detecting violations of them--and many games
and animations "just don't look right" because the designers thought
they could cut corners, or "just fake it".
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.
Luckily, the real laws of physics are strikingly easy to get right if you aren't
trying to "make this cool thing happen" (that is, script the outcome of
the motion). If you just follow Newton's laws and let the coolness
emerge, it's really easy.
Cool ways to Render Points