Keep in mind it's best practice to run your game logic at a constant update rate and render an interpolated state between the current and previous game logic frame, meaning that if your game logic is frame rate dependent, you can still run it smoothly on any monitor.
Using two frames to interpolate at render time is adding one frame of latency.
It is possible to do it on a single frame, extrapolating instead of interpolating, but you have to use a simple but uncommon trick to make it robust.
The latency gain is not a full frame but some sizeable fraction of a frame, I think it is worth it for some games.
What types of games are you thinking?
Extrapolation isnt worth the chance of misprediction if it's a player movement based game.
The 'input latency' introduced by interpolating between frames is far different than typical 'input latency'. It's less than a single frame, and the game still renders movement at the same frame, just less movement. Most 'input latency' tests only test for _any_ movement, so those kinds of tests would detect 0 difference between 'interpolation', 'extrapolation' and 'render the exact game state'.
I'm a fast paced gamer, and I make fast paced games, I've never once 'felt' the input latency from interpolating the players position between simulation frames.
But if graphics frame rate is higher you won’t be able to interpolate until the next logic frame is ready, - wouldn’t that increase latency?
The benefits _far_ outweigh the costs of the other options. Games look _horrible_ if you render the physics at a different frame rate than the rest of the game. Like, horridly bad.
* Run physics at such a high rate that sampling it at 30 or 60 or 144 or 260 hertz is fine, like running physics at 1kHz. This is appropriate for certain kinds of very realistic physics sim style games, but usually undesirable due to performance.
* Run physics at some fixed, sane rate (somewhere between 20 and 100 Hz probably), and then do rendering separately, interpolating between positions for refresh rates higher than the physics tick rate. This can be hard to make feel good on refresh rates which aren't clean multiples or divisors of the tick rate, but ensures that physics behaves identically independent of frame rate.
* Couple rendering and physics and run at a fixed frame rate (60 FPS). This will work okay for many players but a whole lot of people will be angry at you that your game is choppy on their fancy high refresh monitor, and if you don't change monitor mode to change the monitor's refresh rate, a 144Hz screen will sometimes refresh twice and sometimes thrice per game frame, meaning nothing will ever seem smooth even by 60 FPS standards.
* Couple physics and frame rate but allow the delta time to vary (maybe running physics 2 or 3 times per frame if the frame rate is really low). I'd say this produces the best results for any given refresh rate, and it's relatively simple to implement, but it causes physics to behave slightly differently with different frame rates, and it's prone to bugs like the one discussed in this article.
It's not an easy decision, there is no good rule of thumb. I tend to prefer the last option I listed for my games, but I'm aware that it has drawbacks. But "just decouple physics from rendering" is certainly not the straightforward rule of thumb you seem to suggest it is. (EDIT since this post seemed more negative than I meant: running at a fixed time step is a good solution and very appropriate for many games, I'm not saying your suggestion is bad)
> * Run physics at such a high rate that sampling it at 30 or 60 or 144 or 260 hertz is fine, like running physics at 1kHz.
> (...)
> Couple rendering and physics and run at a fixed frame rate (60 FPS)
Both are sensible, but you can do better:
First you can detect the monitor framerate and do a benchmark to get which framerate the computer can comfortably run the game (at not too much CPU utilization), and take the minimum from those two values. That's a good way to gauge a baseline. The only problem is that the simulation will not be deterministic across two different computers (but there are many other sources of nondeterminism, and many games are okay with that)
Then another further issue is that if you run physics at exactly the same frame rate as the monitor, you might sometimes run two physics steps during a frame, or no physics step during a given frame, which causes staggering. To solve that, if your baseline ends up being your framerate, you then run the simulation at a few Hz higher than that (Bevy for example defaults to 64Hz [0], imagining that 60Hz monitors are still common)
[0] https://docs.rs/bevy/0.13.2/bevy/time/struct.Fixed.html
> The default timestep() is 64 hertz, or 15625 microseconds. This value was chosen because using 60 hertz has the potential for a pathological interaction with the monitor refresh rate where the game alternates between running two fixed timesteps and zero fixed timesteps per frame (for example when running two fixed timesteps takes longer than a frame). Additionally, the value is a power of two which losslessly converts into f32 and f64.
I'm sure somewhere on the Internet somebody's written down some good choices of curve; hopefully someone else knows what to search for.
(I don't know what to do if another change interrupts the first but it's a rare case and can probably be handled imperfectly.)
This kind of lerp trick, while imperfect, is useful in exactly these sort of situations. It allows you to smooth movement even if the target point is changing at at arbitrary intervals (note too that it works okay generalised to multiple dimensions). And the statelessness is very useful too - I don't think the feel is great and it's not very controllable, but being able to just add some damping to the movement without having to track animation states or anything like that is super useful.
Extract the position (p0) and velocity (v0) vectors at the moment of interruption, and derive a new function F(t) that meets the constraints {F(0)=p0, F'(0)=v0, F(1)=p1, F'(1)=0}.
With the explicit curve you have more control in the exact damping, too.
> So there we have it, the perfect formula, frame rate agnostic ,
... worth noting what happens on a frame time spike.
a = lerp(a, B, 1.0 - exp(-delta * RATE2))
Write: a = lerp(a, B, -expm1(-delta * RATE2))
This is precisely the situation where you really want to use expm1:
https://www.johndcook.com/blog/cpp_expm1/And (as pointed in the above) if you're worried about the slowness of it, just Taylor expand it to x+x²/2.
Finally, unless division is too costly, do:
a = lerp(a, B, -expm1(delta / -T))
Where T is the “time constant” (which you can intuitively express in time units, like seconds):
https://en.wikipedia.org/wiki/Exponential_smoothing#Time_con...It's not the half-life (sorry) but it's still a lot more intuitive as a parameter.
https://docs.godotengine.org/en/stable/tutorials/best_practi...
Because physics frame rate is fixed (configured under project settings), I suspect developers would be able to get away with using the common lerp() formula and not having to worry about varying (display) frame rates.
I'm really lost, but alas have ~0 experience with 3D about 15 years into a career.
Ignoring variable frame rate: 1. Doesn't the frame rate depend on the display hardware?
2. Can you know the frame rate at runtime?
Variable frame rate: 3. What quantity do you use for frame rate for variable frame rates?
2. You can know the targeted frame rate, you can also infer it by averaging the delta times at runtime (not reliable but maybe more accurate on a slow machine?)
3. In my graph, I did pick random delta between 15 and 120 fps IIRC; the point was to simulate what could roughly happen with random lag spikes
I remember Quake 3 still having that issue, but that was in '99...