Search Unity

Player's interpolated position gets jittery

Discussion in 'Scripting' started by Marscaleb, May 23, 2021.

  1. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    1,037
    So I noticed that my framerate looked poor when the player moved around, and realized it was because my camera is currently set up to lock exactly on the player every update, meanwhile the player movement is updated every fixedUpdate.

    The simple solution to fix this is to set my player's rigidbody to interpolate. Now I get smooth movement on the player, and each update the camera can move to an interpolated position.

    But I found an odd bug that now occurs.
    When my player walks into certain objects, the player (and thus the camera) gets jittery. As best I can tell, it's a vertical motion as if the interpolation figured the player should be moving either up or down.

    These certain objects are capsule colliders. I don't get this problem from box collider or mesh colliders.
    I thought maybe I was just hitting the rounded edge and the physics calculations pushed it slightly up, but even when I made the capsule so immensely tall that it was in no way touching the rounded edge, I still had this problem.

    Has anyone else encountered this before? Any idea of what I might need to be changing or checking?
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    How are you handling collision and movement in general? My guess is you're teleporting your player inadvertently, the physics system realizes you've clipped into the wall, and then teleports the player out -- creating a feedback loop.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,697
    That's my guess too, but without code its hard to say.

    For physics, NEVER use transform.Translate() and NEVER set the position directly.

    The only way to to use Rigidbody / Rigidbody2D is to call the .MovePosition() method on the RB.

    Same goes for rotating: always use .MoveRotation()

    Anything else is considered a "teleport" by the physics system, and like a glass tank of fish, you will startle the physics system if you teleport colliders into each other, and the physics will jerk sharply to try and deconflict.
     
  4. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    Just to be clear, 2D physics is quite happy at using MovePosition on either a Dynamic or Kinematic body. It doesn't teleport, in both cases it sets the velocity required to move to the new position.
     
    GroZZleR likes this.
  6. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    1,037
    I guess I am, actually.
    I have a line that snaps the player to the ground. I have a raycast straight down and if it hits anything it sets the player's position in Y to just above the point where it hits (but sets the X and Z to current values)
    After that I apply a velocity to the rigidbody which only has values in X and Z. The player's rigidbody doesn't use gravity, and is not Kinematic.
    This was to provide smooth and continuous motion while walking up/down slopes.

    So what would be the ideal way to rectify this? I don't really want to use velocities for keeping the player grounded, because then slopes change player speed and the player will continually slide down slopes.
     
  7. Dawdlebird

    Dawdlebird

    Joined:
    Apr 22, 2013
    Posts:
    88
    This might be a bit of an old thread but I have to respond to this, because 'MovePosition' for 2d rigidbodies does *not* alter it's velocity at all (despite MelvMay's comment here and the documentation on it). I tried reporting this as a bug recently, but the response I got from Unity was (and I will paste it here as a quote, with some underscore added):
    So it does teleport and it does not set velocity. Try using MovePosition on a rigidbody2D and you'll find velocity does not change at all.
     
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    True but that doesn't mean it's not using velocity to move it. It never stated it permanently changes the velocity. If it were to do that then it'd move to the position then continue moving which isn't what MovePosition is for, it isn't MoveDirection.

    Quote: "In your script, you're using rb.MovePosition(position), which directly sets the position of the Rigidbody2D. This method does not affect the velocity of the Rigidbody2D because it isn't technically moving the object in a physical sense (where an applied force would result in a velocity change). Instead, it teleports the object to the new position."

    No idea who wrote that (likely a CQA) but it's incorrect and maybe they were basing their knowledge on how 3D physics works where MovePosition/MoveRotation were designed to work with Kinematic bodies only. It's an incorrect statement, not from the 2D team nor me, the person who wrote all the code for 2D physics.

    So let me again state for the record; MovePosition doesn't permanently change the velocity property you read to which you're referring to as evidence that it's "teleporting". That doesn't mean that the movement isn't done with the body velocity behind the scenes during simulation.

    When the simulation runs, we modify the velocity such that in a single simulation step the body will reach the target position. It does not permanently change any velocity it might have before that as this is stored and restored after the simulation step. It also does the same for properties such as linear drag which would stop it reaching the target position. The same goes for MoveRotation.

    So in short, yes it does move with linear/angular velocity and no drag and yes, you'll not detect any change from your API. It'll simply do what you ask it to which is to ensure it moves to the specified position/rotation in the next simulation step. The Rigidbody2D is a wrapper for the "real" physics objects behind the scenes.

    If you were to actually test this correctly you'd see that it doesn't cause tunnelling/overlaps if you were using continuous so it is NOT "teleporting". It is moving with velocity.

    Again, for 3D physics, it uses PhysX target feature to move to the target if it's Kinematic else if it's Dynamic, it just sets the position i.e. "teleporting". In 2D, both Dynamic/Kinematic are moved with the body (Box2D) velocity during the simulation step.
     
  9. Dawdlebird

    Dawdlebird

    Joined:
    Apr 22, 2013
    Posts:
    88
    Actually if you do use movePosition on a 3d rigidbody, velocity does change. I'm developing a platformer with both 3d and 2d levels, with moving platforms that have rigidbodies attached to them. I use 'MovePosition' because it a clean kinematic way of moving them, but I need to read their velocity to transfer to the player when he's standing on them.

    For 3d I was simply reading velocity from the rigidbody directly, which corresponded perfectly with the velocity required to perform the MovePosition() actions.
    It was only when working on the 2d version I found that velocity just returned {0, 0}.
    I've done things differently since, but the inconsistency between the two nags a bit.
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    As I said above, a velocity of a 3D Dynamic body just teleports instantly to that position. It only works for a Kinematic body, in 2D it works for both.

    MovePosition isn't a "calculate the velocity", it's a move to position which 2D does, exactly and only that. Leaving velocity in 3D was something unintentional but wasn't something that was changed because it'd be a breaking change.

    If you want to know the velocity, it's trivial to calculate anyway.

    This is still way, way off-topic for this thread though.