The logic for interpolating between fixed time steps seems flawed to me, or maybe I don’t understand the design properly. This is what I’m seeing:
With interpolation off, the final values for positions coming out of the physics engine will be used for rendering. This happens even if there are multiple render frames for every physics frame, which can cause objects to visually appear to stutter. This is all what you’d expect so far.
With interpolation on, movement is smooth, even when there are multiple render frames per physics frame, but the position where objects are rendered is technically incorrect. I was expecting that the physics system would simulate “ahead” of the render time, then when rendering we can interpolate towards the future position to get the exact right rendered position. But instead, what appears to be happening is that the last physics frame is in the past, and the interpolated position is chosen between the most recent (past) physics frame and the one immediately before that. So, technically speaking, we are rendering physics objects one physics time step in the past, when interpolation is enabled.
In practice, this might not matter much, but seems like a flaw
The interpolation makes sense as-is, it’s just taking a correct physical simulation and adjusting the values at presentation time based on the available data. That behaviour isn’t a “flaw,” it’s literally just correct interpolation. It’s also just one way of doing things among several options. Trying to simulate “ahead” of realtime would obviously be speculative, there could be changes in the game state like adding / removing / moving / etc. bodies that would invalidate the predicted state. Also, you would probably have two separate simulation steps per fixed update, one for an accurate simulation result to use in the fixed update and another for the state “ahead” of the current step. If you’re fine with plain extrapolation, that’s possible with the presence of PhysicsGraphicalSmoothing and an absence of PhysicsGraphicalInterpolationBuffer, baked from Rigidbody.interpolation = RigidbodyInterpolation.Extrapolate or PhysicsBodyAuthoring.Smoothing = BodySmoothing.Extrapolate. So, out of the box, interpolation and extrapolation are supported. A speculative approach isn’t.
It’s not a flaw, that’s how interpolation works. You have a known state, then the physics runs, and you get a new state. Instead of rendering this new state immediately, the interpolation smoothly moves the visual representation from the previous known state to the new state.
However, standard Rigidbody physics also allows Extrapolation. I don’t know if this is available in ECS physics though.
Extrapolation in standard Rigidbodies uses the velocities calculated in the latest state to predict where the next state will most likely be at the next physics frame. Then uses this velocity for rendering the objects “ahead of time”, hoping that when the physics runs the new physics state will mostly match with the visually rendered positions. But this is purely speculative. The next physics frame might result in positions very different from the predicted ones. Forces and torques apply their effects, collisions are processed, etc. So you will also have a discrepancy between the rendered positions and the physics positions, which must be compensated by the extrapolation along the next frames.
I’m not suggesting having multiple physics states at any time. I’m just saying that it seems better to me to run the physics update repeatedly until the current fixed elapsed time exceeds the non-fixed elapsed time, instead of running it until the current fixed elapsed time + fixed time step exceeds the non-fixed elapsed time. Then interpolating just like we’re doing now except between past and future position.
This way, the rendered positions of objects corresponds correctly to the fixed elapsed time value. One way to see this would be to record the rendered position of an object at non-fixed time X during normal update, and then also record the position of the same object in fixed update at fixed time X (making sure that time X is a multiple of the physics time step). If we went with the approach I’m suggesting these would exactly match and otherwise would not. Unless I’m missing something which is very possible?
I also don’t see the problem with having physics run slightly ahead of rendering and how this would cause problems.
I guess it’s all trade-offs though. Both approaches probably have very minor drawbacks
With interpolation, that’s exactly what’s happening. Physics is one frame ahead of rendering and rendering displays a moment in time between the previous and the latest physics frame.
So the rendering is one frame late from the perspective of physics.
My point is that, after the physics time step(s) complete, the current physics fixed time should always be greater than the current variable time. When I looked into this, the physics time step code was running until the (current fixed time + fixed time step > current variable time). I would have expected it to run until (current fixed time > current variable time). In other words, when I looked into the code, it didn’t look like physics was always ahead, but again I could have misread things. Maybe it did run one extra iteration after that condition was met and I am mistaken
Either way I suspect this doesn’t really matter in practice