The idea is that the logic should run at a constant rate, while the rendering is a separate process that interpolates or extrapolates the logic steps to match any framerate the display uses.
Extrapolation is off the cards, because the engine cannot predict the future. I think that only works for certain games which have very predictable movement and can make that assumption. It would result in objects doing things like going inside solids for one tick instead of bouncing off because it extrapolated incorrectly. Also fast, rapidly turning objects using extrapolation tend to get a weird floaty feel to them as they move around in a pattern which is not exactly on their true path (one of your graphs basically shows this). I don't think a technique like that can work in a general-purpose engine.
The big problem with interpolation is the latency, which you tried to downplay but I think will be a significant problem. As you say the engine needs to know the next point along to do the interpolation math, so you need to deliberately delay rendering by the logic time step. Suppose logic is running at 30 Hz (33ms step). Unfortunately hardware timers and OS scheduling is not perfect, so there will be some jitter in that. So in practice the engine would need to increase that to say 40ms.
There are two problems with this:
1) 40ms is a lot of delay, close to the 50ms perception of "instantaneous". I don't know how this compares to the total system latency, but usually users can tell for every extra frame of latency added in. People already notice that there is 1-2 frames of latency on objects following the mouse, and I am pretty sure adding as much as 40ms artificial latency will be a significant, noticeable amount of extra input delay in games.
2) how do you know the system *really* will both schedule and complete a logic step in 40ms? There are several sources of error in the hardware timers, OS thread scheduling, and variations in the actual amount of work that has to be done every tick. If one time it takes 41ms, you're missing a step so you can't interpolate anywhere, so without extrapolation you basically can't render a new frame. So this actually adds a new source of jank: occasional cases where a new step is not ready, forcing rendering to skip a frame. There is a nasty tradeoff here between reducing latency but making it risky you miss frames, vs. increasing the latency but making it more likely you always hit a frame.
Alternatively you can run logic faster than the display rate, but again this comes at a very high CPU cost to gain any actual benefits from that.
There is one more problem with interpolation. Object's positions can change multiple times within the same tick. So to remember where everything was the last frame, the engine will have to complete a tick, then go through every object and remember its finishing position for the next tick. This adds O(n) CPU work to track all moving objects. For games with a lot of moving objects this could be a significant overhead.
So from this I think I can add a couple more benefits to the existing variable-step/v-sync approach:
- does not add any extra input delay
- guarantees a new logic step is ready in advance of every rendered frame
- does not add any extra CPU overhead for tracking interpolation
Just to clarify, I don't claim that the existing variable-step system is perfect, and there may well be some games that can or do use some of those techniques and have it work well. But I think being an actual engine developer gives me a unique perspective. Through some of the bug reports I've seen I know people routinely take the engine to the absolute limits and do completely crazy things. Ideas like extrapolation are interesting, but from this kind of experience, I *know* there are some cases that will just be totally broken by it. I feel the approach we have to take is to choose things which generally work OK everywhere over things that optimise for certain types of game but make others worse.