|[23 Jan 2013]|
Generation of mesh tube along Bezier splines
This article describes the basic principles of mesh generation along Bezier splines.
First of all you need to generate control points of Bezier Curve. Bezier spline is multiple connected Bezier curves. To form spline, Bezier curves should be connected in such a way that the tangent at the end of the previous curve is equal to the tangent at the beginning of the next curve. Or simply penultimate point of the previous curve, common point of the two curves and the second point of the next curve must lie on a straight line:
- numParts - number of Bezier curves in the spline
- splineControlPoints - array of control points
- level - number of control points per curve
- numSegmentsAlongCurve - number of segments along the curve
- numVerticesAroundCurve - number of segments around the curve
The easiest way to generate mesh along the curve is to divide it into finite number of points according to numSegmentsAlongCurve parameter, to construct ring of vertices around each point, and then assemble triangles from vertices. If the curvature of the curve is small the mesh can be generated correctly. But in most cases, certain parts of the mesh will be flipped. So we should take curvature into consideration.
First you need to calculate tangent and normal vectors for each discrete point:
Generation begins from first curve. Whole generation depends on first normal. Set t (parametric value for Bezier curve) to 0. First tangent can be calculated as vector from curve point at t1=t to point t2=t+△, where △ equals to small offset along curve, e.g. △=0.1/numSegmentsAlongCurve.
vec3 t1 = bezierPos(splineControlPoints,part,t1);
vec3 t2 = bezierPos(splineControlPoints,part,t2);
vec3 tangent = (t2-t1).normalize();
Also tangents and normals can be calculated as derivatives:
C'(t) = P0 (-3t26t-3) + P1 (9t2 -12t +3) + P2 (-9t2 6 t) + P3 (3t2 )
C''(t)= P0 (-6T +6) + P1 (18t-12) + P2 (-18t +6) + P3 (6t)
For any vector in 3D there is infinite number of normals. We require only one, but no matter which. Normal in first point can be calculated as cross product of tangent and up(0,1,0) vector.
vec3 normal= crossProduct(tangent,up);
Let's save position (t1), tangent and normal. Set variables prevNormal = normal, prevTangent = tangent.
Let's calculate normal and tangent for next point on the curve. Next point t can be calculated as:
Tangent is calculated as in previous case, as vector from t to t+△.
Normal for current point must be calculated with respect to curve rotation from previous point to current. So, let's calculate rotation. Calculate perpendicular to current tangent and previous tangent, as cross product of these two vectors. This perpendicular is the vector around which curve has bended from previous iteration:
vec3 perp = crossProduct(prevTangent,tangent);
Calculate angle between current tangent and previous tangent, and direction of rotation:
float angle = atan2(perpLen, angleBetweenTans);
// also direction
Calculate rotation matrix around perp vector by angle. Calculate current normal as transformation of previous normal with rotation matrix.
mat4 rotMatrix = rotateAroundAxis(perp,angle);
normal = rotMatrix * prevNormal;
Save positon for t, tangent and normal. Assign values to variables: prevNormal = normal, prevTangent = tangent.
Proceed to the next discrete point on the curve and repeat the process of calculating tangents and normals, taking into account previous normal and tangent. Calculate these vectors for every point on the curve, and then calculate for next curves in the spline.
Now, let's generate vertices - a ring of vertices around every point. For every point we have position, normal and tangent. First vertex for every point will be equal to position + normal * radius. To calculate other vertices it's required to rotate normal around tangent. Angle is dependent on number of segments around the curve.
Vertecies calculation principle:
float rotAngle = 360.0 / numVerticesAroundCurve * i;
mat4 M = rotateAroundAxis(tangents[j],rotAngle);
vec3 rotatedNormal = M * normals[j];
generatedPositions.add(positions[j] + rotatedNormal * radius);
And then form triangles from generated vertices:
For smooth mesh in places of high curvature, you can insert additional points (position, tangent, normal vectors) where angle is too high. For example if angle between previous and current tangent is bigger than someLimit, then insert additional point (with pos, normal and tangent) at t=(tprev+tcur)/2. Also you can perform more precise tesselation with angle and distance epsilons.
Sun and Black Cat- Igor Dykhta () © 2007-2014