Sunday, January 31, 2016

Ray Tracing: the Next Week

There's been a lot of interest and positive feedback on my mini-book on ray tracing.

This page is for the sequel Ray Tracing: the Next Week, available on Kindle.

This page also gives links and pointers for each chapter.   The features covered are those in this picture:

Chapter 1: Motion Blur

This method was introduced in 1984 by Rob Cook.

Chapter 2: A Bounding Volume Hierarchy (BVH)

The construction method in the book can be improved by using the surface area heuristic (SAH).     When evaluating potential partitions, the one that minimized the surface area of the sum of volumes of the sub-trees is almost always good.  Here is a SAH-based build that cuts on the longest axis.

Chapter 3: Solid Texture Mapping

Chapter 4: Perlin Noise 

A fantastic tool explaining how it works by Andrew Kensler

Chapter 5: Image Texture Mapping

Chapter 6: Rectangles and Lights

The program in the book implicitly samples lights so there are no shadow rays.   If you want to get more efficient direct lighting you can either send shadow rays, or importance sample by sending more rays toward the lights.

Chapter 7: Instances

A general instance usually stores transformation matrices.   Composite transforms can all be in one node.   When scales are allowed handling the surface normals must be done with care.

Chapter 8: Volumes

Here's a derivation of the ray-constant-medium intersection.

It is straightforward to add nonuniform densities by adding a more sophisticated intersection method.   This is covered in this blog post.   It's pretty common knowledge in the ray tracing community, but not really in the intersection.

Wednesday, January 27, 2016

Ray Tracing in One Weekend

Ray tracing was invented by Turner Whitted around 1980.   His classic paper is really amazing; it had bounding volume hierarchies, adaptive sampling, and it's future work suggested randomized reflection.   Since then it has branched into a ton of variations and is used in most movies for the indirect "bounce" lighting.

I've was assigned a 2D ray tracer in a physics class in 1984 and I was hooked.   Since then I have written a bunch of ray tracers in Pascal, Fortran, Scheme, C, C++, Java, and most recently Swift (which is awesome for writing ray tracers).   I've also taught classes with ray tracing about a dozen times, most recently at Westminster College in 2015.   My approach over the years has evolved to do what I think are the most fun parts of ray tracing that are still in the direction of writing a production-quality ray tracer.

Ray Tracing in One Weekend is a kindle book that goes through all of the details to generate a rudimentary ray tracer.   It's $2.99 on amazon.   It uses C plus classes plus operator overloading.   I have heard this referred to as "C plus" which I now call it.    Most production renderers are written in C++ so I opted for that as the driving language.    I put the most primal set of these assignments so that it's very doable in a weekend, the fundamental unit of coding self-improvement :)   Here is the book:

The resulting program generates this image:

Here's my MacOS code for the book.   Should be semi-portable but drand48() will need to be written on some systems and the fileio may be too.    I also have a little post on the tools I used to write the book for those interested in doing a little book of their own.   Please let me know if you do!

Links for further reading and exploration related to the book:

Chapter 0: Overview

Here is a list of basic graphics texts that cover the vector background the book assumes:

Fundamentals of Computer Graphics, Fourth Edition

Computer Graphics: Principles and Practice (3rd Edition)

The Graphics Codex

Real-Time Rendering, Third Edition

Chapter 1: Output an image

For output of most LDR and HDR images I love stb_image.

For more info on HDR images and tone mapping the I like the book  High Dynamic Range Imaging, Second Edition: Acquisition, Display, and Image-Based Lighting 

Chapter 2: The vec3 class

I advocate using the same class for points, displacements, colors, etc.   Some people like more structure and type checking (so for example multiplying two locations would be rejected by the compiler).   An example article where points and vectors are different is here.   Jim Arvo and Brian Smits experimented with not only distinguishing points and vectors, but using the compiler to do dimensional analysis (so velocity, length, and time would be different types for example).   They found this to be too cumbersome in 1990s C++ but I'd love to hear about anybody's experience.   Researchers at Dartmouth have taken a really serious effort at this and their code and paper are available at github.

Chapter 3:  Rays, a simple camera, and background

The first thing you might add to your background function is an environment map.   Paul Debevec has a terrific history of environment mapping.   The easiest mapping for this uses a single image for the entire sphere of directions.   Paul also provides some good images to use for your environment map.

Chapter 4:  Adding a sphere

There are a bunch of other object types you can add.   Triangles are usually first and I am a fan of barycentric methods.    After triangles, many people quit adding primitives because graphics has such a big infrastructure for triangles.    Ellipses are an easy thing to add but instancing is usually a more "ray tracey" approach (let the software do the heavy lifting).   Composite objects via CSG are surprisingly straightforward.

Chapter 5:  Surface normals and  multiple objects.

If you want your code to be more efficient for large numbers of objects, use a BVH-- they are as good as any other in efficiency and are the most robust and easiest to implement.

Chapter 6:  Antialiasing

Box filtering as done in the book suffices for most situations.   However, Guassian-like filters can have advantages and are pretty easy.   You can either uniformly sample the whole screen and weight the samples, or use non-uniform samples.   All approaches work.

Chapter 7:   Diffuse Materials

"Ideal" diffuse materials, also called "Lambertian" are used 99% of the time in graphics.     The wikipedia article on this approximation is good.   Real diffuse surfaces do not behave exactly as Lambertian (for example they get specular at grazing angle) but especially with interreflection in the mix the appearance differences are minor.   So this is probably not where you should push your renderer until many many other features are addressed.

Chapter 8:  Metal

The first improvement you might make is to have the color of the metal go to white at grazing angle.   The Schlick approximation (used in Chapter 9 for glass where grazing behavior matters more) works for that.    Full-bore Fresnel equations will describe color variation with angle, but in my experience getting normal incident color is good enough.

Chapter 9:  Dielectrics

The first thing you might add is filtering of light within the dielectric (like the subtle "greenness" of much glass).   This is a classic exponential decay and is covered well in the Beer's Law section of this nice page.

Chapter 10:  Positionable camera
Camera parameter setting is just plain ugly.  The system used in the book is relatively common and is in my opinion the prettiest.   I avoid the matrix formulation wherever possible because I never understand my code when I am done.   But it is very elegant and works.

Chapter 11:  Defocus blur

If you ever need to match a real camera, there is a nice survey of models used in graphics.   And here is a very good presentation on real lenses written for a technical audience.

Chapter 12:  Where next?

You should have the core of a very serious ray tracer now.    I would now take it in one of three directions.   They are not mutually exclusive but explicitly deciding your goals will simplify architectural decisions.
  1. Make it physically accurate.   This will imply using spectra instead of RGB (I like just using a big array of wavelengths) and get something where you know the reflectances.   Popular is to get a X-Rite MSCCC ColorChecker Classic whose data is available online.
  2. Make it good for generating animations.    Lots of movies use a ray traced system, and Disney, Pixar, and the Solid Angle teams have both disclosed a remarkable amount about their code.   Work on features and then efficiency.   I think you will be amazed how soon you can produce amazing images.
  3. Make it fast.   Here you can roll your own, or start using a commercial API.   To see exactly where that community is now, go to the 2016 HPG conference.   Or backtrack in their previous papers.   They are a very open community and the papers go into much detail relative to many sub-fields in computer graphics.
Please send me your questions, comments, and pictures.   Have fun with ray tracing!