How much boilerplate code you need to write a ray-tracer?
This article is very good!  It covers many beautiful techniques and has many beautiful images.  However, I would quibble with the title; if you want to know how much boilerplate code you need to write a ray-tracer, you will not find the answer in it.<p>I wrote the following programs in an attempt to get a better answer to that question.<p><a href="http://canonical.org/~kragen/sw/aspmisc/my-very-first-raytracer.html" rel="nofollow">http://canonical.org/~kragen/sw/aspmisc/my-very-first-raytra...</a> four pages of C<p><a href="http://canonical.org/~kragen/sw/dev3/raytracer1k.clj" rel="nofollow">http://canonical.org/~kragen/sw/dev3/raytracer1k.clj</a> 1K of Clojure, condensed down from<p><a href="http://canonical.org/~kragen/sw/dev3/circle.clj" rel="nofollow">http://canonical.org/~kragen/sw/dev3/circle.clj</a> a page of unfactored but not obfuscated Clojure, translated into<p><a href="http://canonical.org/~kragen/sw/dev3/circle.js" rel="nofollow">http://canonical.org/~kragen/sw/dev3/circle.js</a> a page of JS in node.js<p><a href="https://gitlab.com/kragen/bubbleos/blob/master/yeso/sdf.lua" rel="nofollow">https://gitlab.com/kragen/bubbleos/blob/master/yeso/sdf.lua</a> a page of Lua using signed distance function raymarching that runs in real time at a lousy framerate; to run it, git clone the repo, install the prerequisites listed in the README, and run `make` in the yeso directory, before running sdf.lua.<p>But none of these can load triangle meshes, render caustics, render area light sources, average multiple samples, do bidirectional rendering, etc.<p>Reznik says, "A lot of projects using something like PPM file format, which is very simple, but in the end, you need to write ... extra code for this simplicity (like tone mapping, converting from floating point values to uint8, etc.)," but the amount of extra code required is really <i>very</i> minimal:<p><pre><code>    /* PPM P6 file format; see <http://netpbm.sourceforge.net/doc/ppm.html> */

    static void
    output_header(int ww, int hh)
    { printf("P6\n%d %d\n255\n", ww, hh); }

    static unsigned char
    byte(double dd) { return dd > 1 ? 255 : dd < 0 ? 0 : dd * 255 + 0.5; }

    static void
    encode_color(color co)
    { putchar(byte(co.x)); putchar(byte(co.y)); putchar(byte(co.z)); }
</code></pre>
But on some platforms you don't need even that much; my Clojure raytracer[s] just use[s] javax.imageio.ImageIO/write to encode a JPEG.  (Admittedly, that one in particular cheats pretty shamelessly on tone mapping!)