I’ve been curious why smooth, textured curves were never a thing in graphics. Usually just polygons, or curves made out of polygons. After I saw this video on bezier curves, https://www.youtube.com/watch?v=aVwxzDHniEw thought I had enough tools to figure out why for myself. The video mentions two major difficulties when working with them: It’s hard to solve cubic polynomials, and estimating distance along a bezier curve isn’t precise.
If your goal is texturing them, it turns out you don’t even need to estimate distance. For any 2 bezier curves, they all share a start t value of 0 and an end t value of 1. You just have to scale up whatever t value you’re on to the height of your texture and draw your tline(), and it looks great!
The inability to solve cubic polynomials was tricky. Stack overflow has methods for drawing curves. I can’t quite figure them out, but they appear too slow for pico 8 and take a bit of space. Originally, I would just guess a T value and see if it was one pixel away, and go to the next one. Then I saw this video on newton's method https://www.youtube.com/watch?v=hHeq-SB8uVg
Which still uses guessing, but no checking and guessing again. And, if your first guess is close enough, you don’t even need to have a guess loop! I tried to put something together for that. Wowzers, you have to be really careful on how you approach +/- infinity. I had to precompute all the noteworthy points (the 2 local extrema, and the point in between) Newton's method acts up in areas of low velocity, so, I always approach the local extrema from t0, t1, or the time in between the extrema. (unless the point in between is starting to become a point of low velocity) When this cubic bezier function works, it’s such a nice smooth curve. I have it up on demo slide 2.
Picture generated in google using this equation: x-(393 x^3 +-552x^2+252x-39)/(3393x^2 + 2-552*x+252)
You can see when guesses start to go haywire. Newton's method is very delicate but very powerful for this sort of application
I also put together a quadratic(t^2) bezier function to compare with the cubic(t^3) one :
- A cubic function forming an “S” shaped curve is faster than 2 “C” shaped quadratics glued together making an S shape, but…
- There is now a whole lot of setup code for the cubic function, making it as long or longer than the solutions on stack overflow.
- The cubic bezier still uses a bit more of the cpu when zoomed out, but the quadratic scales down nicely. I think I would like to play games with several cool looping structures in the distance
- Glitches remain in the cubic one. Possibly solved by using quadratic bezier functions inside of it.
I think I will shelve the Cubic bezier for now. The Quadratic using Newton's method is nice, compact and fast, and is mostly functional.
The next step is to figure out how to rasterize it quickly. Which will be challenging with these angled tlines. Right now this demo runs at 30fps because I draw a tline at every pixel change. I hope it could be efficient enough to have a super fast racing game at 60 fps. But, I’m getting burnt out working on this. I think I’ll take a step away for a while.
The step after that is projection. From what I understand about 3d graphics, all one would have to do is project the 2 3d quadratic beziers (their 4 start and end points, and 2 control points), and one should, in theory, have a splendid textured curve in 3d space!
The demo on slide 1 uses some mode 7 type tricks to make it look like the texture is moving and going into the distance. If anyone wants to use a texture in a more standard way, I put in the function draw_textured_quad_bez() at the end (and quad_bezier_newton() above it) that accepts 6 screen control points and map tiles x,y + width/height in tiles. It mostly works pretty well! A sample is on demo slide 3.
TL;DR curved polygons?
[Please log in to post a comment]