Damping with delta-time
Just a quick tip on how to convert usual damping code to something framerate-independent.
Most of us have probably, at some point, written code resembling this:
// Perform velocity damping velocity -= velocity * 0.01f;
… or probably the more correct:
// Per-second damping coefficient float const D = 10.0f; // Damp velocity according to timestep velocity -= velocity * D * delta_time;
Yet this is not fully framerate-independent; results are slightly different at 30fps and 60fps, and more importantly, spikes in the framerate cause lots of weird artifacts, causing developers to attempt to fix the situation by clamping delta_time
, which is not ideal.
The exponentiation method
Here is one way to fix it: assume that the code works correctly at 60 fps. This means that each frame, velocity
is effectively multiplied by 1 - D / 60
.
After one second, i.e. 60 frames, velocity
has been multiplied by (1 - D / 60) ^ 60
.
After two seconds, it has been multiplied by (1 - D / 60) ^ (60 * 2)
.
After N
seconds, it has been multiplied by (1 - D / 60) ^ (60 * N)
.
So, there, we have a formula that tells us what happens after N
seconds, and it’s a continuous function. We can therefore choose N
as we like, and especially N = delta_time
:
// Per-second damping coefficient float const D = 10.0f; // Damp velocity (framerate-independent) velocity *= pow(1.f - D / 60.f, 60.f * delta_time);
Which can be conveniently rewritten as:
// Per-second damping coefficient float const D = 10.0f; // Exponentiation base for velocity damping float const D2 = pow(1.f - D / 60.f, 60.f); // Damp velocity (framerate-independent) velocity *= pow(D2, delta_time);
Use with lerp
The same method can be adapted to uses of linear interpolation such as this one:
// Perform velocity damping velocity = lerp(velocity, target_velocity, K * delta_time);
Which we replace with:
// Damp velocity (framerate-independent) velocity = lerp(velocity, target_velocity, 1.f - pow(1.f - K / 60.f, 60.f * delta_time));