I've stumbled on a problem these days while programming a small simulation. I've read a few articles with a main title of: "Fix you're time step" and concluded on the following loop:
0. numTotalUpdates = 0;
1. fixedDt = 1.0f / 400.0f; // how small is enough?
2. while (IsRunning())
{ 3. DispatchEvents();
4. static float accumulator = 0.0f;
5. numUpdatesThisFrame = 0;
6. accumulator += GetFrameTime() ; // time since last update
7. while (accumulator >= fixedDt)
{
8. UpdateSimulation(fixedDt);
9. accumulator -= accumulator;
10. numUpdatesThisFrame ++;
} 11. numTotalUpdates++;
12. renderInterpolator = accumulator / fixedDt; // safe to say it's in 0..1
13. Render(renderInterpolator);
}
As far as i know this is physics engine friendly main loop because physics engine deal great with small fixed time steps when approximating integration.
As i was saying i was running a simple simulation of a circle that was hitting obstacles and was being reflected as expected. Actually there was more going on, on the screen, but the main idea of the simulation is of a circle in a 2D environment colliding in a breakout game fashion.
I repeatedly run the simulation with VSync on and observed an annoying stuttering/choppy movement of the circle. The stuttering is almost random like. After some profiling i found out that numUpdatesThisFrame was varying kind of weird: it was growing from 6,7 to 15 or even 24. I changed this line to this line
6'. accumulator = some_constant;
and the ran the simulation again with VSync on. The stuttering was gone and since the value of some_constant was tweaked for my processor speed the motion was neither to slow and neither two fast.
So something was happening that caused big times between frames which implied an unnaturally big numUpdatesThisFrame value. The framerate was very high though, without VSync on i was getting a few thousands frames per second so i thought to myself that bothering with why does sometime the time beween frames was unnaturally big, was not the way to solve the problem.
I thought the way to tackle this issue is to compensate for the random big times between is to write additional code in the main loop. I never dealt with the problem of fixed time steps and varying framerate and i can't really know how to start.
One way i thought was to first detect when a big shift occurs and then try to correct it.
The numbers of updates per frame form a series of intger numbers. The series is unlikely to be convergent in the pure mathematical point of view but i think it's intuitive to observe that its values will get closer to some fixed values. I can calculate an approximation of this value by an arithemetic mean like so:
approximateConvergenceValue = Sum(sequence[i]) / numTotalUpdates, 1<=i<=numTotalUpdates;
A better approximation of this value would be to use a quadratic mean like so:
approximateConvergenceValue = Square_Root(Sum(sequence[i]*sequence[i]) / numTotalUpdates), 1<=i<=numTotalUpdates;
This is pretty close to the most frequent values of numUpdatesThisFrame so i guess it's a good approximation. I'm puzzled when applying this detection to correct the framerate and also keep approximateConvergenceValue to a good approximation. The simulation would ideally self adapt to work the same using this calculation(minimizing the effect seen on screen as a result of the adaption)
So how does one usually deal with fixed time step loops and varying frame rate? |