Putting the triangle together
This last step is more of a formality. We can now rasterize triangles! The only thing missing is putting this together with the rest of the pipeline.
As this does not really involve anything complicated, we will just look at the relevant code.
The functions for computing the edge functions and the triangle rasterization of the last steps are integrated into the rasterizer as signed_tri_area_doubled and rasterize_triangle, the only actual change being writing out a color with the write_fragment method instead of directly setting the pixel.
Otherwise, we extend the draw method, so it will go through a list of triangles and calls a precessing method process_triangle for each of them. The process_triangle itself will just call our new rasterize_triangle method for now. This is basically the same thing we did with the lines.
What else can we do with triangle rasterization?
As you might expect, our algorithm isn't the fastest. There are a lot of areas, that we could explore, some even mentioned in the initially mentioned early paper by Juan Pineda [1], but a lot of other follow similar ideas.
Basically we should ask ourselves: Isn't it wasteful, to check every pixel in the triangle bounding rectangle, if it belongs inside of it? The worst case would be a very thin triangle oriented along the diagonal of the screen. In that case we would need to check the entire screen, but more or less only the diagonal would actually contain any pixels that we care about.
So, how about some other approaches. We could rasterize the sides and then move from left to right. We could go down the center line and procced left and right from that, as needed. We could split the rectangle into subrectangles and process them independently.
As you can see, there are many ways to go about it just in that direction.
Another opportunity is the actual work of computation. To keep the code simple, we basically just "optimized" calculating the total triangle area once, but we can do a lot more. Very similarly to the line drawing algorithm, the edge functions can be computed incrementally. If we replace in the formula with a point , we will see that , where is some very easy to compete value based on constants of the triangle and (try it out!). So while the edge functions are not super computionally expensive, if we can replace the formula in each loop by just, for example, one addition and multiplication, we might save a lot when we also draw a lot of triangles/pixels. There are of course other optimizations to do in that regard.
And of course, although not that great of an option in JavaScript, you could try to compute a lot of things in parallel.
Next up, we will implement a more general clipping routine, that can clip a triangle at an arbitrary plane.
Juan Pineda. 1988. A parallel algorithm for polygon rasterization. In Proceedings of the 15th annual conference on Computer graphics and interactive techniques (SIGGRAPH '88). Association for Computing Machinery, New York, NY, USA, 17–20. https://doi.org/10.1145/54852.378457 ↩︎