-1

I have a list of vector points, which define a path of straight line segments to be followed by an object. Currently, I do linear interpolation to animate motion along the path like this:

public class Demo
{
    public float speed = 1;
    private List<Vector3> points;

    private float t; // [0..1]

    private Vector3 Evaluate(float t)
    {
        // Find out in between which points we currently are
        int lastPointIndex = GetLast(t);
        int nextPointIndex = GetNext(t);

        // Obviously, I need to somehow transform parameter t
        // to adjust for the individual length of each segment.

        float segmentLength = GetLength(lastPointIndex, nextPointIndex);

        // But how would I do this?
        return Vector3.Lerp(points[lastPointIndex], points[nextPointIndex], t);
    }

    public void Update()
    {
        // Curve parameter t moves between 0 and 1 at constant speed.
        t = Mathf.PingPong(Time.time * speed, 1);

        // Then just get the evaluated position for the curve time, but
        // this gives variant speed if points are not evenly spaced.
        Vector3 position = Evaluate(t);
        SetObjectPosition(position);
    }
}

I realize, that to achieve constant speed, I need to rescale the parameter t to account for the length of each segment, but I seem to be unable to find out exactly how.

I also know, that I could approximate the path by moving towards the next point at my desired speed and only change direction, once I'm in close proximity or keep track of t as well and change direction once it moves over the next segment, but this seems hacky, when I actually know the exact length of each segment and should be able to interpolate this exactly.

Xarbrough
  • 1,393
  • 13
  • 23

1 Answers1

0

That's actually quiet easy. First, define a speed you want for your object. For example, 6 units per second. That means if a line segment has a length of 6 units then your object will take 1 second to go from its start to its end point. This also means that if you have a line segment that is half that length (i.e. 3 units) it will take the object 0.5 second to cross it. So, what you have to do is calculate the length of all your line segments and divide that by the speed you want to go (3/6 = 0.5 = scaleFactor). Then instead of interpolating between 0 and 1, interpolate between 0 and 1*scaleFactor. Your code then becomes:

public class Demo
{
public float speed = 1;
private List<Vector3> points;

private float t; // [0..1]

private Vector3 Evaluate(float t)
{
    // Find out in between which points we currently are
    int lastPointIndex = GetLast(t);
    int nextPointIndex = GetNext(t);

    float segmentLength = GetLength(lastPointIndex, nextPointIndex);
    float scaleFactor = segmentLength/speed;

    // note that I divided t by scaleFactor instead of multiplication. 
    // That's because Lerp always takes an interval of [0..1]. So, we
    // adjust the curve parameter instead.
    return Vector3.Lerp(points[lastPointIndex], points[nextPointIndex], t/scaleFactor);
}

public void Update()
{
    // Curve parameter t moves between 0 and 1 at constant speed.
    t = Mathf.PingPong(Time.time * speed, 1);

    // Then just get the evaluated position for the curve time, but
    // this gives variant speed if points are not evenly spaced.
    Vector3 position = Evaluate(t);
    SetObjectPosition(position);
}
}
rashmatash
  • 1,699
  • 13
  • 23