During Update, Rigidbody/Transform position does not match last Physics Update Position

I have a problem, where for a few visual update frames, an object is clipping through another object.
The object is going at a reasonable speed, solver steps are high, size of the object is 1x1x0.19 against a static cube of 100x100x100.

When this happens, i see that LAST fixed update, there was no collision, and the object was traveling due to just gravity (10m/s, gravity is set to 30m/s) Then during normal updates, until that next fixed update, the object is clipping into the static cube, and then finally the fixed update comes, where is also is clipping, and the OncollisionEnter is called, at which point the clipping is resolved.

9835347--1414899--upload_2024-5-15_1-7-15.png

I feel like i am losing my marbles here. Why is the rigidbody in an invalid location during the visual frames? What jokes messes up the positioning after the last physics update?

I don't apply any forces manually, i just use mostly default settings, i don't get it.


This is how a lot of devs think and the question should be, why is the visual in an "invalid" location compared to the rigidbody because the physics is what is driving it here. I can only presume you mean why are they different? If you're using interpolation then the Transform is moving from the previous physics pose to the current physics pose i.e. it lags behind because interpolation is historic. The opposite is extrapolate which is predictive based upon the velocity i.e. the future, moving from the current pose to a potential future pose.

The main thing to know is that physics doesn't care about the Transform pose, collisions are based upon the Rigidbody pose. You seem to be wondering why (per-frame) no physics is happening but I could be misinterpreting here; clearly physics isn't running per-frame (by default).

You don't mention which collision detection mode so if you're using discrete mode it moves into overlap and then that overlap will be solved, potentially over multiple simulation steps. Continuous stops this.

2 Likes

As you say: "visual" frames and "physics" frames (timesteps) are not the same thing. In particular, physics may not be updated every visual frame, or may be updated multiple times per visual frame.

In visual frames where physics hasn't been updated, the position of the object can be interpolated or extrapolated, depending on your rigidbody settings. If you want both the rigidbody position and the "visual" position to always the same, set interpolation to none.

I am sorry i think we misunderstood. I am well aware the rigidbody is "leading" and the transform (after sync, either forced or automated by Unity, depending on configurations) follows.
In the logs i posted you can see both Y and RY (transform Y and rigidbody Y) and as you can see they match during every log.

Regardless of Discrete, Continuous or Continuous Dynamic, i am seeing the same thing happen in this order:

  • Fixed update happens - item is above floor, no problem

  • Regular update happens - item is IN floor, problem (persists until next step for multiple visual frames)

  • Fixed update happens - notices item is IN floor, resolves collision, creates a collision event

  • Everything is back to normal

I don't grasp exactly why AFTER a physics update, where the position was still valid (non clipping) at the end of said fixed update, which is also leading for the regular transform and position,. Is then in a new and updated clipping position right after the fixed update until the NEXT fixed update where this gets resolved.

If i look at the order of execution on physics steps it looks like the cause might be because the "internal physics update" happens after my log (log happening in fixed update obviously) but that would mean the "internal physics update" should be aware it just made a collision, and also cause this OnCollision to happen in the same frame. Not remain in the "colliding/clipped" state for an entire physics step, right? (in return causing the visuals to clip for all the visual frames in between)

If this is working as intended, and continuous physics does not solve the issue, what would, are there any other settings i should check, or should i start trying to anticipate it in my own code instead?

When the FixedUpdate happens as part of the Unity PlayerLoop, everything that's registered to it i.e. Scripts, Animation, Physics (etc) are called in a fixed order. The Scripts (MonoBehaviours) are called first and at some point after that 3D Physics is called. FixedUpdate in the Scripts allows you to modify what's about to happen in the simulation step (assuming the simulation mode is set to be called then).

Most physics systems only calculate and solve the contacts once at the start of the simulation step, not twice. This means the contacts it solves and you get a callback for are the ones it has already solved, not the ones that currently exist post velocity integration (movement). If you have the contacts calculated at the end then the simulation solves the previous steps contacts. This can lead to confusion over what it solved and its current state. Doing it twice (once at the start and once at the end is expensive). I know DOTS physics had an option to do this and it was expensive and might've even been removed eventually, not sure.

I'm suspicious that continuous doesn't solve whatever your problem is as there should be no overlap with it. I'd say turn off interpolation first to remove that aspect during debugging, being as it's only visual and has nothing to do with physics itself.

Note that whilst I'm here trying to help, I am NOT part of the 3D physics team and I am not aware of any potential bugs or changes to behaviour at all. I never use 3D physics but I am aware of how things are hooked up even if I'm less than familiar with particular details of PhysX.


Did you try Continuous Speculative?. The other modes will allow a rigidbody to overlap when colliding.

Hey guys, thanks for the input.
I tested the exact same setup, only changing the collision detection method. And of course no interpolation.
It turns out all the methods of detection fail, except for Continuous Speculative.

So while this solves my problem, since i don't particularly need accuracy, and i can switch it to this collision detection mode when i require it, and toggle it back after.
It makes 0% sense to me still, why the other methods of collision detection fail.

I will for clarity post my whole experiment, just so others can find this in the future. Even though i found my solution.
Note that "Under" and the check along with it, is the exact float value at which my object is 100% below the surface of the table (EI: clipping to a point it becomes invisible and a visual issue for me)

    private void FixedUpdate()
    {
        Debug.Log($"Fixed Time: {Time.fixedTime} Velocity: {rigidBody.velocity} Under: {transform.position.y <= -0.075} Y: {transform.position.y} RY: {rigidBody.position.y}");
        if(transform.position.y <= -0.075)
            Debug.Break();
    }

    private IEnumerator FixedUpdateCoroutine()
    {
        while (true)
        {
            yield return new WaitForFixedUpdate();
            Debug.Log($"WaitFixed Time: {Time.fixedTime} Velocity: {rigidBody.velocity} Under: {transform.position.y <= -0.075} Y: {transform.position.y} RY: {rigidBody.position.y}");
        }
    }

    private void Update()
    {
        Debug.Log($"Update Time: {Time.time} Fixed Time: {Time.fixedTime} Under: {transform.position.y <= -0.075} Y: {transform.position.y} RY: {rigidBody.position.y}");
    }
    private void OnCollisionEnter(Collision collision)
    {
        Debug.Log($"Entry Time: {Time.fixedTime} Velocity: {collision.relativeVelocity} UndoForce: {collision.impulse} Under: {transform.position.y <= -0.075} Y: {transform.position.y} RY: {rigidBody.position.y}");
    }

9839556--1415673--upload_2024-5-16_21-48-54.png
9839556--1415676--upload_2024-5-16_21-49-48.png