Frame rate independent air friction

Started by
4 comments, last by uttumuttu 16 years, 2 months ago
I've been playing around with this for a while now. I've searched on the forum for old similar threads, but I couldn't find one that explains what I want. I want to slow an object down each frame by a certain fraction of the speed it's currently moving. My object velocity doesn't yet have time multiplied into it. Time passage can fluctuate from frame to frame. 5 milliseconds can pass in one frame, then 10 in the next, then 33 in the next, then 5 in the next. There are even slow motion time bubbles caused by gameplay events that can cause time to scale down to 10%. My engine has done well to cope with it up to this point, but inaccurate frame-base friction can really screw things up over a long period of time. Here's the best I've come up with so far:
speed *= expf( -time_laps * friction * speed );
speed is the length of the velocity without time. time_laps is the number of milliseconds that has passed since the last frame. friction is specified by the object and doesn't change dynamically. I appreciate any help. All that I ask is to please use english variable names for equations, rather than single characters. I'm strictly a programmer, and not fluent in the general variables used.
Advertisement
There are two commonly used models for air resistance which you may find useful, so I'll cover them both. The first model is most accurate for objects with a low velocity and the second for objects with a high velocity.

For the first model we assume that the force is proportional to the velocity of the object so:

   force = -friction * velocity where friction is the proportionality constant=> mass * acceleration = -friction * velocity=> acceleration = -friction / mass * velocity   let k = -friction / mass=> acceleration = k * velocity=> d^2/dt^2(position) = k * d/dt(position)   Integrate both sides wrt t (time)=> d/dt(position) = k * position + c0   Use separation of variables to solve the resulting first order ODE=> 1 / (k * position + c0) d/dt(position) = 1=> int(1 / (k * position + c0), position) = int(1, t)=> 1/k ln(k * position + c0) = t + c1=> ln(k * position + c0) = k * t + k * c1=> k * position + c0 = exp(k * t + k * c1)=> position = exp(k * t + k * c1) / k - c0 / k   Now apply initial conditions position(0) = init_position, position'(0) = init_velocity=>  init_velocity = k * init_position + c0=>  c0 = init_velocity - k * init_positionand ln(k * init_position + c0) = k * c1=>  c1 = ln(k * init_position + c0) / k       = ln(init_velocity) / k   Substitute for c0, c1=> position = exp(k * t + k * ln(init_velocity) / k) / k - (init_velocity - k * init_position) / k            = init_velocity * exp(k * t) / k - init_velocity / k + init_position 

If you only use the derivative of this to calculate the velocity and then combine that with other things and calculate the new position from that velocity then some error will be introduced over large time steps although it shouldn't be a problem in practice so I'll leave it to you to figure out exactly what you want to do with the above result.

The second model which is more suited for large velocities assumes that the force is proportional to the square of the velocity.

   force = -friction * velocity^2=> mass * acceleration = -friction * velocity^2=> acceleration = -friction / mass * velocity^2   let k = -friction / mass=> acceleration = k * velocity^2=> d/dt(velocity) = k * velocity^2   Which is first order separable so   1 / velocity^2 * d/dt(velocity) = k=> int(1 / velocity^2, velocity) = int(k, t)=> -1 / velocity = k * t + c0=> velocity = -1 / (k * t + c0)=> d/dt(position) = -1 / (k * t + c0)=> position = -1 / k * ln|k * t + c0| + c1   Initial conditions position(0) = init_position, position'(0) = init_velocity=>  init_velocity = -1 / c0=>  c0 = -1 / init_velocityand init_position = -1 / k * ln|c0| + c1=>  c1 = init_position + ln| -1 / init_velocity | / k       = init_position - ln(init_velocity) / k=>  position = -ln|k * t - 1 / init_velocity| / k - ln(init_velocity) / k + init_position


The same comments as for the previous model apply here, you could also consider a combination of the two, for example force = friction0 * velocity ^2 - friction1 * velocity but things start to get a little more complicated if you do that. Alternatively you could just use something with no physical basis as long as it looks good. Hope that helps.
It might help you to read my replies to This thread. In my second post, about adding gravity, replace the vector for gravity with the vector directly opposite the direction vector, or use my suggestion for factoring in multiple forces.
Don't thank me, thank the moon's gravitation pull! Post in My Journal and help me to not procrastinate!
What's wrong with:

velocity -= velocity * constant * slomo * physics rate;

;)
Quote:Original post by jezham
What's wrong with:

velocity -= velocity * constant * slomo * physics rate;

;)


Because applying it twice to two updates with timestep dt isn't the same as applying it once to a single update of 2*dt.

Kest: yes your original formula works (after correcting the lapse typo!) because when you've applied it twice:

speed = speed * expf( -time_lapse * friction * speed ) * expf( -time_lapse * friction * speed )

multiplying exponential terms reduces to just summing the exponents:

speed = speed * expf( -time_lapse * friction * speed * 2)

and that's the same as one update of 2*time_lapse.
It's also possible to combine the linear and the quadratic air friction models, so that

dv/dt = -C_1*v^2 - C_2*v

Where C_1 and C_2 are non-negative
constants. I haven't verified the solution,
but I got something like

new_v = [C_2 * C_3 * exp(- C_2 * timestep)] / [1 - C_1 * C_3 * exp(- C_2 * timestep)],

where

C_3 = old_v / [C_2 + C_1 * old_v]

This topic is closed to new replies.

Advertisement