Manually calling Physics.Update and interpolated rigidbody jumps ahead

I don’t know if this is a bug or if there is something I don’t understand regarding interpolated rigidbodies.
I have a rigidbody with constant velocity moving across the screen. I am manually calling Physics.Simulate (albeit in maybe a weird way). Some frames the body is rendered ahead of its actual position.

public class ManualPhysics : MonoBehaviour
{
    private int _fixedUpdateCounter;
    private int _prevFixedUpdateCounter;
    void Start()
    {
        Physics.autoSimulation = false;
    }
    private void FixedUpdate()
    {
        _fixedUpdateCounter++;
    }
    private void Update()
    {
        if (_fixedUpdateCounter > _prevFixedUpdateCounter)
        {
            Physics.Simulate(Time.fixedDeltaTime);
            _prevFixedUpdateCounter = _fixedUpdateCounter;
        }
    }
}

In the example I have increased fixed timestep to 0.1 to really see the effect. When using the recorder the effects happens all the time (so it is related to the timing of Update and FixedUpdate), when just running in the editor it happens just some frames
mediumdecisivegentoopenguin

(I am using Unity 2021.3.0)

8450927–1121054–ManualPhysicsInterpolation.zip (25.9 KB)

Indeed, It is kinda weird. Btw, this code does the same:

private void FixedUpdate()
{
    updatePhysics = true;
}

private void Update()
{
   if (updatePhysics)
   {
      Physics.Simulate(Time.fixedDeltaTime);
      updatePhysics = false;
   }
}

The problem with that logic is that Simulate will be called only once per frame. Sometimes, it is necessary to run physics multiple times.
A more accurate logic can be found on the Physics.Simulate page:

void Update()
{
        if (Physics.autoSimulation)
            return;

        timer += Time.deltaTime;
        while (timer >= Time.fixedDeltaTime)
        {
            timer -= Time.fixedDeltaTime;
            Physics.Simulate(Time.fixedDeltaTime);
        }
}

I could be wrong (a.k.a wait for someone who actually knows about this), but i don’t think you are supposed to use “interpolate” while manually simulating physics during Update. My guess is that, by simulating during update, you are constantly interrupting the interpolation process by changing the body position/rotation.

Maybe it is intended for you to write your own interpolation (Lerp), not just the simulation part.

Manual simulation has no idea what you’re doing nor where you call it from. How can it interpolate if you call this per-frame? It’s during the frames it interpolates normally based upon you simulating during the fixed-update. You simulating during the fixed-update is WHY interpolation is required. Doing it per-frame means it’s not.

You just have to step back and think about what interpolation is rather than why it’s not working. :slight_smile:

In the example above Simulate() is not called every Update(), just some, so interpolation still makes sense for the rest of the frames.
I have read this thread trying to understand interpolation, but I am having difficulties. There is something I am missing.
What does Simulate() has to do with interpolation? You are saying manual simulation interpolates?
I imagined Simulate() just writes the state of the rigidbody (position and rotation with a timestamp).
Then at/before/after(?) Update(), based on the two latest states the transform can be interpolated. Doesn’t matter when or where Simulate was called…

My original problem is that I am doing a bunch of calculations in the GPU, reading it back asynchronously and using it to calculate forces for rigidbodies. If the data has not arrived from the GPU in time (checking
AsyncGPUReadbackRequest.done) for the next Simulate() (in FixedUpdate) i have to skip it and maybe use twice
fixedDeltaTime the next time.
Since Update is called more frequent (almost all of the times) I was experimenting with trying the give the gpu readback a tiny bit more time to arrive (next Update will be called much sooner than the next FixedUpdate). This is when i encountered the interpolation problems above.

My point was that it’s called during the “Update” when interpolation is supposed to happen.

I’ll tag in a 3D physics dev for you, hopefully they can go over it for you. Maybe something has changed in the meantime. I’m a 2D physics dev so there may be differences.

@yant