Archive: Frame-rate independent decays


3rd December 2003 06:56 UTC

Frame-rate independent decays
Just a tip that's useful for making framerate independent decays plus the derivation for the interested ones.

Most people know the standard decay formula for making a var move exponentially towards a different value:

var=var*.9 + target*.1;

Let's write it as:

var=target + (var - target)*.9;
(exactly the same, verify this if it isn't obvious)

Now consider two successive frames:

var=target + (var - target)*.9;
var=target + (var - target)*.9;

If we replace 'var' in the right-hand first expression by the second expression, we get:

var=target + (target + (var - target)*.9 - target)*.9;

which simplifies to:

var = target + (var - target)*.81

The relation between one round and two rounds is easy to see. The decay factor 0.9 has been squared to 0.9*0.9 = 0.81.

Now suppose a preset is perfect at 30fps with a decay factor of 0.9. We want it to be frame-rate independent. This means that at 15fps, it should do two successive decays, which for a factor of 0.9 means 0.81 as we have seen above. So dividing the framerate by two results in taking the decay factor to a the 2nd power.

Now what about any other framerate? We can conclude that the ratio of the reference framerate versus the current framerate becomes the exponent of the decay coefficient.

If you don't understand this, work out the above scheme for 3 rounds, and you'll get 0.9*0.9*0.9 = (0.9)^3 = 0.729.
You can also derive 'half' a round by splitting one round into two identical ones with a new decay constant, and solving the resulting equation (note, do not confuse the assignment operator with the equation = sign). You would end up with a decay factor of sqrt(0.9), or approx 0.949.

Now all we need is to get the current framerate... gettime(0) returns time in seconds, though with millisecond accuracy. The difference between two successive gettime(0) values is the time it took to render a frame (seconds per frame), so the inverse of that value is the framerate (frames per second).

This is all summarized in the following code:

time = gettime(0);
decay = pow(0.9, 30 * (time - lasttime));
var=target + (var - target)*decay;
lasttime = time;

Hope this was useful ;).


3rd December 2003 10:13 UTC

That was interesting. I've already used linear decay change in the single player pong, but that doesn't work well. I'll update that preset and other presets as well.


3rd December 2003 10:17 UTC

:eek: . Wow, now that's what I call simple and effective. Good job :D


3rd December 2003 13:50 UTC

wery nice thx


7th December 2003 12:47 UTC

Of course, the question is how to implement it. ;)

OT: I just noticed the big red search text is gone. Guess someone realised it was fighting a losing battle.


7th December 2003 14:47 UTC

(the red text only appears when posting a new topic)