Search Unity

Interpolation doesn't work when simulating physics manually

Discussion in 'Physics' started by fjack, May 11, 2019.

  1. fjack

    fjack

    Joined:
    May 5, 2019
    Posts:
    5
    This may be expected behaviour, but it has caught me out - I'd like to understand a bit more about it if anyone knows:

    When I use Physics2D.autoSimulation = true, with Interpolate on my rigidbody, I get very smooth movement. If I disable Interpolate, I get the occasional jitter due to fixed & variable timesteps not aligning. This all makes sense and is standard behaviour.
    When I use Physics2D.autoSimulation = false, and handle my own physics loop in Update(), as follows:
    Code (CSharp):
    1. while (_physicsTimer >= Time.fixedDeltaTime)
    2. {
    3.    _physicsTimer -= Time.fixedDeltaTime;
    4.    Physics2D.Simulate(Time.fixedDeltaTime);
    5. }
    I end up with movement stuttering no matter whether Interpolate is active on my RB2D or not. Is there an easy way to step physics manually yet still have rigidbody interpolation? I can't really work out where in the engine loop the interpolation is handled. The reason for wanting to control physics manually is in order to save the physics state & run the simulation forward a short amount ever frame, then reset the state - for some "forecast" functionality in my game.

    Many thanks
    J
     
    v01pe_, ModLunar and PraetorBlue like this.
  2. fjack

    fjack

    Joined:
    May 5, 2019
    Posts:
    5
    Bump
     
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I'm experiencing this same issue (Unity 2019.4.0f1), 3D physics. Is there a workaround for this?

    In the first part of this video, I'm doing manual simulation (autoSimulate off and calling Physics.simulate). In the second part of the video autosimulate is on:

     
  4. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Just realized this is why the Rigidbody2D interpolation wasn't working!

    Any solution for this?
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I never found a solution. I thought about maybe making my actual physics object invisible, and having a fake version without a rigidbody that follows the position/rotation of the rigidbody. Then you could do your own interpolation in LateUpdate(). But I haven't gotten around to it yet.
     
  6. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Ahh great point.

    I did write this, so I could render the GameObject at a different position than its current physics position.
    The major benefit of doing this rapid-switching (based on Unity's Execution Order per-frame) is that I don't need a 2nd "fake object" (though I'm sure that approach has its pros and cons too).

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Assertions;
    4.  
    5. /// <summary>
    6. /// <para>A component that adds functionality for a GameObject to be rendered at a different position than its transform *usually* is at.</para>
    7. /// <para>This can be used to smooth out player movement with interpolation, without disturbing the physics simulation, for example.</para>
    8. /// <para>The original position of the transform is restored after rendering has finished.</para>
    9. /// </summary>
    10. public class RenderPositionController : MonoBehaviour {
    11.     private bool isRenderPositionInUse;
    12.     private Vector3 renderPosition;
    13.     private Vector3 actualPosition;
    14.  
    15.     public Vector3 RenderPosition {
    16.         get { return renderPosition; }
    17.         set { renderPosition = value; }
    18.     }
    19.  
    20.     #region Unity Messages
    21.     private void OnEnable() {
    22.         Assert.IsFalse(isRenderPositionInUse);
    23.         renderPosition = actualPosition = transform.position;
    24.         StartCoroutine(EndOfFrameLoopCoroutine());
    25.     }
    26.  
    27.     private void LateUpdate() {
    28.         Vector3 position = transform.position;
    29.         actualPosition = position;
    30.         if (Vector3.SqrMagnitude(renderPosition - position) >= 0.01f) {
    31.             isRenderPositionInUse = true;
    32.             transform.position = renderPosition;
    33.         }
    34.     }
    35.     #endregion
    36.  
    37.     private IEnumerator EndOfFrameLoopCoroutine() {
    38.         YieldInstruction wait = new WaitForEndOfFrame();
    39.         while (isActiveAndEnabled) {
    40.             yield return wait;
    41.          
    42.             if (isRenderPositionInUse) {
    43.                 isRenderPositionInUse = false;
    44.                 transform.position = actualPosition;
    45.             }
    46.         }
    47.     }
    48. }
    49.  
    If my assertion (assumption) gets hit during OnEnable, it's probably cause of some Unity-specific quirk that I haven't paid attention to yet. My code just wants to make sure it only moves the object either 0 or 1 times in 1 frame, never more than that or else you'd lose the original position.

    ---

    To use this code, you can add a RenderPositionController component to the root of your GameObject hierarchy, and set its RenderPosition (C# Property) every frame as you wish.

    If you don't set the RenderPosition property each frame, it won't change, and the object will appear to stay stationary during rendering.
     
    ArshakKroyan likes this.
  7. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    Same issue here... :(
     
  8. drossini

    drossini

    Joined:
    Feb 17, 2021
    Posts:
    2
    Hi,

    I'm having the same issue. Any news about this?

    Calling Physics.Simulate() during the Update is not compatible with the RB interpolation?
     
    ModLunar and Gooren like this.
  9. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    Exactly. I even made a bug report with repro project for Unity, only to argue with them for weeks on end only to find out that it's by design, after all the struggle to make them see the issue :D
    BUT
    You can use Extrapolation instead of Interpolation. That works. Unless you have fast moving rigidbodies in your game. These will produce very, very unpleasant results on collision with Extrapolation enabled, for obvious reasons.
     
  10. v01pe_

    v01pe_

    Joined:
    Mar 25, 2015
    Posts:
    71
    Thanks for this thread… I recently fixed an issue by going manual with physics, only to find out, that this raises another issue :(

    Meh… that this is "by design" sounds like an excuse to me, why would anyone want this? I guess it might be difficult to integrate, given the manual simulate could be called at any given time, but interpolating should be possible, w/ the constraint that simulate should be called with a constant value each time!

    Tried using extrapolate, but plain simple straight movement is jittering except I use auto simulate + interpolate. :(
     
  11. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    332
    Extrapolate solved the issue for us fortunately enough.

    I understand that interpolation can be complicated from Unity POV trying to handle all possible manual simulation use cases. They could do the same thing as Unreal however - implement actual physics sub-stepping themselves. Then they could ensure interpolation works as expected with ease.
    I actually asked for that feature, feel free to bump it here :)
     
  12. v01pe_

    v01pe_

    Joined:
    Mar 25, 2015
    Posts:
    71
    Not sure I understand what this does on-top of the fixed time step… replied in the other thread.