Bezier Curves

Im trying to draw a simple curve.

Given that the w factor is used to divide the x,y & z of the points, I assume the curves produced by the following control points should be exactly same. But they are not. Can anyone explain why? I tried using both glMap and Nurbs.

case 1:

double ctrlpoints[4][4] = {
{1.0, 4.0, 0.0, 1.0},
{-5, 4.0, 0.0, 2.0}, <—
{-1.0, -4.0, 0.0, 1.0},
{-7.0, -4.0, 0.0, 1.0}};

case 2:

double ctrlpoints[4][4] = {
{1.0, 4.0, 0.0, 1.0},
{-2.5, 2.0, 0.0, 1.0}, <—
{-1.0, -4.0, 0.0, 1.0},
{-7.0, -4.0, 0.0, 1.0}};

Thanks
Selva

[This message has been edited by Selva (edited 10-31-2001).]

Hi,

I'm not sure if this is what you want by here's the code i used to make a benzier curve(an elipse in this case):

void DrawrElipse(GLfloat CenterX, GLfloat CenterY, GLfloat SizeX, GLfloat SizeY, GLfloat Angle, GLfloat Steps){

double A, B, StepsCont, AngRot, theta, x, y, xRot, yRot;

// xOld, yold - use these if not using line-strips
int i;
A = SizeX;
B = SizeY;
StepsCont = Steps;
AngRot = Angle * PI/180; glDisable(GL_LIGHT1); glDisable(GL_LIGHTING);
glPushMatrix();
glLineWidth(2.5f);
glBegin(GL_LINE_STRIP);
glColor3f(1.0f, 0.0f, 0.0f);
for (i=0; i<PasCont+1;i++) {
theta = 360*(i/PasCont)(PI/180);
x = CenterX + A
cos(theta);
y = CenterY + B*sin(theta);
// if (!i) {xVelho=xRot;yVelho=yRot;}
xRot = CenterX + (x-CenterX)*cos(AngRot) - (y-CentroY)*sin(AngRot);
yRot = CenterY + (x-CenterX)*sin(AngRot) + (y-CenterY)*cos(AngRot);
glVertex3f((float)xRot, 0.0f, (float)yRot);
}
glEnd();
glPopMatrix();
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
}

Hope this helps

Thanks Luiz.

My questions was about the weight (w) of a vertex. If w was used to just devide the x,y,z components, then two control points should produce the same curve.

But my tests show that, apart from dividing the x,y,z components, the w is also used to pull the curve towards/away from the point.

So {5,4,0,2} will pull the curve more than {2.5,2,0,1}.

Better explanations are welcome.

Thanks again.

[This message has been edited by Selva (edited 11-01-2001).]

Originally posted by Selva:
[b]
case 1:

double ctrlpoints[4][4] = {
{1.0, 4.0, 0.0, 1.0},
{-5, 4.0, 0.0, 2.0}, <—
{-1.0, -4.0, 0.0, 1.0},
{-7.0, -4.0, 0.0, 1.0}};
[/b]

the w coord is a weighting factor for use with NURBS. It affects the curve by pulling it towards the control point (or pushes it away). The mathematics for a NURBS curve is something I’m not going to go into here (there’s a couple of very good papers on www.gamasutra.com),,) but there’s more to it than just dividing the x,y,z by w (although that forms a part of it).

Originally posted by Selva:
[b]
case 2:

double ctrlpoints[4][4] = {
{1.0, 4.0, 0.0, 1.0},
{-2.5, 2.0, 0.0, 1.0}, <—
{-1.0, -4.0, 0.0, 1.0},
{-7.0, -4.0, 0.0, 1.0}};

[/b]

The first curve is a NURBS curve that uses a weighting factor of 2 on the second control point to pull the curve towards it. (I think)

The second curve is a cubic bezier curve - the only curve type (convienient lie) that use the weighting factors. To draw the bezier without using gluNurbs, you can do something like :

int i,j;
int LOD = 10;

// draw line strip
glBegin(GL_LINE_STRIP);

// work out coords for LOD+1 curvePoints.
for(i=0;i<=LOD;i++)
{

// calculate the t value
float t = (float)i/LOD;
float CurvePos[3];

// for each x,y,z - calculate value
for(j=0;j<3;j++)
{

CurvePos[j]
= pow((1-t),3)*ctrlpoints[0][j] + pow((1-t),2)tctrlpoints[1][j] + (1-t)*pow(t,2)*ctrlpoints[2][j] + pow(t,3)*ctrlpoints[3][j];

}

// draw curve
glVertex3fv(CurvePos);

}

