Quick answer: Jittery Rigidbody movement is almost always caused by moving a Rigidbody using Transform methods in Update instead of physics methods in FixedUpdate, or by a camera following a physics object in Update instead of LateUpdate.

Here is how to fix Unity physics jittery movement. Your player character shakes, vibrates, or stutters as it moves across the screen. The movement code looks correct, the velocity values are reasonable, and there are no errors in the console — but the visual result is jagged and unpolished. This is one of the most frequently encountered issues in Unity physics, and it stems from a fundamental mismatch between how Unity's physics engine steps through time and how rendering frames are displayed.

The Symptom

A GameObject with a Rigidbody (or Rigidbody2D) visibly jitters, stutters, or micro-teleports during movement. The effect is most noticeable during smooth lateral movement or when a camera follows the object. The character appears to vibrate in place, rubber-band slightly, or move in tiny discrete jumps rather than gliding smoothly. The jitter is often more severe at higher or inconsistent frame rates, and it may appear worse on faster hardware where the gap between the render rate and physics rate is larger.

Sometimes the object itself looks fine in isolation, but the camera following it introduces the stutter. In other cases, the jitter is visible even without camera movement — the object shakes against a static background. Both scenarios share the same root causes.

What Causes This

Unity's physics engine runs at a fixed timestep (default 0.02 seconds, or 50 times per second) in FixedUpdate. Rendering runs as fast as possible in Update, often at 60, 144, or uncapped frame rates. These two loops are not synchronized. When you move a Rigidbody using the wrong loop, or when the camera tracks a physics object in the wrong loop, the visual position jumps between physics steps and creates visible stutter.

The Fix

Step 1: Move all Rigidbody movement to FixedUpdate. Read input in Update (where it is polled every frame) and store it. Apply forces, velocity changes, and MovePosition calls in FixedUpdate (where the physics engine expects them). Never set transform.position directly on a Rigidbody:

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private float _moveSpeed = 8f;
    [SerializeField] private float _jumpForce = 12f;

    private Rigidbody _rb;
    private Vector3 _inputDirection;
    private bool _jumpRequested;

    void Awake()
    {
        _rb = GetComponent<Rigidbody>();
    }

    // Read input in Update (runs every render frame)
    void Update()
    {
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");
        _inputDirection = new Vector3(h, 0f, v).normalized;

        // Use GetButtonDown in Update so it is not missed
        if (Input.GetButtonDown("Jump"))
        {
            _jumpRequested = true;
        }
    }

    // Apply movement in FixedUpdate (runs on physics timestep)
    void FixedUpdate()
    {
        // Use velocity for consistent speed regardless of frame rate
        Vector3 desiredVelocity = _inputDirection * _moveSpeed;
        _rb.linearVelocity = new Vector3(
            desiredVelocity.x,
            _rb.linearVelocity.y,  // preserve gravity
            desiredVelocity.z
        );

        if (_jumpRequested)
        {
            _rb.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse);
            _jumpRequested = false;
        }
    }
}

Step 2: Enable Rigidbody interpolation. Select the GameObject in the Inspector, find the Rigidbody component, and set Interpolation to Interpolate. This tells Unity to smooth the visual position between the previous and current physics positions, eliminating the staircase effect. Use Interpolate for most objects and Extrapolate only if you need prediction (like fast-moving projectiles):

using UnityEngine;

public class PhysicsSetup : MonoBehaviour
{
    void Awake()
    {
        Rigidbody rb = GetComponent<Rigidbody>();
        if (rb != null)
        {
            // Interpolate smooths between last two physics positions.
            // This is the correct setting for player characters,
            // vehicles, and any object the camera follows.
            rb.interpolation = RigidbodyInterpolation.Interpolate;
        }

        // For 2D games, use the 2D equivalent:
        Rigidbody2D rb2d = GetComponent<Rigidbody2D>();
        if (rb2d != null)
        {
            rb2d.interpolation = RigidbodyInterpolation2D.Interpolate;
        }
    }

    // BAD: This causes jitter. Never do this with a Rigidbody.
    // void Update()
    // {
    //     transform.position += Vector3.right * speed * Time.deltaTime;
    // }
}

Step 3: Move camera follow logic to LateUpdate. The camera should update its position in LateUpdate, which runs after all Update and FixedUpdate calls for the frame have completed. This guarantees the camera always sees the object's final interpolated position. For physics-heavy games, you can also use FixedUpdate for the camera and enable interpolation on the camera's own Rigidbody, but LateUpdate is the standard approach:

using UnityEngine;

public class SmoothCameraFollow : MonoBehaviour
{
    [SerializeField] private Transform _target;
    [SerializeField] private Vector3 _offset = new Vector3(0f, 8f, -6f);
    [SerializeField] private float _smoothSpeed = 10f;

    // Use LateUpdate so the camera reads the final
    // interpolated position of the target for this frame.
    void LateUpdate()
    {
        if (_target == null) return;

        Vector3 desiredPosition = _target.position + _offset;

        // SmoothDamp or Lerp for additional smoothing
        transform.position = Vector3.Lerp(
            transform.position,
            desiredPosition,
            _smoothSpeed * Time.deltaTime
        );

        transform.LookAt(_target.position);
    }
}

// --- Alternative: Physics-based camera for extreme smoothness ---

public class PhysicsCameraFollow : MonoBehaviour
{
    [SerializeField] private Transform _target;
    [SerializeField] private Vector3 _offset = new Vector3(0f, 8f, -6f);
    [SerializeField] private float _smoothTime = 0.15f;

    private Vector3 _velocity;

    // SmoothDamp produces the best results for
    // camera follow because it handles acceleration
    // and deceleration automatically.
    void LateUpdate()
    {
        if (_target == null) return;

        Vector3 desiredPosition = _target.position + _offset;

        transform.position = Vector3.SmoothDamp(
            transform.position,
            desiredPosition,
            ref _velocity,
            _smoothTime
        );

        transform.LookAt(_target.position);
    }
}

After applying all three fixes, your movement should be completely smooth. To summarize the rules: read input in Update, move Rigidbodies in FixedUpdate, follow with the camera in LateUpdate, and always enable Interpolation on any Rigidbody that the player can see moving.

Related Issues

See also: Fix: Unity Pink or Magenta Materials (Missing Shader).

See also: Fix: Unity NavMeshAgent Not Moving to Destination.

Input in Update, physics in FixedUpdate, camera in LateUpdate.