Skip to main content
Tweeted twitter.com/#!/StackGameDev/status/476218087201464321
Added second image showing desired behaviour
Source Link

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

Green: Local position when a packet is received (edited for clarity)

enter image description here On a network with a realistic amount of lag and packet loss, this is the result:

Bad stuff

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

This is how it looks on a perfect network with the object moving right to left. (0 ping, 0 packet loss, etc.)

Good stuff

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

    Every x ms, receive a packet with a Vector3 position
  2. Set the goal to that position

    Set the goal to that position
  3. Set the positionAtLastPacket to the current local position

    Set the positionAtLastPacket to the current local position
  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    
    Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.
  5. If the next packet takes longer than expected, interpolation continues past the goal and becomes extrapolation.

I believe what is happening is the extrapolation overshoots a bit to far. Over several packets, this issue compounds, causing the oscillation.

    // local transform position when the last packet arrived. Will lerp from here to the goal
    private Vector3 positionAtLastPacket;

    // location received from last packet
    private Vector3 goal;

    // time since the last packet arrived
    private float currentTime;

    // estimated time to reach goal (also the expected time of the next packet)
    private float timeToReachGoal;

    private void PacketReceived(Vector3 position, float timeBetweenPackets)
    {
        positionAtLastPacket = transform.position;

        goal = position;

        timeToReachGoal = timeBetweenPackets;
        currentTime = 0;

        Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
        Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
        Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
    }

    private void FrameUpdate()
    {
        currentTime += Time.deltaTime;

        float delta = currentTime/timeToReachGoal;
        transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);

        // current local position
        Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
    }

    /// <summary>
    /// Lerp without being locked to 0-1
    /// </summary>
    Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
    {
        return from + (to - from) * t;
    }

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

Green: Local position when a packet is received (edited for clarity)

enter image description here

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    

Green: Local position when a packet is received (edited for clarity)

On a network with a realistic amount of lag and packet loss, this is the result:

Bad stuff

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

This is how it looks on a perfect network with the object moving right to left. (0 ping, 0 packet loss, etc.)

Good stuff

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position
  2. Set the goal to that position
  3. Set the positionAtLastPacket to the current local position
  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.
  5. If the next packet takes longer than expected, interpolation continues past the goal and becomes extrapolation.

I believe what is happening is the extrapolation overshoots a bit to far. Over several packets, this issue compounds, causing the oscillation.

    // local transform position when the last packet arrived. Will lerp from here to the goal
    private Vector3 positionAtLastPacket;

    // location received from last packet
    private Vector3 goal;

    // time since the last packet arrived
    private float currentTime;

    // estimated time to reach goal (also the expected time of the next packet)
    private float timeToReachGoal;

    private void PacketReceived(Vector3 position, float timeBetweenPackets)
    {
        positionAtLastPacket = transform.position;

        goal = position;

        timeToReachGoal = timeBetweenPackets;
        currentTime = 0;

        Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
        Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
        Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
    }

    private void FrameUpdate()
    {
        currentTime += Time.deltaTime;

        float delta = currentTime/timeToReachGoal;
        transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);

        // current local position
        Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
    }

    /// <summary>
    /// Lerp without being locked to 0-1
    /// </summary>
    Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
    {
        return from + (to - from) * t;
    }
moooore clarification
Source Link

In a fast-paced multiplayer game I'm working on, there is an issue with the interpolation algorithm. You can see it clearly inThis interpolation is for a moving object not controlled by the image belowlocal computer.

The server sends packets with the object's position at a fixed rate. (red markers) The interpolation algorithm is attempting (and failing) to create a smooth path between the red markers.

The results of this interpolation are shown by green and black markers. Green is the local position at the exact time a packet is received, and black is the local position at every frame.

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

Green: Local position when a packet is received (edited for clarity)

