I recently needed a cubic Bezier path class, but since there’s not one built-in, I converted some C++ code I’d written quite a while ago to C#.

I just thought I’d share since the Unity community forums are such a great reference The code is on GitHub under a free licence. Hope someone finds it useful.

From the README.md:

The Bezier.cs file contains two classes, a simple BezierCurve class that implements the standard Bernstein polynomials, and a BezierPath class that essentially joins the curves together to create a longer path. Both classes implement functions to find the tangent for any t value.

BezierCurve
In most cases you won’t need to use this class directly, but you can if you like. Give it your 4 CVs, and it will let you get a point on the curve for a particular t value, get the tangent for a particular t value, and find the t value of the closest point on the curve to a point you specify.

BezierPath
This one is much more powerful. It allows you to construct it with the knots you want interpolated. It will compute the necessary extra CVs internally so that things remain smooth between the curve sections. You must give it 2 or more knots (I use the term knot to mean interpolated CV… as in, the path will go right through the point). For 2 knots you just get a straight-line segment. For 3 it’ll be curvy.

BezierPath supports open (a beginning and end) and closed (looping) paths. You can work with t values E [0,1] for the whole path, or t E [0, numSegments]. When you see the word ‘Norm’ it means t E [0,1]. For open paths t will be clamped, for closed paths it will just loop around if you pass it a large t value.

The class also lets you compute what t value will result in a position on the path closest to an arbitrary position you specify. See ComputeClosestParam(). When you see the word ‘Compute’, worry about efficiency. ComputeClosestParam is a recursive call that terminates when a user-specified tolerance is met.

My main criticism for this is its reliance on being exactly 4 control points long (in fact, it’ll throw out-of-range exceptions if you call the constructor with a smaller array). A Bezier curve can have any number of control points - a two-control-point Bezier curve being just a straight line, for example - and while more than 4 control points are virtually unheard of, I can’t think of a reason not to support them, especially since it also entails the support of 2- and 3-point Bezier curves which are more common.

For example (although admittedly this will generate some garbage and should be optimized to cache the arrays being used in the intermediate steps):

public Vector3 GetPoint(float t) {
return GetPointHelper(t, controlVerts);
}
private Vector3 GetPointHelper(float t, Vector3[] verts) {
if (verts.Length == 1) return verts[0];
if (verts.Length == 2) return Mathf.Lerp(verts[0], verts[1], t);
Vector3[] reducedArray = new Vector3[verts.Length - 1];
for (int v=0; v < reducedArray.Length; v++) {
reducedArray[v] = Mathf.Lerp(verts[v], verts[v+1], t);
}
return GetPointHelper(t, reducedArray);
}

Cubic Bezier curves have 4 CVs.The BezierPATH class is the one that has more. It may be reasonable to make the BezierCurve private to the path class… I wasn’t really imagining anyone would find the cubic curve class all that useful… but the path class can make a line segment by providing two knots… and relies on knot multiplicity.

Fair enough I’ve updated the names of (both) classes… and stuck an assert in there for the CubicBezierCurve to check the number of CVs.

Looks like a nice implementation of catmull-rom. Good to know if I ever need it. I have done some other spline work, but a long time ago and not open-source stuff (Hierarchical B-splines). Thank you both for the feedback.