in my opengl application i have a Bézier curve in 3d space and i want to to move an object along it. everything it开发者_如何学运维's ok a part of rotations: i have some problem in calculating them. in my mind the pipeline should be this:
- find point on the Bézier (position vector)
- find tangent, normal, binormal (frenet frame)
- find the angle between tangent vector and x axis
- (the same for normal and y axis and binormal and z axis)
- push matrix
- translate in position, rotate in angles, draw object
- pop matrix
but it does not go as i expected: the rotations seems to be random and does not follow the curve. any suggestions?
You're going to have problems with the Frenet frame, because, unfortunately, it is undefined when the curve is even momentarily straight (has vanishing curvature), and it exhibits wild swings in orientation around points where the osculating plane’s normal has major changes in direction, especially at inflection points, where the normal flips.
I'd recommend using something called a Bishop frame (you can Google it, and find out how to compute it in a discrete setting). It is also referred to as a parallel transport frame or a minimum rotation frame - it has the advantage that the frame is always defined, and it changes orientation in a controlled way.
I don't think the problems with Frenet frames necessarily explain the problems you are having. You should start with some easy test cases - Bezier curves that are confined to the XY plane, for example, and step through your calculations until you find what's wrong.
Instead of computing angles just push the frame into the modelview matrix. Normal, Binormal and Tangent go in the upper left 3x3 of the matrix, translation in the 4th column and element 4,4 is 1. Instead of Frenet frame use the already mentioned Bishop frame. So in code:
// assuming you manage your curve in a (opaque) struct Bezier
struct BezierCurve;
typedef float vec3[3];
void bezierEvaluate(BezierCurve *bezier, float t, vec3 normal, vec3 binormal, vec3 tangent, vec3 pos);
void apply_bezier_transform(Bezier *bezier, float t)
{
float M[16]; // OpenGL uses column major ordering
// and this code is a excellent example why it does so:
bezierEvaluate(bezier, t, &M[0], &M[4], &M[8], &M[12]);
M[3] = M[7] = M[11] = 0.;
M[15] = 1.;
glMultMatrixf(M);
}
精彩评论