Catmull-Rom Splines

I have been working on some code to generate procedural race tracks for a wipeout style game. Part of this work involved using splines to smooth out the track so it looks natural and curvy.

For this purpose I used a fourth order CatmulRom spline which has the nice property that its curve travels through the control points.

I also brushed of my high-school calculus and worked out a derivative function for the spline which is usefull for extracting normal vectors at any point on the curve.

// evaluate spine
// where t is between 0.f and 1.f
float catmullrom_spline(float t, float v0, float v1, float v2, float v3) {

  const float c1 = /********/    1.0f * v1    /*******/   /********/;
  const float c2 = -0.5f * v0 +  /*******/    0.5f * v2   /********/;
  const float c3 =  1.0f * v0 + -2.5f * v1 +  2.0f * v2 + -0.5f * v3;
  const float c4 = -0.5f * v0 +  1.5f * v1 + -1.5f * v2 +  0.5f * v3;

  return (c4 * t*t*t) + (c3 * t*t) + (c2 * t) + c1;
}

// calculate spline derivative
// where t is between 0.f and 1.f
float catmullrom_spline_deriv(float t, float v0, float v1, float v2, float v3) {

  const float c2 = -0.5f * v0 +  /*******/    0.5f * v2   /********/;
  const float c3 =  1.0f * v0 + -2.5f * v1 +  2.0f * v2 + -0.5f * v3;
  const float c4 = -0.5f * v0 +  1.5f * v1 + -1.5f * v2 +  0.5f * v3;

  return (3.f * c4 * t*t) + (2.f * c3 * t) + (c2);
}

The above code is only one dimensional but it can be fairly easily scaled up to two or more dimensions as follows:

// evaluate spline
// where t is between 0.f and 1.f
float2 catmullrom_spline(float t, float2 v0, float2 v1, float2 v2, float2 v3) {
  return float2{
    catmullrom_spline(t, v0.x, v1.x, v2.x, v3.x),
    catmullrom_spline(t, v0.y, v1.y, v2.y, v3.y)
  };
}

// calculate spline derivative
// where t is between 0.f and 1.f
// note that the return value will most likely need to be normalized.
float2 catmullrom_spline_deriv(float t, float2 v0, float2 v1, float2 v2, float2 v3) {
  return float2{
    catmullrom_spline_deriv(t, v0.x, v1.x, v2.x, v3.x),
    catmullrom_spline_deriv(t, v0.y, v1.y, v2.y, v3.y)
  };
}

Hopefully these functions are usefull to someone at some point.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s