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 ;).