Hacker News new | past | comments | ask | show | jobs | submit login
How OpenGL works: software renderer in 500 lines of code (github.com/ssloy)
363 points by gregorymichael on March 11, 2016 | hide | past | favorite | 36 comments



This is great and so concise, but I'm surprised that the author didn't implement OpenGL's interface (obviously not all of it), if the goal is to show how OpenGL works.

Another good example of this is Trenki's software renderer for the GPX2[1], which implements a shader architecture if memory serves. I haven't looked at it for many years, but I remember it being a useful resource when learning this stuff.

Other useful resources are, of course, Michael Abrash's Graphics Programming Black Book[2] (despite it's age, is still a great read filled with useful information), and for a really deep dive into the graphic's pipeline, ryg's (of Farbrausch fame) A Trip Through the Graphics Pipeline[3].

[1] http://www.trenki.net/content/view/18/38/

[2] https://github.com/jagregory/abrash-black-book

[3] https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-...


It turns out that Trenki implemented the OpenGL ES-CL 1.0 interface on top of his software renderer (link [1] above), which should serve as an even better example of how OpenGL (may) work.

http://www.trenki.net/content/view/39/48/


I wrote a software implementation of OpenGL with the only goal of being able to play Quake3 using it. I can vouch that it is an amazing learning experience. The tutorial here doesnt seem to aproach the issues of performance however, which really are another learning experience entirely.


Holy crap. If you could reimplement OpenGL you should be able to buy a video card. I think I had a tnt2 Ultra back then.


"being able to play quak 2" as a goal for validation of effort and to have something concrete to strive for is completely different than "none of my software or hardware on my system can play quake 2", and I suspect grandparent meant the former and not the latter.


Besides cmrx64's answer: Have you considered the possibility that 8bitpimp comes from a country where programmers are paid much worse or has a job that is paid badly but one still has good reasons to take it (say, graduate student)?


The title is a bit misleading, this is boilerplate code for a graphics programming course and it hasn't got much to do with OpenGL.

The articles describing the operation are much more interesting than the code itself.

It's just an inefficient triangle rasterizer. All it does is loop over the pixels in a rectangle covering a triangle, and for each pixel inside it calls a "shader" function. All the beef is in these 40 lines [0].