The local position (green lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    

In a fast-paced multiplayer game I'm working on, there is an issue with the interpolation algorithm. You can see it clearly in the image below.

Green: Local position when a packet is received (edited for clarity)

The local position (green lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    

In a fast-paced multiplayer game I'm working on, there is an issue with the interpolation algorithm. This interpolation is for a moving object not controlled by the local computer.

The server sends packets with the object's position at a fixed rate. (red markers) The interpolation algorithm is attempting (and failing) to create a smooth path between the red markers.

The results of this interpolation are shown by green and black markers. Green is the local position at the exact time a packet is received, and black is the local position at every frame.

The local position (green&black lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

Green: Local position when a packet is received (edited for clarity)

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal, attempting to reach the goal approximately when the next packet should arrive.

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    
Post Reopened by House
Post Closed as "Needs details or clarity" by House
Added more details for code
Source Link

The local position (green lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly. Here is the

The code works like this:

    // local transform position when the last packet arrived. Will lerp from here to the goal
    private Vector3 positionAtLastPacket;

    // location received from last packet
    private Vector3 goal;

    // time since the last packet arrived
    private float currentTime;

    // estimated time to reach goal (also the expected time of the next packet)
    private float timeToReachGoal;

    private void PacketReceived(Vector3 position, float timeBetweenPackets)
    {
        positionAtLastPacket = transform.position;

        goal = position;

        timeToReachGoal = timeBetweenPackets;
        currentTime = 0;

        Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
        Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
        Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
    }

    private void FrameUpdate()
    {
        currentTime += Time.deltaTime;

        float delta = currentTime/timeToReachGoal;
        transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);

        // current local position
        Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
    }

    /// <summary>
    /// Lerp without being locked to 0-1
    /// </summary>
    Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
    {
        return from + (to - from) * t;
    }
  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    

The local position (green lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly. Here is the code:

    // local transform position when the last packet arrived. Will lerp from here to the goal
    private Vector3 positionAtLastPacket;

    // location received from last packet
    private Vector3 goal;

    // time since the last packet arrived
    private float currentTime;

    // estimated time to reach goal (also the expected time of the next packet)
    private float timeToReachGoal;

    private void PacketReceived(Vector3 position, float timeBetweenPackets)
    {
        positionAtLastPacket = transform.position;

        goal = position;

        timeToReachGoal = timeBetweenPackets;
        currentTime = 0;

        Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
        Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
        Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
    }

    private void FrameUpdate()
    {
        currentTime += Time.deltaTime;

        float delta = currentTime/timeToReachGoal;
        transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);

        // current local position
        Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
    }

    /// <summary>
    /// Lerp without being locked to 0-1
    /// </summary>
    Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
    {
        return from + (to - from) * t;
    }

The local position (green lines) seems to oscillate around the goals (red lines) instead of moving between them smoothly.

The code works like this:

  1. Every x ms, receive a packet with a Vector3 position

  2. Set the goal to that position

  3. Set the positionAtLastPacket to the current local position

  4. Every frame, lerp from positionAtLastPacket to goal

     // local transform position when the last packet arrived. Will lerp from here to the goal
     private Vector3 positionAtLastPacket;
    
     // location received from last packet
     private Vector3 goal;
    
     // time since the last packet arrived
     private float currentTime;
    
     // estimated time to reach goal (also the expected time of the next packet)
     private float timeToReachGoal;
    
     private void PacketReceived(Vector3 position, float timeBetweenPackets)
     {
         positionAtLastPacket = transform.position;
    
         goal = position;
    
         timeToReachGoal = timeBetweenPackets;
         currentTime = 0;
    
         Debug.DrawRay(transform.position, Vector3.up, Color.cyan, 5); // current local position
         Debug.DrawLine(transform.position, goal, Color.blue, 5); // path to goal
         Debug.DrawRay(goal, Vector3.up, Color.red, 5); // received goal position
     }
    
     private void FrameUpdate()
     {
         currentTime += Time.deltaTime;
    
         float delta = currentTime/timeToReachGoal;
         transform.position = FreeLerp(positionAtLastPacket, goal, currentTime / timeToReachGoal);
    
         // current local position
         Debug.DrawRay(transform.position, Vector3.up * 0.5f, Color.black, 5);
     }
    
     /// <summary>
     /// Lerp without being locked to 0-1
     /// </summary>
     Vector3 FreeLerp(Vector3 from, Vector3 to, float t)
     {
         return from + (to - from) * t;
     }
    
Edited for clarity
Source Link
Loading
Source Link
Loading