How can I interpolate between two positions within a specified time?

So I've been stuck on this one for a bit. I'm making a replay system and everything is working, but it's just moving objects to the next frames positions and rotations at the moment. I want to create a sort of lerp function that will move and rotate the object to the next frame position over the course of one frames time like 0.02 seconds.
I've tried a couple of things with unity standard Lerp functions but none of them really did it for me.

Thanks

Comments

  • edited
    Hey,
    So here is an idea : you know where you are, you know where you want to be and you know how long you want it to take to get there. So as they teach us in school : speed = distance/time ;)

    For instance you are at (0, 0, 0) you want to be at (0, 1, 0) in 0.02 seconds.
    Vector3 startPosition = new Vector3(0, 0, 0)
    Vector3 endPosition = new Vector3(0, 1, 0)
    float time = 0.02f;
    
    int count = 0;
    int totalFrames;
    Vector3 deltaMovement;


    You get the amount of frames 0.02 seconds equates to by doing this :
    totalFrames = Mathf.RoundToInt(0.02 / Time.deltaTime)


    Then you get the delta distance you need to travel :
    deltaMovement = (endPosition - startposition) / totalFrames;


    Now you need to apply the deltaMovement every frame and it will get you to your destination in time.
    void Update ()
    {
    	if (count > totalFrames)
    	{
    	// You now set the startPosition endPosition to a new value and work out the totalFrames and deltaMovement again.
            //  totalFrames will probably be the same if you keep time at 0.02f
            count = 0; // you reset the counter as well
    	}
    	else
            {
                  theThingYouWantToMove.transform.position += deltaMovement
            }
            count ++;
    }


    I did not test any of this but it should work. Its also not the only way but its probably the route I would go. Check out easing functions as well.

    *Edit*
    Instead of adding the deltaMovement each frame you can also do this :

    newPosition = distanceBetweenPoints * (count/totalFrames)
  • You might find this list of common easing functions useful. Just pass milliseconds into the function you want to use. :)

  • If you're not looking to code if all yourself I can recommend this library
  • Wait, what's the problem with regular lerping? This is pretty much exactly what lerp is there to do...

    Is the issue from trying to lerp two things (position and rotation) and then combining those results being difficult?
  • @dislekcia I think if you use regular lerp it wont ever reach the target destination. And he cant specify the time it should take to get there.

    This linear interpolation function (from @garethf) is probably what he wants :
    Math.linearTween = function (t, b, c, d) {
    return c*t/d + b;
    };
  • edited
    @dislekcia I think if you use regular lerp it wont ever reach the target destination. And he cant specify the time it should take to get there.
    That didn't seem to be the issue. A replay system is playing back known states at a known time scale. If you know that an object was in state A at 0s and then at state B in 0.05s and you're playing back at half speed, that's prime target for easy lerping.

    I'm waiting for @notsimon207 to explain the actual problem :)

    P.S. A lerp not actually reaching its destination generally happens when you shift either the end-point of the lerp and/or change the time in which you want the lerp to happen in. You really shouldn't be trying to lerp towards a non-static position, there are different functions for that... Replays are usually static though.
    Thanked by 1Kobusvdwalt9
  • edited
    @dislekcia We use the term "lerp" to imply moving towards something at a speed proportional to the distance left (and never quite reaching the point). Of course lerping doesn't have to function like that, and probably doesn't mean that in the context @notsimon207 provided.

    I think further explanation from @notsimon207 might help, assuming the information others have helped him with hasn't already solved the problem.
  • edited
    @dislekcia We use the term "lerp" to imply moving towards something at a speed proportional to the distance left (and never quite reaching the point). Of course lerping doesn't have to function like that, and probably doesn't mean that in the context @notsimon207 provided.
    I dunno where all that stuff about "speed proportional to the distance left" comes from. A lerp is a linear interpolation between two values based on a factor between 0 and 1. That's the definition and that's what the lerp functions in Unity give you: lerp(A, B, 0f) = A, lerp(A, B, 1f) = B and lerp(A, B, 0.5f) = halfway between A and B.

    I don't think that it's a good idea to confuse lerping with other kinds of interpolation, given how often the way that lerping works is misunderstood... The interpolation you're talking about changes the factor of the lerp based on the distance between the most recent lerp output and state B. That's totally a valid usage of lerping, but the problems in that come from the self-referential nature of taking the fraction of a distance (Zeno's paradox) and not from anything inherent in linear interpolation itself.

    It's also pretty easy to fix the problem you're bringing up: just have a minimum value for your factor and the interpolation will definitely get to its goal point ;)
  • edited
    @dislekcia In my day-to-day the kind of lerping I'm referring to is vastly more common than the linear interpretation between two points (when modifying values there is nearly always some kind of easing that I want and the lerp function is great at achieving some of that, I almost always use lerp functions to decelerate for instance). For me the kind of behaviour I'm describing (as in tend towards while easing out) is the default use case for "lerp" unless the context dictates otherwise. As such, the verb "lerping" for me often with mean a different thing to "lerping" to you (from what I can tell of your usage), though I'd agree that your definition is more strictly accurate.

    In any case, I was just trying to clear up some confusion of what I thought to be a problem of semantics, rather than of logic. Seems I made more confusion instead :(
  • The word 'lerp' comes directly from Linear intERPolation, so anything other than @dislekcia's description of the equation isn't strictly a lerp, but a different type of easing interpolation equation, and I agree that it doesn't help anyone to throw terms around arbitrarily and confuse people :)
    Thanked by 1mattbenic
  • Thanks for all the help. @kobusvdwalt9 that's exactly what I needed.
    @Dislekcia the problem wasn't really that it's hard to combine rotations and positions, it 2as just that unity lerp function didn't seem to take the value from one position to another in a specified time.

    I found a pretty cool solution for the lerping in the end. I use physics for everything. So I just save the rigid body velocity and angular velocity each frame as well as the positions and rotations. Then I move the rigid body to the position and rotation of the current frame and set it's velocity and angular velocity to what it was at that time and let the physix take care of it until the next frame. It works pretty well at about 20fps. But I think I can get it to work at lower frame rates by doing tome clever interpolation of velocities. Also keeping everything in physics state the whole time means the replay system can double as a sort of layer able time traveling system.
    Thanked by 1Kobusvdwalt9
  • edited
    @notsimon207: I don't understand the issue... Are you saying that you were having difficulty figuring out what to put in for the factor? That's easy: You have to scale your current time as a fraction (between 0 and 1) of the total time you want the lerp to take...

    So if you have a list of saved states that include time, then lerping between state 0 and 1, you need to do something like this:

    timeSinceLastState += frameDeltaTime * timescaling;
    factor = timeSinceLastState / (stateB.time - stateA.time);
    
    while (factor > 1f) {
      timeSinceLastState -= (stateB.time - stateA.time);
      stateA = stateB;
      stateB = GetNextStateFromWherever();
      factor = timeSinceLastState / (stateB.time - stateA.time);
    }
    
    position = lerp(stateA.position, stateB.position, factor);


    I would be REALLY suspicious of a physics-based system like you've described doing well. It probably works okay at specific framerates, but if that changes drastically or differs from the rate it was recorded at, shit is going to go crazy alarmingly fast. Think about it this way: You've already done all that calculation once AND saved it, why risk doing it again when it might have different results?
  • edited
    Or in its most simple form:

    position = Vector3.Lerp(startPosition, tagetPosition, elapsedTime/totalTime);
Sign In or Register to comment.