Your idea is correct, you just have to work more on it.
Here is an article I wrote last year: http://blog.meltinglogic.com/2013/12/how-to-generate-procedural-racetracks/
It uses exactly what you described, and as you can see, the result is very good.
Here is the code which explains how the mesh was generated from the spline:
for(float i = 0; i <= 1.0f;)
Vector2 p = CatmullRom.calculatePoint(dataSet, i);
Vector2 deriv = CatmullRom.calculateDerivative(dataSet, i);
float len = deriv.Length();
i += step / len;
Vector2 v1 = new Vector2();
Vector2 v2 = new Vector2();
if(i > 1.0f) i = 1.0f;
The idea behind this algorithm is, traverse through the spline by segments of
step size, for each point on the spline, calculate its derivative, normalize it to get the normal, rotate it by 90°, then add two points to the vertice list:
splinePoint + normal and
splinePoint - normal. You'll have a stripe of vertices following the spline, you can easily generate it's indices, If you have problems generating those indices, just throw a comment and I'll edit the answer.
Some further clarifications:
- Derivative is the same as tangent, in case your engine words it differently;
step / derivativeLength to the
time parameter is the right thing to do. Since the size of the spline differ from point to point, you must use this to keep going at a constant speed;
- With that being said,
step parameter should be defined in World Units, not Spline Percentage. (That is, if you set step to 5 and your units are pixels, then each segment will be put 5 pixels apart, and not each 5% of the spline);
thickness is some constant that you should fiddle around to find a good value. If your world units are pixels, then your mesh will be
2 * thickness thick;
- If your engine doesnt support derivatives, try porting these: LibGDX Catmull Rom or LibGDX Bezier
- In case you want details on the implementation of catmull derivatives, it seems that OP have already did the awesome job of asking on Math.SE, so go read that!