Sign in to follow this  
Kest

Frame rate independent air friction

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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_position
and 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_velocity
and 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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this