Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- on the topic of software rendering, im surprised how little gustavo pezzi's lectures get mentioned here on hacker news.by atan2
- Gustavo's lectures are great! I work through his Compiler lectures now and I bought the 3D renderer course too.by AlexeyBrin
- Hey! Gustavo here. Thanks for the mention. The 3D software renderer course is still one of my favorites, even though it was one of the first ones I've published. I recently re-recorded the chapter on perspective projection matrix.by gustavopezzi
- For anyone wondering, Gustavo runs https://pikuma.com/ which has a host of lectures on a variety of topics from PlayStation 1 programming to maths to triangle rasterisation.by bananaboy
- I actually submitted my first PR against this repo in forever because I found a bug in how macOS handles OpenMP. Cool article and code.by Wintermute21
- I jumped when the first image loaded on the page.. didn't expect that.by t1234s
- > I jumped when the first image loaded on the page.. didn't expect that.
mbappe'?
by mito88 - What image was that? The first image I get is a headshot.
Personally I’d have gone with a teapot as my demo but I don’t see anything shocking about the model the author chose.
by hnlmorg - That's impressive. Building a renderer from scratch sounds like one of those projects that teaches you far more than following tutorials ever could. I'll definitely check out the screenshots.by Zfyuchar
- There's basically no such thing as "bare C++" anymore. On any modern machine you are relying on piles of code. You can't just write to registers to edit vram and output video like on some 80s computer. It all happens on top of a thick stack of APIs, drivers and firmware.by smolder
- In a fit of 90s nostalgia I’ve also been going back to software rendering, though I’m doing a hybrid of 2D style CLUT banks with a more modern binned triangle and barycentric technique. Since I’m sticking to a fixed pipeline look, I’ve been amazed at just how many triangles one can push even with a fairly naive draw function.by xgkickt
- There was a software rendered game in vein of Tomb Raider 1 graphics for both DOS and Unix, but I can't remember its name. It was an exploration game, modern, a bit cyberpunkish, in 3D.by anthk
- Finally an engineering feat that's not built in Rustby espetro
- I wish we could have just one of these tutorials properly cover the concern of triangle clipping. This is the part that I struggle with the most in a software renderer. If you are going to be building a practical one, this is something you will eventually have to deal with, even for super basic scenes. Any time geometry intersects the view frustum you need to clip those triangles.by bob1029
- My renderer attempts always got stuck on the "should implement clipping" phase too, until I finally bit the bullet and managed to write a working one without much effort, independently "rediscovering" the Sutherland–Hodgman algorithm [1] as I found out later (googling it beforehand would've been cheating, of course).
The algorithm itself is fairly straightforward and intuitive, I think the biggest mental block is the weirdness of the projective space and working with homogeneous coordinates (actually the only frustum plane that you have to clip against in P₃(ℝ) is the front plane, the rest could be clipped after the perspective division, but no reason not to do it all at the same time while you're at it). The plane equations in the clip space are super simple, basically the six equations of the form ax + by + cz = w simplify to
Meaning, for example, that if the x coordinate of your vertex is greater than the w coordinate, that vertex is outside the right clipping plane. The Sutherland–Hodgman itself goes something like this:x = ±w y = ±w z = ±w.
Then you just call this for all the planes so that the output of one call becomes the input for the next call! The end result of this process is a convex polygon (of at most nine vertices for a triangle against six planes), which can be trivially triangulated. You can make the whole process faster by precomputing so-called outcodes which allow you to avoid clipping triangles known to be entirely outside at last one plane, or entirely inside every plane.# Returns true if point is inside the half-space defined by plane def point_inside_plane(point, plane) -> bool: # single dot product, can be further simplified # Returns t such that the edge (p1, p2) intersects plane at lerp(t, p1, p2) def edge_intersect_plane(edge: (Point, Point), plane) -> float: # single dot product, can be further simplified # Given the vertices of a simple polygon and a plane, # returns the part of the polygon fully inside the plane def clip_against_plane(poly: [Vertex], plane): let result: [Vertex] = [] let [(v_1, v_2), (v_2, v_3), ..., (v_n, v_1)] = poly.edges() for each (v_i, v_j) of the edges: let i_inside = point_inside_plane(v_i, plane) let j_inside = point_inside_plane(n_j, plane) if i_inside and j_inside: # v_j will be pushed on the next iteration! result.push(v_i) else if not i_inside and not j_inside: pass # Nothing to do! else: # One is inside, the other is not, we have to clip let t = edge_intersect_plane((v_i.pos, v_j.pos), plane) # Synthetize a new vertex straddling the plane let v_new = Vertex( pos = lerp(t, v_i.pos, v_j.pos), # For each vertex attribute attrib = lerp(t, v_i.attrib, v_j.attrib) ) if i_inside: result.push(v_i); result.push(v_new) # discard v_j else: result.push(v_new); result.push(v_j) # discard v_i return result[1]: I. Sutherland and G. Hodgman. 1974. "Reentrant polygon clipping." Communications of the ACM, Volume 17, Issue. Available: https://dl.acm.org/doi/10.1145/360767.360802
by Sharlin - You only need to clip triangles is you're worried about attribute interpolation for very large triangles. There's two ways to handle this: (1) discard (fast but not a great user experience); or, (2) primitive synthesis. Just frustum clipping is enabled by point picking in the local tile. Primitive synthesis requires some FP kung fu; but, is easiest done in barycentric space against a reverse transformed clipping rectangle. This lets you carefully control clip rounding error using either doubles or (better) fixed point. Abrash likes to use integer fixed point, but that is historical — modern fixed point can be handled with careful control of the fp unit in the mantissa. The major issue is regenerating the Z and the 1/Z values for the new vertices of the synthesized primitives. Everything else should flow down the pipe naturally, assuming a deferred attribute synthesis rasterizer.
There are examples in the open source version of my rasterizer: OpenSWR.org.
by thechao - I have a whole chapter on that! https://gabrielgambetta.com/computer-graphics-from-scratch/1...by ggambetta
- Is the Foley/Van Dam book still a go to resource for this? It seems it was updated in 2013, but, honestly, I’m more familiar with the ‘82 edition that was dedicated to 2D.
Back in the day, it was The Book for computer graphics.
by whartung - I also learnt with the second edition, I own the last one from 2013, it is alright.
The languages have evolved across editions, from Pascal, to C, to C and C++, and a bit of C# as well on the last one.
Naturally it misses on several new concepts, however I would assert it has quite valuable content.
by pjmlp - I haven't looked at my copy in years. To me, the book is a peculiar encyclopedia with some historical importance.
I found the course note from this github to be a good refresher on the subject. While the repo source code style is distasteful to me and their old-school rasteriser in the course is too naive and unoptimal, it's still a better read than Foley I'd assume :)
by momocowcow - This resource, along with Mathematics for Computer Graphics by John Vince [1], was truly indispensable when I wrote my own software renderer [2]. This was long before LLMs, so the whole process took me at least a couple months - most of it trying to wrap my head around math behind computer graphics and tracking down C segmentation faults. Fun times.
[1]: https://www.amazon.co.uk/Mathematics-Computer-Graphics-John-...
by nkanaev - How many hours a day over the couple months?by mentos
- Is the source of yours public anywhere? I'd like to take a look.by DatCodeMania
- I went through this a few months ago in Rust. I wrote all the code by hand, no LLMs. Then I went ahead and added a small "game" on top, plus some special effects like pixelization shaders and chromatic aberration at the edge of a flashlight.
https://github.com/kshitijl/tinyrenderer-rs
if anyone is interested! The repo has lots and lots of in-progress screenshots so you can see the renderer come to life, plus all the hilarious visual bugs along the way.
I learned a lot! My biggest lesson, other than the specifics of how rendering works, was that modern CPUs are really fast: a single-threaded CPU renderer can definitely run an interactive 3D game with some fancy special effects.
- Why does it pull in wgpu if it's a software renderer?by 0x1ceb00da