4
votes

Good afternoon,

I am attempting to implement a GameObject in Unity that moves along a Cubic CatMull-Rom Spline given 8 constrained random values. I have implemented a function, ComputePointOnCatmullRomCurve, that returns a point on a cubic Catmull-Rom curve (given a scalar 'u' from 0 to 1 and segment_number which indicates which 4 pts to use for interpolation).

I am having trouble implementing the update function to allow for the GameObject to move smoothly. I am currently calling ComputePointOnCatmullRomCurve each update and am incrementing the segment_number each time. The GameObjects position is then set to the result of the function.

However this leads to a GameObject that moves extremely quick. I believe my Update function is incorrect, but I am unsure about how to move the GameObject with respect to the points that are being output by the interpolation function.

If someone would be able to explain to me what I am doing incorrectly, or provide an example or link to an example, it would be very helpful!

Function to compute point on curve:

Vector3 ComputePointOnCatmullRomCurve(float u, int segmentNumber)
{
    // TODO - compute and return a point as a Vector3       
    // Points on segment number 0 start at controlPoints[0] and end at controlPoints[1]
    // Points on segment number 1 start at controlPoints[1] and end at controlPoints[2]
    //       etc...

    Vector3 point = new Vector3();

    float c0 = ((-u + 2f) * u - 1f) * u * 0.5f;
    float c1 = (((3f * u - 5f) * u) * u + 2f) * 0.5f;
    float c2 = ((-3f * u + 4f) * u + 1f) * u * 0.5f;
    float c3 = ((u - 1f) * u * u) * 0.5f;

    Vector3 p0 = controlPoints[(segmentNumber - 1) % NumberOfPoints];
    Vector3 p1 = controlPoints[segmentNumber % NumberOfPoints];
    Vector3 p2 = controlPoints[(segmentNumber + 1) % NumberOfPoints];
    Vector3 p3 = controlPoints[(segmentNumber + 2) % NumberOfPoints];

    point.x = (p0.x * c0) + (p1.x * c1) + (p2.x * c2) + (p3.x * c3);
    point.y = (p0.y * c0) + (p1.y * c1) + (p2.y * c2) + (p3.y * c3);
    point.x = (p0.z * c0) + (p1.z * c1) + (p2.z * c2) + (p3.z * c3);

    return point;
}

Update Function:

void Update () {
    // TODO - use time to determine values for u and segment_number in this function call
    // 0.5 Can be used as u
    time += DT;

    segCounter++;

    Vector3 temp = ComputePointOnCatmullRomCurve(time, segCounter);
    transform.position = temp;
}

Variables:

const int NumberOfPoints = 8;
Vector3[] controlPoints;

const int MinX = -5;
const int MinY = -5;
const int MinZ = 0;

const int MaxX = 5;
const int MaxY = 5;
const int MaxZ = 5;

float time = 0;
const float DT = 0.01f;
public static int segCounter = 0;

Thanks!

Matt

1
Since you say it's moving too quick, does changing time += DT; to time += DT * Time.deltaTime; resolve your timing issues? See docs.unity3d.com/ScriptReference/Time-deltaTime.htmlChris McFarland
Are you incrementing the segment that the entity is on every single Update call?Matt Coubrough
@Chris adding Time.delatTime does not resolve the issue. The time variable can be set at constant, say 0.5 and fast motion still occurs.Marcus Koz
@MattCoubrough Yes, the reference point for the segment is being incremented each update, the three other points used for interpolation based off that initial point are initialized within the ComputePointOnCatmullRomCurveMarcus Koz

1 Answers

4
votes

Your are doing 2 errors in the Update function.

First error:

You are incrementing the index of the current segment at each frame (segmentNumber). I guess this should be done only when the object complete it's travel along the previous spline segment.

Hint:

For spline curves defined by multiple patches I usually express the time (u) in the range [0,n] where n is the number of segment defining the curve. This way you can retrieve the index of the current patch (segmentNumber) simply extracting the integral part from the parameter. Something like:

int segmentNumber =  Mathf.FloorToInt(u);
float segmentU = u - segmentNumber;

Second Error

I don't know what your DT variable is, but unless you are scaling it by the frame delta time somewhere else, you have to do it. Basically you can increase time this way:

time += Time.deltaTime * speedAlongCurve;

I hope it helps.