[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)