Adding alpha to Catmull-Rom

1.3k views Asked by At

I am trying to generate a Catmull-Rom curve from a list of points in Unity. As I do not want to store points in between points of the curve I opted to use a solution that could calculate a position in a Catmull-Rom curve based on time. There are a few examples of this, here and here, however, neither shows how to implement alpha.

The reason I want to implement alpha is so I can have the ability to change between a centripetal, chordal, and uniform Catmull-Rom curve.

private Vector3 GetCatmullRomPosition(float t, Vector3 p0, Vector3 p1,
                                      Vector3 p2, Vector3 p3, float alpha)
{
    Vector3 a = 2f * p1;
    Vector3 b = p2 - p0;
    Vector3 c = 2f * p0 - 5f * p1 + 4f * p2 - p3;
    Vector3 d = -p0 + 3f * p1 - 3f * p2 + p3;
    return 0.5f * (a + (b * t) + (c * t * t) + (d * t * t * t));
}

Source of code

1

There are 1 answers

0
Dan On BEST ANSWER

To anyone who comes here, the answer actually comes from the maths in one of the links from the original question. It is an answer from an SO question Catmull-rom curve with no cusps and no self-intersections . So credits to cfh.

The code posted in my original question is a great way to calculate points in a uniform Catmull-Rom spline, however, it did not factor in alpha. Therefore, it could not be used for chordal, or centripetal, (or anything in between) Catmull-Rom splines. The code below does take into account alpha and therefore supports both chordal and centripetal Catmull-Rom splines.

Without further ado, here is the code ported into C# for Unity.

private Vector3 GetCatmullRomPosition(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float alpha = 0.5f)
{
    float dt0 = GetTime(p0, p1, alpha);
    float dt1 = GetTime(p1, p2, alpha);
    float dt2 = GetTime(p2, p3, alpha);

    Vector3 t1 = ((p1 - p0) / dt0) - ((p2 - p0) / (dt0 + dt1)) + ((p2 - p1) / dt1);
    Vector3 t2 = ((p2 - p1) / dt1) - ((p3 - p1) / (dt1 + dt2)) + ((p3 - p2) / dt2);

    t1 *= dt1;
    t2 *= dt1;

    Vector3 c0 = p1;
    Vector3 c1 = t1;
    Vector3 c2 = (3 * p2) - (3 * p1) - (2 * t1) - t2;
    Vector3 c3 = (2 * p1) - (2 * p2) + t1 + t2;
    Vector3 pos = CalculatePosition(t, c0, c1, c2, c3);

    return pos;
}

private float GetTime(Vector3 p0, Vector3 p1, float alpha)
{
    if(p0 == p1)
        return 1;
    return Mathf.Pow((p1 - p0).sqrMagnitude, 0.5f * alpha);
}

private Vector3 CalculatePosition(float t, Vector3 c0, Vector3 c1, Vector3 c2, Vector3 c3)
{
    float t2 = t * t;
    float t3 = t2 * t;
    return c0 + c1 * t + c2 * t2 + c3 * t3;
}