PDA

View Full Version : Bezier curves

User137
01-11-2007, 11:07 PM
Came to thinking ways to make 3D animation smooth and came across with bezier curve. Had no experience on it before and thought it would be so overly complicated and all... However, there was nice animated gifs at wiki that explained it all to my simple mind that cannot understand the formulas :lol:

Anyway, i can already imagine so many different uses to this, maybe you do too.

http://en.wikipedia.org/wiki/B%C3%A9zier_curve

Screenshot: http://img216.imageshack.us/img216/1517/bezierxq3.jpg

To my surprise, code became very very simple and seems very fast too! No sqrt or power functions needed. Here's code that i now have on my Next3D engine:

// Define these 2 functions overloaded

type
TVector3f = record x,y,z: single; end;
PVector3f = ^TVector3f;

// delta = 0..1
function nxBezier(const a,b: PVector3f; const delta: single): TVector3f;
var d1: single;
begin
d1:=1-delta;
result.x:=a.x*d1+b.x*delta;
result.y:=a.y*d1+b.y*delta;
result.z:=a.z*d1+b.z*delta;
end;

// Always call with count >= 2
function nxBezier(p: array of TVector3f; const count: word; const delta: single): TVector3f;
var v: array of TVector3f; i: integer;
begin
if count>2 then begin
setlength(v,count-1);
for i:=0 to count-2 do
v[i]:=nxBezier(@p[i],@p[i+1],delta);
result:=nxBezier(v,count-1,delta);
end else if count=2 then
result:=nxBezier(@p[0],@p[1],delta);
end;

Enjoy!

Edit: Still, maybe for animations some other formula would fit better? Something that doesn't approximate as much to remove that much details...

Thought of another function came to mind, when 3 points in animation frame are given (previous vertex, current and next), start curve from half way between time frames. That way details remain not much changed and is possible to make faster function specially for this. But still this wouldn't reach the "top" of each keyframe.

User137
02-11-2007, 03:03 PM
And now thing i call half bezier:

http://img518.imageshack.us/img518/8310/bezier2qv7.jpg

This should be awesome for animating 3d models at least in theory.

function nxHalfBezier(const a,b,c: PVector3f; const delta: single): TVector3f;
var i,j,b1,b2: TVector3f;
begin
i.x:=(a.x+b.x)/2; i.y:=(a.y+b.y)/2; i.z:=(a.z+b.z)/2;
j.x:=(b.x+c.x)/2; j.y:=(b.y+c.y)/2; j.z:=(b.z+c.z)/2;
b1:=nxBezier(@i,b,delta); b2:=nxBezier(b,@j,delta);
result:=nxBezier(@b1,@b2,delta);
end;

arthurprs
02-11-2007, 05:27 PM
nice code i will try to use it in opengl to produre nice effects

chronozphere
02-11-2007, 07:56 PM
Very nice... will take a look (and probably use) the code :razz:

ATM i'm writing and gathering good math-related source. e.g I coded a function that rotates 2D vectors around a center (finished it just a few minutes ago) and a Line-Circle intersection algorithm. :)

These are really nice snippets. How about setting up Pascal-GameDev snippet library?? :razz:
(I'll add my snippets too, then)

arthurprs
02-11-2007, 08:13 PM
Very nice... will take a look (and probably use) the code :razz:

ATM i'm writing and gathering good math-related source. e.g I coded a function that rotates 2D vectors around a center (finished it just a few minutes ago) and a Line-Circle intersection algorithm. :)

These are really nice snippets. How about setting up Pascal-GameDev snippet library?? :razz:
(I'll add my snippets too, then)

a wiki?

cronodragon
02-11-2007, 09:41 PM
http://en.wikipedia.org/wiki/B%C3%A9zier_curve

Screenshot: http://img216.imageshack.us/img216/1517/bezierxq3.jpg

To my surprise, code became very very simple and seems very fast too! No sqrt or power functions needed. Here's code that i now have on my Next3D engine:

Your routine is smaller than the one at Wikipedia, how did you do that? :shock:

arthurprs
02-11-2007, 09:52 PM
nice code i will try to use it in opengl to produre nice effects

upload a demo with the source code :)

grudzio
03-11-2007, 10:10 AM
Bezier curves have one disadvantage. If you interpolate a set of points with such curve, it will not pass through all the points. So, if you want to interpolate a movement through a set of waypoints you must also specify a set of control points outside of the path.

It is much better to use Catmull-Rom splines (http://en.wikipedia.org/wiki/Catmull-Rom_spline) which can be also used for keyframe animations.

User137
03-11-2007, 11:08 AM
It is much better to use Catmull-Rom splines (http://en.wikipedia.org/wiki/Catmull-Rom_spline) which can be also used for keyframe animations.
Thanks.

http://www.mvps.org/directx/articles/catmull/
Showed simple formula of:
q(t) = 0.5 *( (2 * P1) +
(-P0 + P2) * t +
(2*P0 - 5*P1 + 4*P2 - P3) * t2 +
(-P0 + 3*P1- 3*P2 + P3) * t3)

But i see small disadvantage to this. In figure 2 of that formula i see curve taking an extra leap upwards before heading to next point from P0 to P1.. same with P2 to P3. Wouldn't this look clumsy on animation? Or perhaps something similar to my half bezier can be used on those 2 middle ones that looks working good...

chronozphere
03-11-2007, 02:26 PM
Hmm.. i dont think that's a problem. I see that this method uses vectors to control the line direction.
(Much like the pen tool in photoshop). That extra leap is there because the vector of P0 points up while P1 is located at the bottom right, from P0's point of view. :)

So that extra leap is OK!

User137
03-11-2007, 04:50 PM
There is only point coordinates, no normals in the formula though :P But yeah it's well worth try method too.

NecroDOME
03-11-2007, 05:01 PM
Nice! its also something I still wanted to implement since NecroSPACE 2 :P

User137
04-11-2007, 01:31 AM
Like this image showed:
Desired point is in the middle, between second and third point. So the end points are there to just show where to twist :)

As you see here, only middle section is what we need:
http://img64.imageshack.us/img64/1639/catmullas3.jpg

function nxCatmull(const a,b,c,d: PVector3f; const delta: single): TVector3f;
function Calc(p0,p1,p2,p3,t: single): single;
begin
result:=0.5 *( (2 * p1) + (-p0 + p2) * t +
(2*p0 - 5*p1 + 4*p2 - p3) * t*t +
(-p0 + 3*p1- 3*p2 + p3) * t*t*t);
end;
begin
result.x:=Calc(a.x, b.x, c.x, d.x, delta);
result.y:=Calc(a.y, b.y, c.y, d.y, delta);
result.z:=Calc(a.z, b.z, c.z, d.z, delta);
end;

PS. I really like seeing these twist in 3 dimensions real time :wink:

PPS. Here's what you get when combining the middle sections 8) It's exactly the way the curve is supposed to go! Now is it fast enough for real models?
http://img512.imageshack.us/img512/3514/catmull2kp4.jpg