Nvidia put out a really interesting article all the way back in 2007 about rendering vector graphics on the GPU: https://developer.nvidia.com/gpugems/gpugems3/part-iv-image-effects/chapter-25-rendering-vector-art-gpu
They have a pretty simple solution to a problem I've been having with my implementation, which is how to handle cases where curves' convex hulls overlap:
Just don't render curves whose hulls overlap in the first place
I need to remind myself that constraints are sometimes necessary. I don't need to be able to render any arbitrary arrangement of control points like I was trying to. I can get away with rendering only what I deem sensible.
The article is an interesting read, and I think I can use it to improve my approach in a couple of places: This article was written several years before tessellation shaders were really a thing, so it's calculating the boundary of the curves in the pixel (fragment) shader. This is pretty expensive because you need to calculate the boundary once for every pixel inside the curve's area.
I think the tessellation evaluation shader is a more suitable place for the boundary calculation. This way, you only need to calculate the boundary once for each vertex on the curve and we don't need to do any substantial work in the fragment shader. I'm doing this in my current implementation, but I want to pinch the way the article is constructing the shapes it renders:
We're both constructing a "solid" part of the shape based on the bezier curves that make up the surface, but I'm triangulating a shape based only on the start and end points of each curve and deforming one or more edges of those triangles into a curve.
The article, on the other hand, forms the solid part using a combination of the start and end points of the curve, as well as the innermost control points and renders the curved parts entirely separate from the solid parts. That way the curves are entirely separate and there's no risk of overlap between the curves and the solid portion of the shape - a problem I was running into before.
This approach will let me tessellate everything as quads, too. Which is much nicer than tessellating triangles and having to deal with barycentric coordinates. I will have to do this as two separate render passes, one for the solid shape and one for the curve, but that's a tradeoff I'm happy to make if it means it's simpler to implement and will actually work.
I draw, code, and make memes sometimes.