I don't know how they've done the texturing in all those pretty pictures (it's in the "shaders", not included here), but they don't calculate the partial derivatives required for correct, mipmapped texturing. Simple non-mipmapped perspective correct texture mapping can be computed in the shaders, with the usual caveats.

OpenGL is much more than a rasterizer, there's texturing, depth-stencil operations, blending, compute shaders and efficient memory management.

[0] https://github.com/ssloy/tinyrenderer/blob/master/our_gl.cpp...

edit: Someone in reddit pointed out that this is a translation of a Russian language course. The original Russian version looks to be a bit longer than the English translation (but I don't read Russian, so I can't tell if it is better): https://habrahabr.ru/post/249467/


You need to look through the short course notes in the wiki of the page to understand the full quality of this repository.


Yes, I did and that's much more interesting than the code itself. But the title is still misleading and emphasizes the code, which isn't terribly spectacular.


If it's looked purely from educational point of view it's quite hard to find graphics code that is this clear and concise.

The author modifies this short code to implement various shading techniques with code that is as pithy and understandable as any.

You have to recall that 40 years ago even texture mapping was a scientific publication quality material.

This code makes several non-obvious things obvious - and simple! I don't think that's a light achievement.


Let me cite one thing:

https://github.com/ssloy/tinyrenderer/wiki/Lesson-6:-Shaders...

"Recall that all my source code here is meant to be compared with yours. Do not use my code, write your own. I am a bad programmer."

If you want to improve the text, the wiki is open. If you want to improve the source code, fork -> code -> pull request


> It's just an inefficient triangle rasterizer. All it does is loop over the pixels in a rectangle covering a triangle, and for each pixel inside it calls a "shader" function.

99% of programmers without graphics training would not come up with the barycentric coordinates solution when asked how to draw triangles (including me, before I learned about it). Even if the code were nothing but that, it'd be extremely educational.

The point of this course is obviously not to teach graphics gurus how mipmapping or anisotropy or whatever works. That would be an interesting series of lessons (albeit one with a much narrower audience), but it's not what this tutorial is about.

Nobody complains that showing absolute beginners their first "hello world" program isn't valuable because they aren't teaching them about Unix file descriptors or the concept of a syscall.


Jeez. This repo clearly isn't for someone like you, it would be much more educational for someone who doesn't know much about how this stuff works under the hood.

Creating a dead-simple software rasterizer goes a long way toward improving one's understanding of how apis like OpenGL and DirectX work and how to use them.


Wov, this is so elegant, short and sweet. It's the most beautiful code I've seen in a while - because it's pithy, to the point, but yet retains enough critical detail to be educationally valid. Thanks for sharing.


I remember once I needed to macro up a software that needed an X server with OpenGL to run. (Like really dirtily hack it up, with xmacro and stuff like that). I wish I could set up a headless X server with a dummy OpenGL renderer (witch doesn't actually render anything), so it doesn't bottleneck on rendering that isn't used anyway. I guess it's even easier to write such and OpenGL implementation.

edit: Now I see it doesn't implement the OpenGL API though, the goals are obviously different.


Mesa has an offscreen rendering implementation that allows you to do OpenGL without an X server :

http://www.mesa3d.org/osmesa.html


I've done this with Mesa. Another way to is to run Xvfb and connect to it via x11vnc, or your xmacro system.


Related but more efficient (includes a rasterizer) :

https://fgiesen.wordpress.com/2013/02/17/optimizing-sw-occlu...


I just went through the lessons and all the code compiled and worked as expected. Nice and simple. As things should be.

Thank you for posting this online.


Stanford's past notes on polygon rasterization are interesting for historical background and algorithmic elegance: http://www.graphics.stanford.edu/courses/cs248-98-fall/Lectu...

Edit: Also this https://graphics.stanford.edu/courses/cs248-08/scan/scan1.ht...


https://github.com/ssloy/tinyrenderer/blob/master/geometry.c...

What's going on there with the template<> template<> ?


The struct vec takes a template parameter T, and it's constructor takes a different template parameter U. Therefore, you must specify both template directives when defining the constructor; one for the class type, and one for the constructor's argument.


Edit: re-wording this reply.

I guess what surprised me is I would almost expect it to look something like this...

template <> vec<3,int> ::vec(template <> const vec<3,float> &v) : x(int(v.x+.5f)),y(int(v.y+.5f)),z(int(v.z+.5f)) {}

I can tell that is silly but still.


If anyone has a link that shows the Vulkan equivalent (e.g. how pipeline states might be implemented, etc.) I would really appreciate it.

In particular, I'm very curious how tile-based deferred rendering wound interact (positively!) with a Vulkan software rendering implementation by keeping all tile buffers for a render pass in the on-chip cache of a modern Intel CPU. It seems like Vulkan provides a better API for a software rendering than OpenGL for that reason, and I'd like to see that confirmed one way or the other.


OpenGL is partly these widely available graphics algorithms. Thank you for explaining them so well here. OpenGL also has a particular architecture that provides concurrency and extensibility among other things. If we are talking about OpenGL specifically vs other Rendering Engines, then it would be good to explain the architecture to help folks understand the reasons why OpenGL is so widely used.


Will this teach you how shader-based OpenGL works or the older fixed function pipeline rendering method?


"OpenGL" is a bit of a misnomer here, there's nothing directly related to OpenGL. This will not teach you how opengl works, but is an example of a software rasterizer. Knowing how that works will help you understand what is going on under the hood of your graphics API.

This renderer does do lighting per-fragment, so it's more akin to the newer shader-based OpenGL.


If you look at main.cpp the vertex and framgment stages are abstracted via IShader, which also handles passing data between them. This emulates the programmable pipeline.


It will give the educational toy-analogue to a modern programmable pipeline by using C++ code which is more or less isomorphic to shader based OpenGL (or DirectX).


I would love a section on anti-aliasing. It seems to be the big thing missing.


That's probably because OpenGL doesn't do antialiasing by default. When it does it, it does it by rendering everything at a larger scale and downscaling it (well, actually MSAA allows the GL to avoid having to do this to everything, and only do it for some buffers)

FXAA and similar antialiasing algorithms fake it as a post process effect.


> (well, actually MSAA allows the GL to avoid having to do this to everything, and only do it for some buffers)

MSAA is faster than supersampling because the GPU generates subsample coverage but doesn't individually shade each subsample. And, this is absolutely critical, there is a compression scheme for depth and color transmission between the DRAM and texture cache which is a massive bandwidth optimization in the common case where a sample tile (usually 8x8, which for 4x MSAA corresponds to only 4x4 pixels) is covered by only one or two triangles.


This looks amazing, I wish it was in C, but I will check it out.




Reposts are ok if a story hasn't had significant attention yet.

https://news.ycombinator.com/newsfaq.html




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: