Hacker News new | past | comments | ask | show | jobs | submit login
A Primer on Bézier Curves (pomax.github.io)
197 points by s1291 on Jan 27, 2022 | hide | past | favorite | 51 comments



Oh I do love a Bézier Curve post, the math and geometry behind them is just so beautiful.

Bartosz Ciechanowski's one from last year is my favourite, a little less math heavy and goes on to explain other curves and surfaces: https://ciechanow.ski/curves-and-surfaces/


Another beautifully explained piece on bézier curves is: The beauty of bézier curves by Fréya Holmer

https://youtu.be/aVwxzDHniEw

Found this via a contest by Grant Sanderson, and it absolutely blew me away(and most people I forwarded it to)


+1 to both to Freya and Bartosz, both are incredible knowledge sharers. I'm happy to see their names pop up on these sorts of things more frequently.


Yes, this is my favorite Bézier Curves


I used to think it was my fault that I struggled to draw things with Bézier curves but then I took a look at the resource packs for a game I respected (which had a flat art style that would have been a good fit for vectors) and found that my favorite character designers didn't know how to draw anime characters with Bézier curves either.

That is, no matter how much art you know or math you know it is awkward to draw things with Bézier curves and it's a bit of a tragedy that NURBS and other curve families that are more intuitive to work with haven't caught on.


I personally really like x-splines:

https://inversethought.com/jordi/xsplines/

I find them super-intuitive to use. The fact that at each node you can make it close, sharp, or interpolating is quite helpful. They're also not hard to implement. You can read my js code to see how I did it.

They're implemented in Xfig and just about nowhere else. I wish they were elsewhere. I've been thinking about getting them into GNU IMP. Maybe some day I'll sit down and try to write patches for it.


I wouldn't think of Bézier curves as a design tool, they are more an implementation device. So design comes from some freestyle drawing, and then you implement it with a Bézier tool to set perfect and minimal curves (the minimal is a property that is important when designing fonts). But to go from blank to design with just the curves can be brutal, yes. There are also the usual free drawing tools which allow you to draw lines freely and then approximate them automatically with curves, but that can be imprecise and murky.

The first implementations of digital fonts (before the DTP time with Adobe/Apple/Microsoft) were also using other types of curves, but Béziers won, I think because they are much more efficient to calculate, which was particularly important in the 90s (as the next step after bitmap fonts).


Right, if you were going to design with NURBS or something like that you would probably approximate them with Bézier when you deploy them.

For all the complaints that people have about PDF files my favorite is that PDF doesn't have a primitive to draw circles (generally conics) so a 'circle' in a PDF file is always some combination of Bézier curves.

One application I like for Béziers is easing curves for animations, dimming lights, etc. Unlike the 2-d drawing case I feel like I can always get the effect I want without a fight.


> it’s a bit of a tragedy that NURBS and other curve families that are more intuitive to work with haven’t caught on.

I feel like it’s even more tragic that Uniform B-splines aren’t more common, especially quadratic and cubic versions. Git rid of knots, and talk specifically about degree 2 or 3, and you don’t need a PhD in math to follow the explanation. You can explain it without the sums of sums of recursive basis functions while juggling several different indices, no need to discuss knot insertion and removal. Uniform B-splines segments have a 1:1 mapping to Bézier curves, and understanding them before diving into non-uniform curves would be so helpful and actually cover two thirds of what people need and what happens in practice.

The big problem with NURBS is that the only information you can find on them dives into unwieldy math notation and discussion about knots, there’s almost nothing out there that’s simple and quick to follow, or tailored specifically to constrained cases, people writing drawing apps and games. The material all seems to be abstract and arbitrary degree and arbitrary complex uses. I feel like NURBS is a case where it becomes clear that the notation gets in the way of understanding, it truly feels like there should be a simpler notation because the concepts are easier to grok than the math.


> it is awkward to draw things with Bézier curves

I guess? I think most designers are so used to using the pen tools and problem solving with them that they start to become intuitive after a while. There's a bit of a learning curve (pun intended), but I think once you understand how they are implemented in Adobe products, for instance, they become pretty simple.

This Bezier game is excellent practice: https://bezier.method.ac/


Béziers never become intuitive, even for professional font designers and illustrators with decades of experience. If you start paying attention you will find that almost every expert regularly makes lumpy curves with them, with lumpiness unrelated to their original artistic intentions, just an artifact of a tool that poorly matches people’s goals and expectations.

To always get “fair” curves using Bézier segments requires an extreme amount of effort, and either a very good eye and a lot of experience or some additional tooling that highlights where the lumps are.


> it is awkward to draw things with Bézier curves

Sorry for repeating my comment, but you really should check out the the interactive examples of the closed bezier curves (which could also be open). They were designed to be intuitive as the control points are on curve.

The project is is in its infancy, yet the interactive examples are working. https://rockingship.github.io/ccbc/README.html


What game was that?