glEnd();

Thanks “Rob The Bloke”.

If my understanding is correct, then the formula you gave will not incorporate the weight factor. Is that right?

Second, my intention was to produce a kink at that particular point (in case 1). I want it to touch the point fully. But how much ever I add the weight, it only passes closeby. I think you will be able to help me in this regard. Thanks.

Bezier curves do-not use weighting factors, so yes, the w is ignored in the algorithm. The use of the w is actually fairly limited and something I tend to avoid.

Taking the bezier curve, we need to insert a kink in the curve. This isn’t easy to do with a bezier. Ideally we need to convert the bezier curve into a spline.

the bezier curve equation:

QB(t) = (1-t)^3P1 + (1-t)^2tP2 + (1-t)t^2P3 + t^3P4

the cubic b-spline equation : (still not using weights)

QB(t) = (-t^3 + 3t^2 - 3t + 1)P1 + (3t^3 - 6t^2 + 3t)P2 + (-3t^3 + 3t^2)P3 + t^3P4

If you take the code I gave you above, and re-write it slightly to include the b-spline equation above, you’ll get something that looks very odd.

You’ll notice that the curve is very very small and doesn’t touch any end points at all. In order to generate the same curve you get with the bezier, you need to clamp it. This is done by drawing a total of 5 curves :

curve 1 : uses control points : P1 P1 P1 P2
curve 2 : uses control points : P1 P1 P2 P3
curve 3 : uses control points : P1 P2 P3 P4
curve 4 : uses control points : P2 P3 P4 P4
curve 5 : uses control points : P3 P4 P4 P4

using control points a number of times, gives us the ability to pull the curve to the points. You may notice that the curve is of degree 3 (the highest power in the equation) and it requires 3 control points the same to get it to meet the curve. 4 repeated control points will break the curve.

getting the curve to meet at control point 2 requires us to draw yet more curves (experiment cos I cant check this…)

curve 1 : uses control points : P1 P1 P1 P2
curve 2 : uses control points : P1 P1 P2 P2
curve 3 : uses control points : P1 P2 P2 P2
curve 4 : uses control points : P2 P2 P2 P3
curve 5 : uses control points : P2 P2 P3 P4
curve 6 : uses control points : P2 P3 P4 P4
curve 7 : uses control points : P3 P4 P4 P4

this should work, but is fairly messy. This is where knots and the cox-de-boor algorithm comes into play. Rather than repeatedly re-draw curves, we use a knot vector to hold information that relates to which curves require which control points. Inserting extra knots does a similar thing to duplicating control points. For the bezier curve we can say :

4 control points P1-P4
degree = 3
order = degree+1 = 4
knot vector = [0,0,0,0,1,1,1,1]

The knot vector itself is very difficult to explain, but to give you an overview, it essentually is nothing more than a construct for the cox-de-boor algorithm that lists the parametric t values. Looking up some stuff on the cox-de-boor is probably a good idea.

hermite,beziers & cubic splines: http://www.eburg.com/~baxters/curves/

Carl de Boor’s website has tonnes of material and resource lists for b-splines and NURBS - http://www.cs.wisc.edu/~deboor/

Thank you Bloke. Your explanation and the Baxter’s site were really useful. Im planning to read more on B-Spline curves and surfaces.

Thank you again.
Selva

I’ll check this when I get home, but I don’t think this is too off-base…

So I don’t confuse myself with other naming conventions, here’s how I define Bezier curves.

I’ll call u my parameter, 0 <= u <= 1.

B0-B3 are my basis functions, so
B0=(1-u)^3, B1=(1-u)^2 * u, B2=(1-u) * u^2, B3=u^3.

P0-P3 are my control points such as those given by Selva above.

This means that our output point P(u) = B0P0 + B1P1 + B2P2 + B3P3. So far this agrees with Rob The Bloke 100%. Here’s where I differ though.

You can think of this function acting on each individual component of the control points. In otherwords, if PX(u) is the x-component of the output point, PX(u) = B0P0X + B1P1X + B2P2X + B3P3X. The y and z components are calculated similarly, as are the w-components!

This means that P(u) = < PX(u)/PW(u), PY(u)/PW(u), PZ(u)/PW(u) >. In most cases you don’t specify a w-coordinate and PW(u) = 1 (you can easily show that when all w-coordinates are 1 PW(u)=1). However when you do specify w-coordinates, PW(u) != 1 and funny things can start happening. For example, one point can influence the curve in ways you don’t expect. I remember doing some really weird things by specifying control points with w=0.

