[HN Gopher] GPU ray tracing tutorial - 10 articles
___________________________________________________________________
GPU ray tracing tutorial - 10 articles
Author : henkie_bk5
Score : 133 points
Date : 2022-06-15 17:48 UTC (5 hours ago)
(HTM) web link (jacco.ompf2.com)
(TXT) w3m dump (jacco.ompf2.com)
| dahart wrote:
| This is awesome! I've been wanting to see what it would look like
| in OpenCL.
|
| Side note, I hope we graduate away from the terms BLAS & TLAS
| soon. They make the most sense for a strictly 2-level hierarchy,
| but the power of ray tracing comes from multi-level, where "top"
| and "bottom" are ambiguous. This is why OptiX uses IAS (Instance
| AS) and GAS (Geometry AS) instead.
| jbikker wrote:
| Well if you have more than 2 levels you can always collapse,
| which is the preferred solution. Just walk the scenegraph, and
| flatten the matrices. Now you're left with an array of BLASses,
| each with their final matrix.
|
| RTX has hardware support for this flattened structure only;
| OptiX will become significantly slower if you force it to have
| more levels.
| dahart wrote:
| Yes, very true. Or at least you can usually collapse. Memory
| is the issue, and collapsing multilevel doesn't always fit.
|
| There is some cost in the current hardware to multi-level
| traversal, that's true. But still top & bottom terminology
| isn't future-proof, doesn't translate to CPU, and we might
| not be limited to 2-level GPU traversal forever. More to the
| point perhaps is that "top" and "bottom" aren't words that
| describe the function. It'd be better to have terms that say
| what it does rather than where to find it, right?
|
| Full disclosure, I work on OptiX. (But to be clear I
| literally have no idea if/when we might see multilevel
| traversal in hardware. I just happen to be in favor of seeing
| it someday, and if/when it does, TLAS and BLAS will become
| more awkward or get replaced.)
| henkie_bk5 wrote:
| The last article of the series on BVH construction, ray tracing
| and GPU ray tracing (using OpenCL) is now complete: 10 articles
| cover the basics as well as advanced GPGPU topics.
| jazzyjackson wrote:
| I got rejected by the server so here's an archive
|
| https://web.archive.org/web/20220615174927/https://jacco.omp...
| skratlo wrote:
| I find their C++ style particularly appalling.
| jazzyjackson wrote:
| It's just ANSI style without extra newlines, a matter of taste
| I suppose.
| alar44 wrote:
| It really is hideous. I think they skipped newlines to keep
| line count as low as possible. /Eyeroll
| rollulus wrote:
| Based on the name of the author, Jacco Bikker, I can blindly
| recommend this. He has decades of experience and knows how to
| combine modern computer graphics algorithms from the academic
| world with real world low level optimizations and a sauce of
| magic to create state of the art ray tracers.
|
| Disclaimer: my master thesis work was part of his PhD
| dissertation. As a teenager I read his articles on flipCode and
| due to sheer coincidence he ended up as my thesis supervisor.
| jeroenhd wrote:
| Back when I took the author's course on computer graphics in
| Utrecht (took me a few times to pass it, by no fault of his) I
| thought it was very strange that the course started out with ray
| tracing rather than traditional GPU rendering. After all, when
| you think graphics, you think OpenGL/Vulkan/DirectX, right?
|
| Only after having to implement both types of renderer do you
| really get an appreciation of how elegant ray tracing really is
| in comparison. The basic ray tracer from this tutorial clocks in
| less than 200 lines of C++ excluding the headers! Then there are
| optimisations like BVHs/BLAS/TLAS which are all so simple to
| think and reason about compared to the inner workings of a GPU
| rendering pipeline.
|
| I should find the time to go through this guide again and find
| out how I can get more performance out of my old ray tracer now
| that I've grown a few years older and wiser.
|
| This tutorial is more about optimizing a ray tracer than writing
| one from scratch. If you're looking to learn the basics, I
| recommend reading through the tutorial the same author wrote
| eighteen years ago [1]. It covers the more basic concepts of a
| ray tracer without telling you exactly what to copy paste unless
| you "cheat" and download the code archive, which is a great way
| of teaching concepts to programmers in my opinion, as it gives
| you the opportunity to think for yourself.
|
| With modern C++ you'd probably want to write your code a bit
| different (VC++ 6 wasn't the best C++ even at its time) and the
| compute limitations at the time are dwarfed by even your average
| integrated GPU, but the core concepts haven't changed.
|
| [1]:
| https://www.flipcode.com/archives/Raytracing_Topics_Techniqu...
| (I needed to fix the encoding for the page in Firefox to get the
| math to show up right)
| kragen wrote:
| I've written several raytracers and rasterizers that are
| smaller than 200 lines of C++, though quite likely they're
| worse pedagogically than Jacco's (slashdotted, but available at
| https://web.archive.org/web/20220615174927/https://jacco.omp...
| ) tutorial, and they also don't illustrate useful
| optimizations. Hopefully, what mine lack in cluefulness and
| performance they make up in breadth, diversity, and brevity:
| they are written in C, C++, Python, JS, Lua, and Clojure, with
| output to JPEG files, PPM files, X11, the Linux framebuffer,
| ASCII art, Unicode Braille art, and the browser <canvas>.
|
| * http://canonical.org/~kragen/sw/aspmisc/my-very-first-
| raytra... 184 lines of C, including vector arithmetic, input
| parsing, and PPM output. I'm not sure what you mean by
| "excluding the headers" -- this one doesn't have any headers of
| its own (why would a 200-line program have headers of its own?
| Are you on a Commodore 64 such that the compilation time for
| 200 lines of code is so high that you need separate
| compilation?) but it #includes math.h, stdio.h, stdlib.h, and
| string.h, which total almost 1800 lines of code on my machine
| and presumably 15x that by the time you count their transitive
| includes.
|
| * http://canonical.org/~kragen/sw/dev3/circle.clj 39 lines of
| Clojure, including the model, which is a single sphere; it uses
| java.awt.image for JPEG output. About half of the code is
| implementing basic vector math by hand. A minified version is
| under 1K: http://canonical.org/~kragen/sw/dev3/raytracer1k.clj
|
| * https://gitlab.com/kragen/bubbleos/blob/master/yeso/sdf.lua
| 51 lines of Lua for an SDF raymarcher including animation, the
| model itself, and live graphical output. SDFs are cool because
| it's often easier to write an SDF for some shape than to write
| code to evaluate the intersection of an arbitrary ray with it.
| This one runs either in X-Windows, on the Linux framebuffer, or
| in an unfinished windowing system I wrote called Wercam.
|
| I feel like basic raytracing _is_ a little simpler than basic
| rasterizing, but I don 't think the difference is hugely
| dramatic:
|
| * http://canonical.org/~kragen/sw/torus is a basic rasterizer
| in 261 lines of JS, which is larger than the three raytracers I
| mentioned above, but about 60% of that is 3-D modeling rather
| than rendering, and another 5% or so is DOM manipulation. On
| the other hand, one of the great things about raytracing is
| that if you want to raytrace a sphere or torus or metaballs or
| whatever, you don't need to reduce them to a huge pile of
| triangles; you can just write code to evaluate their surface
| normals and intersect a ray with them, and you're done.
|
| * http://canonical.org/~kragen/sw/netbook-misc-
| devel/rotcube.p... The smallest I've been able to get a basic
| rasterizer down to, 15 lines of Python, just rotating a point
| cloud, without polygons. You might argue that rotating a point
| cloud is stupid because it doesn't look very 3-D, but Andy
| Sloane's donut.c does okay by just applying Lambertian shading
| to the points in the point cloud:
| https://www.a1k0n.net/2011/07/20/donut-math.html.
|
| * http://canonical.org/~kragen/sw/dev3/rotcube.cpp in C++
| rotating an ASCII-art pointcloud is 41 lines; and
|
| * http://canonical.org/~kragen/sw/dev3/braillecube.py with
| wireframes in Braille Unicode art it's 24 lines of Python, but
| that's sort of cheating because it imports a Braille Unicode
| art library I wrote that's another 64 lines of Python.
| Recording at https://asciinema.org/a/390271.
|
| So I think that the core of either a (polygon!) rasterizer or a
| raytracer, without optimizations, is only about 20 lines of
| code if your ecosystem provides you with the stuff around the
| edges: graphical display (or image file output), model input,
| linear algebra, color arithmetic. If you have to implement one
| or more of those four things yourself, it's likely to be as big
| as the core rasterizer or raytracer code.
|
| For a polygon rasterizer, it's something like:
| tpoints = [camera_transform @ point for point in points]
| framebuffer.fill(background) painter = lambda poly:
| min(tpoints[i].z for i in poly.v) for poly in
| sorted(polys, key=painter)): normal =
| tpoints[poly.normal] if normal.z > 1: # backface
| removal, technically an optimization continue
| p2d = [(p.x / p.z, p.y / p.z) for p in [tpoints[i] for i in
| poly.v]] lambert = normal.dot(light_direction)
| color = min(white, max(black, lambert * light_color + ambient))
| framebuffer.fill_poly(p2d, color)
|
| While a Whitted-style raytracer is more like this:
| for yy in range(framebuffer.height): for xx in
| range(framebuffer.width): ray = vec3(xx, yy,
| 1).normalize() hits = [(o, o.intersect(ray))
| for o in objects] hits = [(o, o.p) for o, p in
| hits if p is not None] if hits:
| o, p = min(((o, p) for o, p in hits),
| key=lambda t: t[1].z) # nearest
| framebuffer[xx, yy] = o.shade(p) else:
| framebuffer[xx, yy] = background
|
| But this presumes you've previously transformed the objects
| into camera space, it leaves .intersect and .shade to be
| defined (potentially separately for each object), and it
| doesn't do the neat recursive ray-tracing thing that gives you
| those awesome reflections. For a sphere, intersection is about
| 7 lines of code evaluating the quadratic formula (which you can
| cut to 3 if you have a quadratic-equation solver in your
| library), and basic Lambertian shading is about the same as in
| the rasterizer; your surface normal is (p -
| sphere.center).normalize().
|
| The core of my Lua SDF raymarcher I linked above is simpler
| than that. Here I'm using the iteration count as part of the
| shading function to fake ambient occlusion, which is pretty
| bogus because it depends on where the camera is in a totally
| non-physically-based way, but it looks pretty 3-D.
| local function torus(p, c, r1, r2) return
| length2(length2(p[1]-c[1], p[3]-c[3]) - r1, p[2]-c[2]) - r2
| end local function render_pixel(x, y, palette)
| local p, n = {x,y,1} -- near clipping plane: z=1
| local q = normalize(p) -- ray direction
| for i = 0, 255 do n = i local r =
| scene_signed_distance_function(p) p = add(p,
| mul(r, q)) if p[3] > 10 then return
| palette(0) end -- far clipping plane if r < 0.02
| then break end end return
| palette(max(0, min(255, 48 - n -
| math.floor(p[1]*-16+p[2]*32)))) end
|
| I know what BVHs are, even though I've never implemented them.
| I'm so clueless that I didn't know what BLAS and TLAS are, but
| Jacco explains them in part 6 of his series: https://web.archiv
| e.org/web/20220605013040/https://jacco.omp....
| pengaru wrote:
| Years ago I read the flipcode article you linked and wrote a
| raytracer as an introductory exercise to 3D graphics. I even
| ended up reaching out to Jacco afterwards via linkedin to thank
| him for the making the tutorial, to my surprise he replied.
|
| It does seem like an excellent way to get introduced to 3D
| graphics. All the fully-featured triangle rasterizers are a
| huge pile of complexity. Especially if you're going hardware-
| accelerated and will also have the burden of navigating
| existing platform-specific GPU APIs.
|
| There's something to be said for just writing boring CPU-based
| code in your favorite language and getting to focus on the
| actual subject being explored.
| jazzyjackson wrote:
| Looks like a great resource.
|
| I was about to ask how you fixed the page encoding but figured
| it out for safari, just needed to click View > Text Encoding >
| ISO Latin 1
| pixelpoet wrote:
| Lotta Dutch guys in the comments :)
|
| I wrote similar stuff about ray tracing for learning sort of
| recently here: https://news.ycombinator.com/item?id=30715009
| yohann32 wrote:
| Fantastic, thanks!
| chunkyks wrote:
| This feels like an opportunity to link my own, much sillier,
| raytracer: https://github.com/chunky/sqlraytracer
| patoroco wrote:
| The file has disappeared :(
| joshenders wrote:
| 403 from Europe. Cool GDPR policy.
| matttb wrote:
| It's also 403 from NA, don't think it has anything to do with
| GDPR. This comment has an archived link:
| https://news.ycombinator.com/item?id=31759691
___________________________________________________________________
(page generated 2022-06-15 23:00 UTC)