I recently wrote an article about smoothing out measured time fluctuations and provided a code sample that fixes the issue. I haven’t seen this stuff talked about much before and I’m noticing some confusion about what causes this aspect of stuttering and how we can eliminate it. In a nutshell the problem is that the measured time delta fluctuates around the actual vsync interval. This is not the same issue as temporal aliasing which happens when you have a fixed time step but no interpolation! Here’s an article on AnandTech that explains the issue of frame delta stuttering in great technical detail.
Perhaps a thought experiment can better help explain this aspect of stuttering. I’ll start with an analogy for triple buffering to show how can we trade latency for the ability to smooth out the occasional long frame. We will build on that to show how measured clock time will always fluctuate between frames and why it must be corrected for.
Lets imagine that I’m writing a story at the same time you are reading it.
You read at precisely 1 page per minute, reading each page very quickly then taking a short break before starting a new page in exactly minute intervals. I can write much faster then 1 page per minute, maybe even twice as fast but sometimes I need to slow down to think and write much slower. Problem is we only have 3 pieces of paper to share between us and I can’t write on the same page you are reading. To make matters worse we are in different rooms and can’t see each other. We have a helper who brings my new papers to you and your old papers back to me, so there is some unpredictable variance when we actually get that paper from the other person. I can magically erase papers instantly when I get them. We have clocks but they aren’t synchronized and there’s no way to communicate.
Can you keep reading at a steady pace even as I’m taking a variable amount of time to write each page?
As long as I don’t fall too far behind you can keep busy by reading the buffer paper so any minor fluctuations should buffer out. As long as I keep that extra paper/buffer full I can take almost twice as long to write one page and not miss a beat. After that happens I need to work hard to get that buffer full again, it might take a few pages before I am back on track but the important thing is you didn’t have to stop reading. I need to try to plan things out so I never take too long too often. If we run out of buffer and there is not a new page ready in time you will need to stop reading for 1 minute while I catch up.
With double buffering the situation gets a little worse. We would only have 2 pieces of paper which means I always need to write faster then you can read plus enough to cover any variance we have when passing papers back and forth. With a single buffer I’m basically writing to the same page you are reading, erasing the lines as I go. The upside is that you would be reading more recently to when it was actually written so there is less latency.
How do delta time fluctuations have anything to do with this?
Lets make things a little more complicated and say we want every paper to to represent exactly 1 minute of time in the fictional world I’m writing about. I don’t write pages at 1 page per minute but I can still write each page to represent exactly 1 minute even though it might take me more or less time to write it. I can even create a time stamp that I just increment by 1 minute each time I start a new page. When you are reading as far as you know the time stamps are correct and exactly 1 minute apart regardless of our relative times. And since you are reading at exactly the same rate as the time stamps then it will also appear to you that each time stamp matches up with your own time.
If the story you are reading represents 1 minute per page in the fictional world and it takes you exactly 1 minute to read each page then you are reading it in real time. As long as I keep a reasonable pace and our helper gets us the pages on time we can do this without any stutter with a buffer of 1 or 2 pages to share between us. This would be equivalent to always using the vsync interval as your delta. Some console games solve the problem in this way because they are in such a predictable environment they can “lock” the framerate to whatever the vsync interval is (or a fraction of it, typically 30hz on 60hz HDTV). My method of time smoothing goes one step farther to detect when frames get skipped, which can happen in less predictable environments like a windows system.
What if I use my stopwatch to keep track of how long each page should be?
I could try to use a stop watch to time how long each page takes to write and make the next page represent that length of time in the fictional world. This would cause each page to not be exactly 1 minute apart from each other, in fact it would probably fluctuate quite a bit because it takes me different amounts of time to write each page. Maybe one represents 30 seconds of time and another that represents almost 2 minutes. When you are reading at exactly 1 minute intervals it will come across at the same rate on average but in different sized chunks. It should be obvious by now why this causes stuttering, yet this is how so many games apply their time delta! To alleviate this you can fix up the delta time to be a proper multiple of the refresh time like the solution proposed in my first article.
This analogy is pretty close to what’s actually happening so I hope it helps people wrap their brains around this challenging problem of temporal dynamics. If you don’t have anything in your engine to smooth out frame deltas then consider giving my solution a try and see the difference for yourself. If you think this doesn’t apply to you because your engine already has a fixed time step and interpolation then think again because this is a totally different issue and must be resolved for interpolation to function properly. For more technical details and the stutter elimination code check out my earlier article.