It sounds good but I’m doing this from memory… Somebody help me out here… is this completely wrong?

– sec

To calculate the weighting values you need to do the following :

Qx(u) = B0PO.xPO.w + B1P1.xP1w + B2P2.xP2.w + B3P3.xP3.w
Qy(u) = B0
PO.yPO.w + B1P1.yP1w + B2P2.yP2.w + B3P3.yP3.w
Qz(u) = B0PO.zPO.w + B1P1.zP1w + B2P2.zP2.w + B3P3.zP3.w
Qw(u) = B0
PO.w + B1P1w + B2P2.w + B3P3.w

at each point defined by parametric u, this needs to be mapped back to 3D, so each point actually equals :

Q(u) = ( Qx(u)/Qw(u) , Qy(u)/Qw(u) , Qz(u)/Qw(u) )

You now have yourself a rational bezier curve. I have to say though, why do you want a rational bezier curve? Unless you are writing a little test app to demonstate that you can use them, they are fairly pointless. My reasonings against the w are :

  1. When using w, there are extra checks needed to prevent divisions by zero. This is done automatically by the cox-de-boor when calculating splines - you might as well use splines to do it…

  2. If you want a w for real time graphics, my recommendation is to use NURBS with the w and then convert to non-rationl beziers as a pre-processing step, because the calculation is speeded up for real time applications.

  3. Splines offer continuity in a much better way and remove the need to enforce continuity with hacks.

  4. knots are a much more powerful tool than the weightings.

  5. how do you create a tool to make use of the weights that artists can use? I’ve not seen a good one yet (infact, I’ve not seen one).

I have some very strong opinions when it comes to splines, from the point of the programmer they are very nice - little amounts of data - lots of room for optimisation etc. But there are a lot of problems with them - especially when it comes to surfaces.

Beziers & splines for Motion Paths :

when an animator wants to animate motion paths curevs are definatly the best way to do it, however B-splines and beziers are not. The most imporant thing you need is the ability to break the continuity of the curve, to enable changes in direction etc .The best curves for doing this are hermite curves and cardinal splines. These curves give you control points and tangents to control the curve shape. If someone puts down a control point, the curve will pass through it, and the tangent specifies the shape of the curve. In my opinion, the artists are the ones that will end up using the tools you create, so it is imperative that they are done in the most user friendly way.

Bezier Patches & NURBS surfaces :

They do offer surface scalability, and significant advantages for skinning algorithms not afforded by polygons. There are however MAJOR drwbacks.

  1. Bezier patches do not make good surfaces for modelling - it’s too hard for an artist to create something without continuity across surfaces.

  2. NURBS are extremely difficult to model with. For an artist, they will not want to know the maths behind them, but they will need to know in order to produce good looking models. It’s extremely hard to get the shapes you require without specifing high levels of geometry - enough to kill most real time applications.

  3. Texturing is extremely wastefull on a Curved surface. Each surface requires it’s own texture, this texture is covered on a 1 to 1 mapping with the parametric u & v values. On large areas of the surface, there will not be enough texture coverage, and on the small areas too much texture space is wasted. If your model consists of 50 surfaces, you’ll need 50 textures (most of the space on which is wasted).

  4. NURBS models look like NURBS models. They all have very clean looking shapes, and although knot insertion goes some way to rectifying this, it can more often than not, cause more problems than it solves.

I like curves as a subject matter, but they are too limited in their usability, sorry for going off on one…

Don’t get me wrong, I agree completely. In my experience as well there are many reasons that rational Bezier curves are more interesting in theoretical applications than in practical ones. But this does explain exactly why Selva was observing the behavior he was – without delving into an explanation of splines, NURBS, and the Cox-de-Boor algorithm.

The posts (and links) above have a lot of good information though, if you’re looking for a bit more than a simple explanation. I know I learned something.

– sec

Hi Rob,

I agree with you on the curves for animation path.

But on the weight point, knots do not produce exactly what we want. It does not pull the curve exactly towards the point, but slightly adjacent to the point.

I did write a small test routine to convert b-spline to bezier and used glMap. It worked very well. Now I dont need to worry about knots except when I need to create a kink (actually your suggestion)

In this way I could combine different curves smoothly instead of using one whole NURB object with a lot control points. I think this will give me much more control over the texture of the image too (I have not testes this one yet).

I always thought that glu NURBS do not provide enough control over the image.

Even though your points about surfaces seem to make sense, I dont know what other alternative I have.

Thanks
Selva