Get Interpolated rigidbody velocity

Hello fellow creators! I’m trying to get the interpolated velocity of a RigidBody to use when updating the camera lerp speed. This is because I want the camera to speed up the faster the player is going so that it doesn’t lag far enough behind the player. My implementation introduces some jitter even though I use interpolated RigidBodys and use the transform position, which should give me the interpolated positions to calculate the velocity.

And I don’t want to put the camera logic in FixedUpdate(). I want the camera to be as smooth as possible on a high refresh rate monitor.

Here is the code:

LateUpdate ()
{
     //using transform (not rigidbody) to get distance/velocity between last frame.
     float velocity = Vector3.Distance(playerPos.position, lastPosition)/Time.deltaTime; 
  
     lastPosition = playerPos.position; 

     //Lerp the camera position using the speed of velocity.
     camera.position = Vector3.Lerp(camera.position, goalPos,velocity*Time.deltaTime); 
}

Thank you for your time!

You could be using Lerp, but not like that, you will see many comments suggesting to use lerp like that, they are all wrong. Dont use Time.deltaTime with Lerp, it doesn’t work, you wont be able to manage to use Lerp framerate-independent like that.

For me to try to explain why not to use Lerp like that you would need to really understand how Lerp works first. Unity has no smoothing functionality build into the editor, you would have to code it yourself. The best approach is to use MoveTowards with animation curves, is there any reason you would prefer not to use them?

here Ill share a simple example of why Lerp doesn’t work with Time.deltaTime:

Imagine your start point is 0,0 and your target is 1,0 i’ll use 2 examples one running at 1 fps and other 5 fps and your “velocity” will be 0.5 * time.deltaTime

second 0 second 0.2 second 0.4 second 0.6 second 0.8 second 1.0
1 fps Ex1 (0,0) (0,0) (0,0) (0,0) (0,0) (0.5,0)
5 fps Ex2 (0,0) (0.1,0) (0.19) (0.271, 0) (~0.43, 0)

I think you really want to be using Mathf.SmoothDamp, instead of Lerp.

This has a good explanation of what’s wrong with using lerp this way:

Vector3.Lerp simply gives you a vector between two vectors based on the ratio passed in.

So if you know how long you want the camera to take to get to the target, you would pass the camera starting position (not current), camera target position, and the timePassed/desiredTotalTime. If you did this, you could lerp a camera between some starting point and an ending point.

However, in your example, the target is moving, the desired speed is changing, ect. This isn’t really what lerp is for. If you wanted to force it into that role, you could, but it would be extra work.

Instead, Vector3.SmoothDamp does essentially what you want. You would simply pass in the current camera position, the target position of the camera, a dummy velocity variable that the function will update based on the other parameters, the time you want it to take to get there, the max speed if you want one, and the time since calling the function.

I believe that should do what you need.

camera.position = Vector3.Lerp(camera.position, goalPos,velocity*Time.deltaTime);

This approach… It’s being repeated over and over, given as an answer on formus… it’s completely wrong and bad. Why?

Lerp simply returns a linear interpolation between the two values, the first two arguments. The third argument is just a factor, amount of blend between those two.
The line above takes deltaTime as the factor. No matter how many times you execute that, no matter how many updates pass, the camera.position will never reach goalPos, because there’s always some fraction of the goalPos left (Unless deltaTime is more than 1). Moreover, it’s very framerate dependent. On different FPS, the rate of approach will be different (see again the example with deltaTime = 1, when the goal would be reached in one frame and otherwise never). If you have unstable FPS, the motion will also be stuttering.

To smoothly move a value to its goal over time, you can use MoveTowards (with constant speed), or SmoothDamp (which accelerates and deccelerates smoothly towards target). Please don’t ever ever use deltaTime as factor in Lerp, discard any tutorials that tell you to do so, it’s a very common misconception.

Regarding your actual question, I am not aware of an interpolated speed property, but you can easily calculate it. The speed is given in units per second. If you need to access it in Update(), you could simply remember previous interpolated position from previous Update, make a difference and divide by deltaTime (which is a deltaTime from previous frame, so there still might be some stuttering if you use that for motion). Also it would give you the position delta from the last frame, and not speed, which has meaning over time. Velocity of a rigidBody really only changes on FixedUpdate() (or rather, the Physics step) and is constant in between.

For the camera smoothing, just do
cameraPosition = Vector3.SmoothDamp(cameraPosition, targetPosition, ref m_velocity, smoothTime, Time.deltaTime); where smoothTime is an approximate time you expect the camera to reach a new position from any distant stationary position, and m_velocity is a variable where you remember the smoothing motion velocity (just declare a field and let the SmoothDamp use it).

Hello, in your code, you find velocity and divide it by Time.deltaTime. And when you start using it, you multiply it by Time.deltaTime. Therefore, these two actions do not make sense.

Why not just use Vector3.Lerp without finding the velocity? And so that the camera cannot lag far behind the player, it is only necessary to add a condition for checking the distance.

The code:

void LateUpdate ()
{
    camera.position = Vector3.Lerp(camera.position, goalPos, Time.deltaTime * 5);
  
    float distance = 2;
    if (Vector3.Distance(camera.position, goalPos) > distance)
    {
        camera.position = goalPos + (camera.position - goalPos).normalized * distance;
    }
}