Raytracing in One Weekend (2016)
raytracing.github.io
raytracing.github.io
Also, PBR is getting a fourth edition this year that goes into fully GPU rendering—it's a great time to start learning about pathtracing!
*Rayrender Github: https://www.github.com/tylermorganwall/rayrender
Website/Docs: https://www.rayrender.net
Computer Graphics from Scratch: https://www.gabrielgambetta.com/computer-graphics-from-scrat...
The tiny{raytracer,renderer,kaboom} series: https://github.com/ssloy/tinyraytracer & https://github.com/ssloy/tinyrenderer & https://github.com/ssloy/tinykaboom
Ray tracing a tiny procedural planet: https://casual-effects.com/research/McGuire2019ProcGen/McGui... with the video on https://youtu.be/JvfjYuz7q4I
If you don't know Trig... you'll have to brush up on your math. But fundamentally, you project rays, you calculate if those rays hit an object (and if so, which object is "in front", and therefore hit first). And finally, you apply BSDF functions (math formulas created by artists that specify how light bounces off of objects) to calculate where the light bounced to.
That's it. The BSDF is an abstraction: there are many different models: one for metal, one for "specular" ("shiny" objects, like a marble), one for "diffuse" ("soft" objects like an egg), etc. etc. And an "uber BSDF" that kind of provides sliders for many different objects. (Invented by Disney: Roughness, Metalicness, Specularness, Diffuseness). But the BSDF itself is just an abstraction: where did the light bounce to? And different objects have different properties.
------
From there: making a FAST raytracer is the hard part. What kind of data-structures are needed to calculate intersections more quickly? Understanding the hardware (SIMD-cores, maybe even GPUs) to calculate BSDFs in parallel. Etc. etc. Lots of little things to learn and ultimately complicating the thing.
A professional raytracer would also have special code for the different kinds of objects in the scene.
True random path tracing takes too long. Biased techniques and quasi-random paths can make smoother images with less effort. Unbiased techniques shy away from such "theoretically suboptimal" optimizations. Denoising. Multithreaded, multi-computer, multi-GPU support. The feature sets goes on-and-on-and-on.
But if you want to just make "a" raytracer, without any care in the world about how fast (or slow) it is, then you easily can do that in one weekend. So give it a shot if you like.
-----------
https://www.kevinbeason.com/smallpt/
They brute-force an all-to-all check against all objects. There's no oct-tree partitioning or BVH trees. The only shape supported are spheres of varying sizes (no squares, no triangles, no cubes. Just spheres). There are only three BSDF functions implemented (specular "hard and shiny", diffuse "soft and matte", and glass). This tiny program is inefficient as all heck, but hey... 99 lines of code is pretty spiffy. That's all you really need for a raytracer.
Eigenvectors won't show up in an elementary path/ray tracer.
You need the most barebone understanding of LA for xform composition/application.
You can probably??? write a raytracer using Trig alone: it just means that you'll be using sin/cos on angles instead of "short-cutting" with a dot-product to determine normal vectors.
Hmmm... well... maybe the concept of dot-products and orthogonal vectors will help. So Linear Algebra probably will make things easier if you studied that too... but I still think its kinda optional.
tan(angle) = opposite-leg / adjacent-leg.
arctan(opposite-leg / adjacent-leg) == angle.
The more I do this, the more I realize that the linear-algebra approach might be easier... but the Trig approach can certainly do what you are asking for.I mean, I recognize that I'm just "reinventing cross-product" here to get the length of opposite-leg and the direction of adjacent-leg. But it does seem feasible to do all of these things in Trigonometry alone.
A little bit of Linear algebra (cross product creates an orthogonal vector) would definitely make this problem easier.
(0,0,0), A, and B are the three points of a right-triangle.
Hmm... okay, yeah. I see what you mean. Every time I think about how to do things, its linear algebra time.
The thing is: I've had this feeling before in other maths: the more you study one math subject, the "worse" you get in another. There's surprising things you can do with algebra alone without any calculus... but once you learn calculus, you kinda forget those old algebra tricks.
Your next line suggests you already know this, but just so it's clear it's not, they are three points in an arbitrary triangle. Each vector has a right triangle between the origin and (two of?) it's axis, but I'm not sure that's helpful.
Yeah, I agree in that it feels like you should be able to do this, but I just know that I've been stumped in the past, and can't figure it out now either.
sin(a) / A = sin(b) / B = sin(c) / C
Apparently, MY trigonometry is awful and needs more practice! Law of sines is basic 'non-right triangles' stuff.
There are three legs: A-0, B-0, and B-A. Hmmm... B-A seems like a vector operation (but its a really easy one, so... probably can be figured out without formally studying linear algebra).. That gives us the "A", "B" and "C" for lengths.
Aaaannnnd I'm stuck again. I have the lengths but I don't have the angles. I only need to find one angle and the other two are solved with law of sines.
Maybe a system of equations at this point (lol, another subject where linear algebra helps). The law of sines gives 3-unknowns, but only 2-equations. So I still need one more constraint before I can math-out a solution.
------
EDIT: Law of sines is fully:
sin(a) / A = sin(b) / B = sin(c) / C = d
Where "d" is the diameter of the circumcircle of the triangle. So the circumcircle's diameter gives us the 3rd equation needed to solve the above system of equations (using non-matrix math).
So yeah, I think its possible. Its just waaayyyy harder to do. I also am handwaving a difficult part. I guess... take the average of 3 points, which would give the center of the circumcircle. Then sqrt(x, y, z) from the center to find the radius, then 2*radius = d.
Wow, that's a lot of work compared to an easy projection matrix...
You could also use the law of cosines to get a triangle's angles pretty easily when you know its edge lengths: https://mathworld.wolfram.com/LawofCosines.html.
Sines and cosines fall out of rotations because of the implicit circle involved, but it’s more general to think of a transform between two basis frames. It just so happens that the lengths of basis vectors of one frame projected to the other are computed using sines and cosines, but the transform and dot products are there whether they’re made explicit or not.
Using only sines and cosines falls apart very quickly, here are a couple of examples:
Compute a surface normal under non-uniform scaling. You need the inverse transpose matrix. I don’t even know how to derive it using trig.
Implement instancing or a character rig in your ray tracer. As soon as you need to compose transforms just to trace a ray, the trig route is off the table (impractical in the extreme), and matrix math is required. An alternative might be geometric algebra - is that in the same boat with linear algebra for you?
trigonometry provides the trigonometric functions, their relationship and a few basic equations. Linear algebra provides vectors/matrices. You need both of them to model 3D objects and vectors interscting with them (aka rays hitting objects)
> math formulas created by artists
Rarely do artists create the BSDF, generally a general model BSDF is provided by an engineer or scientest, and the parameterization is tweaked by an artist.
> that specify how light bounces off of objects
Technically a BSDF generalizes all light interaction with medium. a BRDF, is the function that describes how light bounces (reflects, the R in BRDF) off of objects, which is sufficent for raytracing solid, non transparent/translucent objects.
> And an "uber BSDF" that kind of provides sliders for many different objects. (Invented by Disney
The idea of an uber BSDF wasn't "Invented by Disney" Brent Burley did develop Disney's principled BRDF at Disney, but it builds on a long foundation of uber BRDFs at VFX studios. He did popularize, if not invent the idea of a metalness map. It was however already possible to represent metals in existing uber shaders by just using a standard full color specular lobe.
> Understanding the hardware (SIMD-cores, maybe even GPUs)
I'd add understanding memory cache hierarchies, and their affect on performance highest among those.
A friend worked on a similar project to predict bird (and dinosaur) coloration from the structure of their feathers, which is just wild!
I don’t know what the precise differences are, but FWIW we had an uber shader that we called “uber shader”, with a metalness map (a texture driven metallic BRDF lobe, not just full color specular) at PDI in the late 1990’s, written by Sing Choong Foo (who worked on the Lafortune model). I’d guess Pixar and other studios had one too by that time.
I'm not even sure Disney can be fully credited with popularizing it, I think it was becoming important in videogames with packed GBuffers almost concurrently.
Chapter 3 introduces BVHs, Chapters 4-5 add more surfaces, and Chapter 7 adds cubes. There's a third book ("Ray Tracing: The Rest of Your Life") that tackles more sophisticated approaches like importance sampling.
It's been pretty great; realtime rendering gets all the hype, but offline rendering is where realtime is headed and this is a super exciting time with all this parallel computation around.
Curious what you mean by this. Just that realtime will start using more and more offline techniques as hardware speeds up? Or are you talking about pre-rendered scenes?
Eventually desktop GPU drivers will emulate "old" rasterised games on ray tracing hardware.
Did you market yourself? Got noticed by somebody important? Started selling your own raytracer? Or maybe just apply somewhere?
The main thing is actually spending a lot of time writing ray tracers... you should write your first 5 ray tracers as quickly as possible :)
I really recommend! Much cooler (IMO) then doing another TODO list app. I also recommend going to google to more deeply understand some of the algebra concepts that are used (since they aren't really explained in a deeper level and assume you already know).
As a casual observer, it seems that making a properly typed opengl wrapper is apparently quite hard, and the solution space hasn't matured yet.
The beauty of raytracers is that you don't need any graphics support at all. The output of a raytracer is a frame. The simplest way is just an array. Compute your color values, save them to array positions.
Of course, you eventually will want to see the result. You can save an image to a file then. One of the simplest formats is PPM. The PPM format requires a header, afterwards you just push RGB values. Which means you don't even need a library (http://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#C)
If your question is not about raytracers, but more general, there's countless ways.
Are you drawing in 2D (and not a game)? You can use the OS's own native functions for this if you are brave. Since Rust can call C libraries, this should work. Draw in memory, then "blit"(i.e. copy it over) to the appropriate buffer. Under Windows, you could use the Win32 API directly if you don't value your time :)
Alternatively, you can use a library that will make your work much simpler. There are many cross platform UI libraries, some of them with Rust bindings. And some Rust-specific ones too Check https://www.areweguiyet.com/
If you don't care about GUI controls and are mostly drawing images (like in games!), there's SDL. That will take care of most of your needs.
See also: https://arewegameyet.rs/
If you are doing it in 3D, you could use OpenGL. I've done that with my raytracer back in university. Same principle applied: I would generate a scene in memory, then copy to a texture and display it. Geometry was just two triangles. You could do a similar thing.
(full disclosure: I contribute to some of these crates)
For example, there is an implementation of WebGPU (https://github.com/gfx-rs/wgpu-rs) that can run both inside and outside of the browser that has been growing in popularity lately.
There are also bindings for Vulkan (ash, erupt), D3D12 (d3d12-rs), Metal (metal-rs), cross-platform abstractions at various levels (gfx-hal, wgpu), OpenGL (glow, glium), etc.
It's also possible to simply render graphics to an image (a pretty common approach for Raytracing in One Weekend) or blit pixels onto a window surface.
I ended up doing a lot more maths than writing code, so it wasn't that good of a project.
I used this first book as a project to learn Clojure https://github.com/ElHacker/rt-in-weekend-clojure
I'm slowly going through the 3 books series https://github.com/RayTracing/raytracing.github.io/
This past weekend I finished the second book "The Next Week", also implemented it in Clojure https://github.com/ElHacker/rt-next-week-clojure
It's been a great source for learning!
If you really want something more portable like PNG then it happens to be quite a fun library to implement. I encourage you to write your own. It’s basically:
- some magic number bytes
- a static header to announce the image is 8bit RGB zlib-compressed unfiltered non-interlaced
- a final set of magic bytes to say “here’s the actual image”
- zlib compressed rows of RGB bytes, with a 0 at the start of each row
So really just a fancy image.ppm.gz. What’s cool is that with 10 more lines of code you can implement animated PNG.
Both tutorials are excellent, but Gabriel's explanations just gelled a little bit better with my personal learning style.
[1] https://www.gabrielgambetta.com/computer-graphics-from-scrat...
THANKS!
Am nearly done with the first book and have been having a lot of fun.
I am not sure if the (2016) qualifier is adequate.
Reading the other comments here, I'm starting to think that's how you're supposed to use the book :)
For anyone curious, I implemented it at https://github.com/skytreader/praytracing in a way that's Pythonic, more software engineer-y, with experiments on the code outlined in the comments. It also has no dependencies (save mypy) which means it could turn your computer to a radiator for a short while, perfect for winter.
(Also used it to benchmark and experiment with PyPy, but that's another story.)
Even basic GDI and OpenGL is monumentally frustrating for beginners who just want to draw a simple rectangle to the screen.
https://gist.github.com/CoryBloyd/6725bb78323bb1157ff8d4175d...
There are lots of other projects like this too. One in particular that I have loved is NodeBox (nodebox.net/code/index.php/Home.html) - a Mac app where you write super simple code in python 2, and the output can render directly to image or PDF or QuickTime. There’s a similar python 3 project called DrawBot (drawbot.com). These both come from a lineage of forked open source projects over many years, so there are quite a few others.
It's about ~300 lines of Scala and runs in the browser via Scala.js. The page has a link to the source code. Could definitely be sped up or improved in a myriad of ways, but even as is I think the output graphic is pretty impressive given the input code size and programmer effort!
I can code it up but I don’t understand how it works.
Personally I absolutely love learning math and using it to code up programs that make pictures, learning and applying the trig and linear algebra is pure fun for me, so if it interests you go for it, I say. :)
Becoming fluent with a dot product is maybe the most useful single tidbit of math you could learn...
2016: https://news.ycombinator.com/item?id=10984620
related from 2018: https://news.ycombinator.com/item?id=18387344
https://casual-effects.com/markdeep/
Essentially markdown plus ASCII graphics, and it can "resolve" itself into HTML by adding a little JS footer to the end (AFAIK it's also possible to convert to HTML offline, like a conventional static site generator).
Markdeep can also be converted offline to HTML (e.g. with https://github.com/romainguy/markdeep-rasterizer).
Is there a reason to make this distinction here? The site & book are doing ray tracing, so the title is accurate. It mentions path tracing once at the very beginning, because the end goal is a path tracer. I think the goal is achieved, so in this case the book is both ray tracing and path tracing.
The original method, by Whitted, that looked much better than any previous methods, and yet looks horrible by today's standards, is ray tracing. It had no global illumination.
The method based on solving, explicitly or implicitly, the rendering equation by James Kajiya, and one that has built-in global illumination, is path tracing.
The distinction is not important for buzzword hijacking hacks, marketing gimmickers, and snake oil salesmen.
I'm completely stumped by your last sentence though, I have no idea where your anger is coming from. But it fails to explain why you want to make the distinction in this thread, since, as I already pointed out "Ray Tracing in one Weekend" is doing both (for example chapters 1-7 are the mechanics of ray tracing, no path tracing concepts are used until chapter 8). Are you referring indirectly to any specific products that have marketing you don't like? Your story can't explain people who use the term "ray tracing" since they're being honest about not necessarily doing path tracing. So are you talking about someone who uses the term "path tracing" when they're not doing global illumination?