Good article but I found this remark at the start interesting: "The first of these are as easy to draw as they are easy to make a computer draw. Give a computer the first and last point in the line, and BAM! straight line. No questions asked."

Ha! Of course every graphics API makes it easy, but there is much going on under the hood. (Um, do GPU's have hoods?) See "Bresenham's algorithm": https://en.wikipedia.org/wiki/Bresenham's_line_algorithm


For some reason that comment brings back memories of writing Basic on an Apple II when I was kid, where it only had “hlin” and “vlin” commands - only axis-aligned lines, no function for diagonal lines.

Yeah the API counts as a hood, I would say modern GPUs and CPUs have multiple hoods… multiple API layers… hoods under hoods. It’s hoods all the way down. :P

An interesting generalization of Bresenham is the DDA https://en.wikipedia.org/wiki/Digital_differential_analyzer_...


Sure, but bresenham's algorithm is a highly optimized form of "drawing a line" in the same way that we can write a highly optimized forward prediction algorithm for Bezier curves and it will be more work than Bresenham's algorithm for lines.

The basic "draw a line" is the incredibly simple "single lerp to get the next on-line pixel coordinate" (which for naive drawing, may be the same coordinate, of course).


Bresenham's algorithm really is all about integer division, and its applications are far broader than just drawing a line. When I was still doing a lot of CAD work Bresenham's was the proverbial Swiss Army Knife, from stepper control across five axis (including rotation axis for thread cutting) to 3D visualization and all kinds of other odds and ends.


Over the past couple of weeks I've been diving into WebGL, and even at that level of abstraction (several layers higher than the GPU itself), the incredible complexity involved in rendering stuff to the screen becomes apparent. It's truly amazing.


There is a trivial interpretation of Bezier curves that helped me to understand them:

Quadratic Bezier is just trajectory of a point with initial velocity and constant acceleration.

Cubic Bezier is just trajectory of a point with initial velocity and acceleration, and constant change of acceleration.

Direction to control points are just initial/final velocity.


An alternative would be to say: Bézier curves are parametric polynomial curves (represented in Bernstein basis rather than monomial basis).

(A function with constant nth derivative is a polynomial.)


Norman J Wildberger has a series of videos about Bézier curves (referring to them as "de Casteljau Bézier", or dCB, curves) https://www.youtube.com/watch?v=6LtMKObyKMs

He's got hundreds of videos, from elementary school subjects up to research seminars, and they usually provide interesting perspectives even for familiar subjects, since he always tries to avoid using infinite sets, irrational numbers, limits, etc. (which he "doesn't believe in")


Interesting (I guess one can call it „religious“) belief.


This video tutorial is also good: https://www.youtube.com/watch?v=aVwxzDHniEw


knew Freya's video would show up on this post! her work is pretty fantastic, lots of great bits on shaders as well!


Real good


Slightly related: Closed Continuous Bézier Curves with on-curve control-points for a Much more intuitive interaction. It is also used to fit curves into arbitrary outlines like country/region borders.

The project is heavily under construction, however the interactive examples are functional. The examples are intended for desktop, but should work with touchscreens.

https://rockingship.github.io/ccbc/README.html


Always nice to see folks enjoying the primer - if anyone runs into issues with it, feel free to head on over to https://github.com/Pomax/BezierInfo-2/issues and report your findings so we can improve things together.



So, let's say I want to implement these (or other) curves into a drawing program. How do I go about doing that? I mean to say, I want to implement a brush on canvas type interface - how do Bézier curves fit into that?

Do I collect points when mouse is down and build a curve with those points? Do I get some other path information and rasterize?

I'm trying to write my own drawing program (for fun) but given my lack of background in this I feel myself floundering.


You can use the very close relative of the Bezier, the uniform B-spline, for drawing curves, it’s a more natural fit. Yes, this way you can collect a sequence of mouse events and use them as-is as the control points of a curve. Depending on how you render your curve, in 2d, you might want a “normal” for the curve in order to rasterize a thick and/or textured stroke. You can do it easily and unambiguously by rotating the tangent (derivative) of the curve by 90 degrees. In 3d, it’s harder.

The B-spline is just a math name for a connected sequence of curve segments, setup so that the segments join nicely and so that there is a continuous “parameter” along the entire curve.

For a sketch interface, I personally prefer the quadratic B-spline to the cubic (but you can use any degree you want). The background for curves in general isn’t easy to pick up and understand quickly, but you might check out the “Chaikin” subdivision which is super simple math and equivalent to a quadratic curve.


I'd look at other programs for inspiration. Blender for example allows you to place the anchor point and then gives you the option for how many segments you want connecting the anchors. Turning the resolution up and down gives you a feel for how many subdivisions you'll need for a smooth curve.

At the very least you'll need a UI for placing the anchors and handles, but how the UI works is really subjective. Your next step is to take those anchors and desired resolution and generate a list of vertices. After that it's just an exercise in rasterization.


This is still the best resource I have come across for Bezier curves, B-splines and Nurbs:

https://pages.mtu.edu/~shene/COURSES/cs3621/NOTES/

OP's primer looks very good too though. I look forward to going throught it properly.


This post helped me so much when I was using the graphviz library. I was trying to use the layout functions in graphviz for another tool, and graphviz spits out layout in bezier curve points. I was plotting the points directly, and didn't realize I needed to interpolate the actual points of the curve. This post helped immensely.


Related, for a practical application of Bézier curves, they can be used to simulate human-like mouse movements to prevent bot detection (ie. aimbots, web scraping): https://github.com/vincentbavitz/bezmouse


Unrelated but similar, https://blog.maximeheckel.com/posts/cubic-bezier-from-math-t....

Includes hands-on examples to help understand the math behind bezier curves.



I always wonder: why just drop a link like this in? Are you trying to let people know there are previous entries with comment threads that they might be interested in, or are you trying to shame folks for not knowing it got posted in the past? Or even something else altogether?


It’s standard practice on HN for someone (often the mods) to post links to previous threads on repeat posts, especially when the previous threads are substantial.

This is not shaming in any way, it’s indexing good stuff, making it easy for people to find more information. It’s helpful to know that the posts are repeated, and is not expected that someone would know this - after all, most people here are relatively new and probably always will be (assuming the user base is growing). On occasion it also helps avoid repeat debates. I personally use the links often and I appreciate it when people collect them.


I've seen them plenty of times with a "previous discussions here" note, which makes sense, but not a lot of bare "go figure out what I meant by this" links =)


Ah, I see, that’s a fair question, especially if it’s only a link and nothing else. I don’t know if the top-of-thread comment was edited when you asked, but at least as of my response, the word “Previously” now sufficiently indicates it’s past discussions on a repost article.


just in case anyone wanted to read the previous comments


gotcha. Cheers!


I would forget Bezier and go straight to Catmull Rom. They're convertible.


Why’s that? They’re convertible but not equivalent; there’s lots of things you can do with Bézier curves that you can’t do with Catmull-Rom. Manually tweaking animation curves in a timeline is something that doesn’t work with Catmull-Rom because of the lack of control over tangents. There are several other reasons but I’m curious to hear yours.

Edit to clarify, you can convert Catmull-Rom strands to Bezier strands, but you cannot generally go the other way from Bezier to Catmull-Rom and still preserve connected segments.


Except now you gave yourself the problem of not having a curve that starts and ends at your first and last point. CR are great, but they are absolutely not a "better choice" than Bezier curves in myriad applications.


I worked a lot with different curve generating algorithms when I was working in sail CAD design. If you can, avoid Bezier curves and use Splines. Far more predictable and much easier to construct with.


Is it just me or do the sliders lose focus after the slightest change? This prevents me from dragging the slider to different values using my cursor to view the changes smoothly.


No one's reported that before so that might really just be you: please file an issue about it over on https://github.com/Pomax/BezierInfo-2/issues with some STR (and obviously os/browser/extensions information) and I can have a look.


There is a nice C++ (GPLv3+) implementation of a lot of these algorithms in Solvespace here:

https://github.com/solvespace/solvespace/blob/master/src/srf...

I'll be having a read of this to see if we can improve on some of these. In particular I've wanting to add curve-curve intersection as in section 29:

https://pomax.github.io/bezierinfo/#curveintersection

I had already considered that exact approach, but there are cases (in CAD anyway) where portions of 2 curves may exactly overlap. In that case we'd want to identify the overlapping region and split the 2 curves into 3. These special cases might seem like corner cases and they are, but they come up in practice more than I'd like.


They come up in practice a LOT actually. The challenge with curve/curve intersections boils down to tolerances. Visualize two circles with different radii, with the smaller circle inside the larger circle, that meet at a single point. When understanding those circles as primitives (centerpoint, radius) finding that intersection point is relatively trivial. However when simply thinking of these as arbitrary curves, we have a condition where those curves are getting progressively closer together, but it's really hard to tell if they exactly touch, and exactly where.

Of course at a point we'll get close enough to consider there to be some intersection, but do we get "close enough" for a single point? for a portion of each of the curves? Does the result change with the scale of the circles? Does it scale when the relative radius between the circles changes? Making those kinds of judgement calls within the algorithms is really a challenge, but makes a huge difference when building a geometry library and for usability (for other developers, and end users). Knowing your use cases may be helpful in determining what's the right approach for these situations.


>> we have a condition where those curves are getting progressively closer together, but it's really hard to tell if they exactly touch, and exactly where.

OMG different curves and surfaces becoming tangent at a point is a huge pain. It's tempting to say that it tends to happen at the ends and can be checked for as a special case, or an algorithm tweaked based on that assumption, but then someone will find a perfectly reasonable construction that results in tangency at some arbitrary place and the problem returns.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: