Advertisement

Bezier curves

Started by October 09, 2002 08:29 AM
7 comments, last by DBX 22 years, 4 months ago
I have a series of bezier curves in 3D space which make up a path. Each curve has two endpoints and a control point. I can find the position at some point, t, along the curve but I also need to know three vectors forming the axis aligned to the curve (i.e. forward, right and up) so that I can align objects that follow the curve and move objects at right angles to the curve. Can anyone help me with this. I read somewhere that the tangent is obtained from the derirative, but my calculus is very old and very useless. Thanks
I don''t know much about bezier curves, but the derivative of a third-degree polynomial is quite easy to find:

f(x) = ax³ + bx² + cx + d

f''(x) = 3ax² + 2bx + c

If you do that for all three components (x, y, z), you should get the tangent vector. The up and right vectors are not encoded in a bezier curve, so you''ll have to determine them yourself.

HTH,

Cédric
Advertisement
hi dbx

if you have your new base vectors U,V,W
(W is your tangent-vector ("new" Z axis) U and V are your "new" X and Y vectors)
you have to multiply the model matrix with

| Ux Vx Wx 0 || Uy Vy Wy 0 || Uz Vz Wz 0 || 0  0  0  1 | 

where
W = tangent-vectorU = [0,1,0] cross WV = W cross U|U| = |V| = |W| = 1 

by the way
you could obtain your tangent-vector numerically as well
(assuming B(t) is your bezier-function returning a vector)
W = ( B(t + 0.0001f) - B(t) ).Normalize(); 

this could result in problems near 1.0 though
depending on your interpolation-step

hth/

[edited by - diego_rodriguez on October 9, 2002 10:57:09 AM]
cedricl and diego_rodriguez both have workable solutions for finding the tangent vector, which will be the direction of the axis aligned to the curve.

As cedricl says, and diego* gives some ideas about, you have to use some rules to determine the other 2 axes. diego*''s solution is not robust since it will fail if W = [0,1,0]. You''d probably want to use some rule like U always points towards a specific object or point, and select that object/point such that it is always sits off to the side of the curve somewhere. The rest of diego*''s solution would then work for finding V.

Since Bezier curves are so simple, I prefer cedricl''s approach to finding the tangent. And he is exactly correct, though I will expand a bit. Just your Bezier curve equation as:

x = x(t)
y = y(t)
z = z(t)

Those will be simple polynomial functions, and you can use cedricl''s example of a derivative in x---just replace x with s. And the tangent vector will be:

tangent = (dx/dt)i + (dy/dt)j + (dz/dt)k

with dx/dt, dy/dt, and dz/dt evaluated at the current parametric position, t, along the Bezier curve.

That tangent won''t be unit length, so you''d have to normalize it if you need unit length.

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
The listed methods will work, but they are really overkill for bezier curves. The easy way to get the tangent and binormal (and thus normal) of a bezier curve involves forward differences. So, since you have three control points, the method goes like this:

p0 = first control point
p1 = second
p2 = third

Then, let us define the following

ffd0 = p1-p0
ffd1 = p2-p1

These are the first forward differences. Also, since you don''t just want the normal to the curve, we need to get the second forward differences. There''s actually only one for a cubic curve, but in general there would be more.

sfd0 = ffd1-ffd0

Now, to get the tangent, you just treat the first forward differences as control points for a new bezier curve. Thus,

T(t) = t*ffd0+(1-t)*ffd1

for a cubic curve. For a higher order, you would need to do a little more work, but the idea is the same. Getting the binormal vector is a bit uglier, but still the same idea:

B(t) = (t*ffd0+(1-t)*ffd1) ^ (sfd0)

You probably want to normalize both of these, by the way. Finally, the Normal vector is given by

N(t) = B(t) ^ T(t)

So, using the tangen, normal, and binormal vectors, you should be able to do everything you need. Also, I''m using the ^ to mean cross product, in case that''s a source of confusion. Also, if you want to see this stuff in action, I helped write some java applets over the summer to demonstrate bezier curves. There''s a 3D one that requires Java3D (yuk), but it shows off what I''m talking about pretty well. The URL is http://www.rose-hulman.edu/~finn/courses/geometry/CCLI/summer02.htm
Thanks for your answers, but I''m still having a little trouble understanding them.

tsuraan: You say
quote:

Now, to get the tangent, you just treat the first forward differences as control points for a new bezier curve. Thus,

T(t) = t*ffd0+(1-t)*ffd1



I''m not sure what that equation means. The bezier curve equation I am using is (taken from some JAVA code)

x = (int)((1-t)*(1-t)*x0 + 2*t*(1-t)*x1 + t*t*x2);

and similarly for y and z. Where x0 and x2 are the endpoints and x1 is the control point.
I can''t see how to fill this in for your example - you have only stated two points, not three. Unless I use the point along the curve as the start point, but I still don''t understand how to take this further.

Any further help would be apprieciated.


Advertisement
Ok, the equation that you''re using is for cubic curves, and it''s correct. There is a more general form, involving the bernstien polynomial, which looks like this:

B(n,k,t) = choose(n,k)*(t^k)*((1-t)^(n-k))

That''s a bit ugly, and nobody uses it directly, but it''s pretty necessary. Using that, the formula for a bezier curve of order N is:

K(t) = sum(B(N-1,k,t)*Pk, k=0..N-1)

Thus, for a curve of order 3, we have

K(t) = sum(B(N,k,t)*Pk, k=0..2)
K(t) = B(2,0,t)*P0 + B(2,1,t)*P1 + B(2,2,t)*P2
K(t) = (1-t)^2*P0 + 2*(1-t)*t*P1 + t*t*P2

Which is exactly what you have. The nice thing about this form is that it allows you to find the curve for any number of points. So, since the tangent only wants two curves, we let N be two, and use the equation:

K(t) = sum(B(1,k,t)*Pk, k=0..N-1)
K(t) = B(1,0,t)*P0 + B(1,1,t)*P1
K(t) = (1-t)*P0 + t*P1

So, that''s how that works. If that''s too confusing, I can try again to explain it.
quote:
Original post by tsuraan
B(t) = (t*ffd0+(1-t)*ffd1) ^ (sfd0)



Yes, actually that''s a nice solution when you just need to have an object kind of roll with the curve. But there may be reasons to choose a different vector than the binormal, for example you may want the object to have one axis always parallel to the xy plane, and that constraint would determine the 2nd to axes.

Also, you should recognize that your binormal approach fails when ffd0 and ffd1 are parallel, giving B(t) = 0i + 0j + 0k----no direction at all.

It is possible for ffd0 and ffd1 to be parallel even when the curve is not flat. For example, suppose the curve has an inflection point at p0, and that the forward side of the curve is exactly reversed in z from the backward side of the cure, e.g., p2.y - p1.y = p1.y - p0.y; p2.x - p1.x = p1.x - p0.x, and p2.z - p1.z = p1.z - p0.z. In this case, you''d get ffd0 == ffd1. You can always change your discretization in such a case, but if you''re just doing, for example, a uniform discretization of the curve then there is a very real possibility that this situation will arise.

Also, ffd1 == ffd0 will happen if the curve is a line.

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Thank you all, I now have the tangent working correctly with the following:

ex = (int)(2*t*x0-2*x0+2*x1-4*t*x1+2*t*x2);

I will work on the other two axis later tonight.

This topic is closed to new replies.

Advertisement