Using Bezier Curves

Need an easy way to compute a smooth path going through a series of points? Bezier curves are the answer.

A Bezier curve is a mathematical process of parameterizing a smooth function between two points using two other points as "handles" or "tangent vectors."

I won't go into the mathematics or the explanation of Bezier curves here - there's plenty of that out on the net. What you need is a simple function you can drop into your Lingo project that makes things smooth. And that I can provide.

A Sample Use Case for Bezier Curves

This 3D animation drives the camera through a path consisting of only four points, each of which has a single "tangent" value associated with it. Easy technique, but a nice effect. (May take a few moments to start up.)

This animation uses Bezier curves to drive the camera around the scene with a nice, calm, floating effect. There are actually four Bezier curves here, each one leading from one of the four waypoints to the next, and the camera simply follows along those four curves from one to the next.

To store the curve, all I needed was four waypoints, and tangent vectors for leaving each waypoint. The tangent vector is negated for the path coming in to the waypoint so that the path through the point is smooth.

The Bezier Function Code

Below is the all-powerful Bezier function. You pass it five parameters based on the figure below:

Bezier diagram
p0
The "starting point" of the curve.
p1
The "tangent point" of p0. Think of this as the point where you would end up at if you went straight in the same direction you leave p0 from instead of curving around towards p3. You can also think of it as "pulling" the curve toward it.
p2
The "tangent point" of p3. This is the same thing as p1 - think of it as the point you would end up at if you went straight coming off of p3 instead of curving around towards p0.
p3
The "ending point" of the curve.
r
The ratio along the line, ranging from 0.0 to 1.0. This just indicates what point along the line you want the function to return; a value of 0.0 would give you back p0, and a value of 1.0 would give you back p3. A value of 0.5 would give you the point halfway along the curved path.

The further away from the end points p1 and p2 are, the more they will deform the path. Conversely, if p1 and p2 lie on p0 and p3, you will get a straight line.

Note that this routine works on many different data types. Any element that can be added, subtracted, and multiplied can be passed through the Bezier routine to make it smooth. For 3D, you'll probably be passing it vectors. For 2D, you'll probably be passing it points. For other purposes, you might just pass it numbers, or maybe arrays of vectors and points. For practically anything you need smoothed out, Bezier can help!

Here's the code:

Bezier Along A List

Often, you'll find you want more than one waypoint in your Bezier list. In the example case above, the camera is driven through a series of four Bezier curves, each one leading into the next.

One easy way to achieve a smooth curve between a series of points is to treat the entire series of points as a set of individual Bezier curves, with each Bezier segment between two points using the points before and after those two points to compute the handles.

If that's what you're looking to do, you can use the code below. It gives you the option to define whether the list loops or not; a "looping" list connects the first and last end points, whereas a non-looping list just ends in points.

Fixed distance along a Bezier curve

One final problem you might encounter is finding a point a fixed distance away along a curve. For instance, if you were to drive a snake along a Bezier curve, you would want the snake's segments to be equidistant from each other. Using fixed-difference values of r will get you approximately fixed distances, but between any two arbitrary points, that distance is not fixed.

This function solves that problem. Given a parametric value on a Bezier list (see above), this function returns the parametric value that will return a point on the Bezier list of a given distance that comes "after" the current one. It's up to you to define Bezier lists that have such a point; there is no error trapping for cases where no such point exists.

(Actually, since we're talking about imprecise numbers here, you must supply a greater-than-zero "tolerance" value that determines the range of distance error you're willing to accept. For instance, if you want to find a vector 100 units away from the current value, you might ask for findPointAlongSplineAtDistance( theList, currentValue, 100, .1) to return the parameter that is within .1 units of being 100 units away from the Bezier point at currentValue. Use the highest tolerance that gets you good results.)

This example function assumes a list of vectors (since the context of this site is for Shockwave3D), but it could easily be repurposed for any scalar value type you want by changing the way it determines "distance." It also assumes a looping list.

Made on Mac