Skip to main content
GameDev.net gamedev.net
🔒 Locked

Closed Form Air Resistance Approximation

Started by Tubos Jan 31, 2010 at 2:43 PM 9 replies 2.9k views
Original Post
Tubos
Tubos
Hi! I'm simulating particles with air resistance and gravity on the GPU. Since the particles move fast, air drag slows them down. This force is proportional to velocity^2. The start velocities are random. The simulation must calculate the position at time t using only position&velocity at t=0. But the differential equation for that has no closed-form solution. How would you approximate the particle motion? It just has to look right, physical realism is not necessary.
alvaro
alvaro
You need to update your simulation's state every certain time increment (say, 10ms), and use an integrator to compute the update. Euler integration is the easiest to understand, and probably the first one you should implement. Verlet and Runge-Kutta give you a lot more precision for a given time step. You may also consider an implicit method if things get out of control (unlikely in the scenario you describe). Chances are any of these methods will make the simulation look good enough.
Tubos
Tubos
I'd like to do the simulation inside a vertex shader on the graphics card.
That means I cannot update position/velocity and have to calculate everything using only the start values.

Of course, the simulation could be done on the CPU. But this would probably hurt performance!
That's why I'm looking for a good approximation formula without numerical integration.
momotte
momotte
you can store particle states (position/velocity/...) inside a texture, and update that texture each timestep to compute the new states.

however, being able to analytically evaluate the particle states at a give time in the life of your particle system allows for all sorts of interesting stuff, like instant-seeking into the particle effect, which allows immediate switching of particle LOD-levels, without needing to simulate everything again from the beginning, or to load a level with your particle systems in a specific state, by saving the time at which they should be when your level starts ("particle system no 46 in the level should start at 12 seconds along its lifeline at level start")

have you tried using exponentials? if you want frametime-independent fluid friction, you'll need them anyway.
for incremental updates, you'd do something like:

velocity *= exp(-friction * mass * dt);

you can try:

f = friction * mass
position = startPosition + startVelocity * (1 - exp(-f * t)) / f

?
Steve132
Steve132
I am confused...I was under the impression that the differential equation for air resistance WAS solvable in closed form..

Force = mass * acceleration
acceleration = dv/dt

F(t) = m dv/dt

the force is equal to some constant acceleration + the air resistance, which is a force proportional to v(t)

m*a(t) = constant_acceleration*m + k*v(t)
m*dv/dt = m*g+k*v

This is a simple linear first order diff. eq., which DOES have a solution. Particularly,

http://www.wolframalpha.com/input/?i=m*dv%2Fdt+%3D+m*g%2Bk*v
Emergent
Emergent
Quote:
Original post by Steve132
I am confused...I was under the impression that the differential equation for air resistance WAS solvable in closed form..


Yes when the resistance is linear in the velocity, no when it goes with the square (though IIRC I may have seen a closed for expression for this second case in two dimensions, in "Classical Mechanics" by Taylor... will check later...)
Tubos
Tubos
Quote:
however, being able to analytically evaluate the particle states at a give time in the life of your particle system allows for all sorts of interesting stuff
Exactly. Plus, I'd like a simple solution and not bother with stateful particle systems on the GPU :-)

Quote:
(though IIRC I may have seen a closed for expression for this second case in two dimensions, in "Classical Mechanics" by Taylor... will check later...)
Thanks! But my simulation runs in 3D.

The Exp-Formula is okay. startVelocity * (1 - 4^(-t*0.5)) is also good.
But both formulas have the problem that the particles stop after a few seconds.

startVelocity * sqrt(time) works surprisingly well, but has another problem: The velocity distribution doesn't look right when comparing fast-moving and slow-moving particles. I'll try startVelocity*sqrt(time*k), where k depends on the initial velocity.

Quote:
Yes when the resistance is linear in the velocity, no when it goes with the square
Exactly. That seems to be the problem with the exp-formula like (1-exp(-t)): it's a solution to the linear resistance diff.eq. But since the particles are fast-moving, linear air resistance doesn't look right.


Maybe there's an even better solution than powers or square roots?
PDP-1
PDP-1
If I understand your problem right, you have a differential equation with and acceleration force m*a and a drag force k*v*v, where the constant k here is some kind of cross-sectional area. The sum of the forces is zero, so we get:

(1) m*a + k*v*v = 0

Then from physics we know that v=x' and a=x" where the primes represent derivatives with respect to time.

(2) m*x" + k*x'*x' = 0

Expand the derivatives using these numerical approximations:

(3) x" = (xp - 2*x0 + xn)/(dt*dt)

(4) x'=(x0 - xn)/dt

Where x0 is the current position, xn is the position one frame ago, and xp is the position you are going to be in the next frame. The time step between frames is dt. Inserting equations (3) and (4) into (2) gives:

(5) a*(xp - 2*x0 + xn)/(dt*dt) + k*(x0 - xn)*(x0 - xn)/(dt*dt) = 0

Solve this for xp to get an update equation:

(6) xp = 2*x0 -xn - (k/m)*(x0-xn)*(x0-xn)

At the start of the simulation we only know the starting position X(0) and starting velocity V(0), so we use that to set things up as:

(7) x0=X(0)

(8) xn=X(0)-V(0)*dt

and then apply equation (6) each frame to find the new position of the object for each update. You should be able to make similar equations for the Y and Z axis components.

Does that work?

edit: fixed a sign error

[Edited by - PDP-1 on February 1, 2010 2:18:33 PM]
Tubos
Tubos
Thanks for your detailed response!
Unfortunately, I cannot store the position one frame ago because the particle system runs on the GPU. The simulation has to work using only start velocity and start position.

I'm currently experimenting with some sort of
position = startPosition + startVelocity * sqrt(time / length(startVelocity))
but the results are not very good.

I'll appreciate any other ideas for approximation formulas.
Helicobster
Helicobster
Quote:
Original post by Tubos
Unfortunately, I cannot store the position one frame ago because the particle system runs on the GPU.


Have you considered solving some particles on the CPU (Euler or Verlet for simplicity) just for reference?


If you have a few 'stateful' CPU particles on screen along with your GPU particles, you'll see what your stateless particles should be doing. Then when you've hit upon the right exponents etc. for your stateless particles, you'll see them doing almost exactly the same thing as your CPU particles, and you can ditch the CPU particles.

Or you may just find that stated CPU particles aren't really the performance hit you're worried about, and that they're far more flexible. It's win/win.
Tubos
Tubos
Helicobster, that's an excellent idea!

I'll try that!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.