Wednesday, December 28, 2016

Bug in my Schlick code

In a previous post I talked about my debugging of refraction code.   In that ray tracer I was using linear polarization and used these full Fresnel equations:

Ugh those are awful.   For this reason and because polarization doesn't matter that much for most appearance, most ray tracers use R = (Rs+Rp)/2.    That's a very smooth function and Christophe Schlick proposed a nice simple approximation that is quite accurate:

R = (1-R0)(1-cosTheta)^5

A key issue is that the Theta is the **larger** angle.   For example in my debugging case (drawn with limnu which has some nice new features that made this easy):

The 45 degree angle is the one to use.   This is true on the right and the left-- the reflectivity is symmetric.   In the case where we only have the 30 degree angle, we need to convert to the other angle by using Snell's Law: Theta = asin(sqrt(2)*sin(30 degrees).

The reason for this post is that I have this wrong in my book Ray Tracing in One Weekend :

Note that the first case (assuming outward normals) is the one on the left where the dot product is the cos(30 degrees).  The "correction" is messed up.    So why does it "work"?    The reflectances are small for most theta, and it will be small for most of the incorrect theta too.   Total internal reflection will be right, so the visual differences will be plausible.

Thanks to Ali Alwasiti (@vexe666) for spotting my mistake!

Sunday, September 18, 2016

A new programmer's attitude should be like an artist's or musician's

Last year I gave a talk at a CS education conference in Seattle called "Drawing Inspiration from the Teaching of Art".   That talk was aimed at educators and said that historically CS education was based on that of math and/or physics and that was a mistake and we should instead base it on art.   I expected a lot of pushback but many of the attendees had a "duh-- I have been doing that for 20 years" reaction.

This short post is aimed at students of CS but pursues the same theme.   If you were an art or music student your goal would be to be good at ONE THING in TEN YEARS.   If a music student that might be signing, composition, music theory, or playing a particular instrument.   Any one of those things is very hard.   Your goal would be to find that one thing you resonate with and then keep pushing your skills with lots and lots of practice.  Sure you could become competent in the other areas, but your goal is to be a master of one.   Similarly as an artist you would want to become great at one thing be it printmaking, painting, drawing, pottery, sculpture, or art theory.   Maybe you become great at two things but if so you are a Michelangelo style unicorn and more power to you.

Even if you become great at one thing, you become great at it in your own way.    For example in painting Monet wanted Sargent to give up using black.   It is so good that Sargent didn't do that.   This painting with Monet's palette would not be as good.   And Monet wouldn't have wanted to do that painting anyway!

Computer Science is not exactly art or music, but the underlying issues are the same.   First, it is HARD.   Never forget that.   Don't let some CS prof or brogrammer make you think you suck at it because you think it's hard.   Second you must become master of the tools by both reading/listening and playing with them.   Most importantly find the "medium" and "subject" where you have some talent and where it resonates with you emotionally.   If you love writing cute UI javascript tools and hate writing C++ graphics code, that doesn't make you a flawed computer scientist.   It is a gift in narrowing your search for your technical soul mate.   Love Scheme and hate C# or vice-versa.   That is not a flaw but again is another productive step on your journey.   Finally, if you discover an idiosyncratic methodology that works for you and gets lots of pushback, ignore the pushback.   Think van Gogh.    But keep the ear-- at the end of the day, CS is more about what works :)

Friday, July 15, 2016

I do have a bug

I questioned whether this was right:

I was concerned about the bright bottom and thought maybe there was a light tunnel effect.   I looked through my stuff and found a dented cube, and its bottom seemed to show total internal reflection:
The light tunnel effect might be happening and there is a little glow under the cube, but you cant see it thought the cube.   Elevating it a little does show that:

Digging out some old code and adding a cube yielded:
This is for debugging so the noise was just because I didn't run to convergence.   That does look like total internal reflection on the bottom of the cube, but the back wall is similar to the floor.   Adding a sphere makes it more obvious:
Is this right?   Probably.

Wednesday, July 13, 2016

Always a hard question: do I have a bug?

In testing some new code involving box-intersection I prepared a Cornell Box with a glass block, and first question is "is this right?".    As usual, I am not sure.    Here's the picture (done with a bajillion samples so I wont get fooled by outliers):

It's smooth anyway.   The glass is plausible to my eye.   The strangest thing is how bright the bottom of the glass block is.   Is it right?    At first I figured bug.   But maybe that prism operates as a light tunnel (like fiber optics) so the bottom is the same color as a diffuse square on the prism top would be.   So now I will test that hypothesis somehow (google image search?   find a glass block?) and if that phenomenon is right and of about the right magnitude, I'll declare victory.

Tuesday, June 7, 2016

A sale on Limnu

The collaborative white-boarding program I used for my ray tracing e books has finished their enterprise team features that your boss will want if you are in a company.   It's normally $8 a month per user but if you buy in the next week it is $4 per month for a year.   Looks like that rate will apply to any users added to your team before or after the deadline as well.   I love this program-- try it!

Sunday, May 15, 2016

Prototyping video processing

I got a prototype of my 360 video project done in Quartz Composer using a custom Core Image filter.     I am in love with Quartz Composer and core graphics because it is such a nice prototyping environment and because I can stay in 2D for the video.   Here is the whole program:

A cool thing is I can use an image for debugging where I can stick in whatever calibration points I want to in Photoshop.   Then I just connect the video part and no changes are needed-- the Core Image Filter takes and image or video equally happily and Billboard displays the same.

The Filter is pretty simple and is approximately GLSL     

One thing to be careful on is the return range of atan (GLSL atan is the atan2 we know and love).

I need to test this with some higer-res equirectangular video.    Preferably with fixes viewpoint and with unmodified time.   If anyone can point me to some I would appreciate it.

Saturday, May 14, 2016

What resolution is needed for 360 video?

I got my basic 360 video viewer working and was not pleased with the resolution.   I've realized that people are really serious that they need very high res.   I was skeptical of these claims because I am not that impressed with 4K TVs relative to 2K TVs unless they are huge.   So what minimum res do we need?    Let's say I have the following 1080p TV (we'll call that 2K to conform to the 4K terminology-- 2K horizontal pixels):

Image from
If we wanted to tile the wall horizontally with that TV we would need 3-4 of them.   For a 360 surround we would need 12-20.   Let's call it 10 because we are after approximate minimum res.  So that's 20K pixels.   To get up to "good" surround video 20K pixels horizontally.   4K is much more like NTSC.   As we know, in some circumstances that is good enough.

Facebook engineers have a nice talk on some of the engineering issues these large numbers imply. 

Edit: Robert Menzel pointed out on Twitter that the same logic is why 8K does suffice for current HMDs.

Thursday, May 12, 2016

equirectangular image to spherical coords

An equirectangular image, popular in 360 video, is a projection that has equal area on the rectangle match area on the sphere.   Here it is for the Earth:

Equirectangular projection (source wikipedia)
This projection is much simpler than I would expect.    The area on the unit radius sphere from theta1 to theta2 (I am using the graphics convention of theta is the angle down from the pole) is:

area = 2*Pi*integral sin(theta) d_theta = 2*Pi*(cos(theta_1) - cos(theta_2))

In Cartesian coordinates this is just:

area = 2*Pi*(z_1 - z_2)

So we can just project the sphere points in the xy plane onto the unit radius cylinder and unwrap it!   If we have such an image with texture coordinates (u,v) in [0,1]^2, then

phi = 2*Pi*u
cos(theta) = 2*v -1

and the inverse:

u = phi / (2*Pi)
v = (1 + cos(theta)) / 2

So yes this projection has singularities at the poles, but it's pretty nice algebraically!

spherical to cartesian coords

This is probably easy to google if I had used the right key-words.   Apparently I didn't.   I will derive it here for my own future use.

One of the three formulas I remember learning in the dark ages:

x = rho cos(phi) sin(theta)
y = rho sin(phi) sin(theta)
z = rho cos (theta)

We know this from geometry but we could also square everything and sum it to get:

rho = sqrt(x^2 + y^2 + z^2)

This lets us solve for theta pretty easily:

cos(theta) = z / sqrt(x^2 + y^2 + z^2)

Because sin^2 + cos^2 = 1 we can get:

sin(theta) = sqrt(1 - z^2/( x^2 + y^2 + z^2))

phi we can also get from geometry using the ever useful atan2:

phi = atan2(y, x)

Friday, May 6, 2016

Advice sought on 360 video processing SDKs

For a demo I would like to take come 360 video (panoramic, basically a moving environment map) such as that in this image:

An image such as you might get as a frame in a 360 video (
And I want to select a particular convex quad region (a rectangle will do in a pinch):

And map that to my full screen.

A canned or live source will do, but if live the camera needs to be cheap.   MacOS friendly preferred.

I'm guessing there is some terrific infrastructure/SDK that will make this easy, but my google-fu is so far inadequate.

Tuesday, May 3, 2016

Machine learning in one weekend?

I was excited to see the title of this quora answer: What would be your advice to a software engineer who wants to learn machine learning?   However, I was a bit intimidated by the length of the answer.

What I would love to see is Machine Learning in One Weekend.    I cannot write that book; I want to rread it!    If you are a machine learning person, please write it!   If not, send this post to your machine learning friends.

For machine learning people: my Ray Tracing in One Weekend has done well and people seem to have liked it.    It basically finds the sweet spot between a "toy" ray tracer and a "real" ray tracer, and after a weekend people "get" what a ray tracer is, and whether they like it enough to continue in the area.   Just keep the real stuff that is easy, and skip the worst parts, and use a real language that is used in the discipline.   Make the results satisfying in a way that is similar to really working in the field.   Please feel free to contact me about details of my experience.  

Monday, April 25, 2016

Level of noise in unstratified renderers

When you get noise in a renderer a key question, often hard to answer, is is it a bug or just normal outliers?   With an unstratified renderer, which I often favor, the math is more straightforward.   Don Mitchell has a nice paper on the convergence rates of stratified sampling which is better than the inverse square root of unstratified.

In a brute force ray tracer it is often true that a ray either gets the color of the light L, or a zero because it is terminated in some Russian Roulette.   Because we average the N samples the actual computation looks something like:

Color = (0 + 0 + 0 + L + 0 + 0 + 0 + 0 + L + .... + 0 + L + 0 + 0) / N

Note that this assumes Russian Roulette rather than downweighting.   With downweighting there are more non-zeros and they are things like R*R'*L.   Note this assumes Color is a float, so pretend it's a grey scene or think of just each component of RGB.

The expected color is just pL where p is the probability of hitting the light.    There will be noise because sometimes luck makes you miss the light a lot or hit it a lot.

The standard statistical measure of error is variance.    This is the average squared error.   Variance is used partially because it is meaningful in some important ways, but largely because it has a great math property:

The variance of a sum of two random quantities is the sum of the variances of the individual quantities

We will get to what is a good intuitive error message later.   For now let's look at the variance of our "zero or L" renderer.   For that we can use the definition of variance:

the expected (average) value of the squared deviation from the mean 

Or in math notation (where the average or expected value of a variable X is E(X):

variance(Color) =  E[ (Color - E(Color))^2 ]

That is mildly awkward to compute so we can use the most commonly used and super convenient variance identity:

variance(X) = E(X^2) - (E(X))^2

We know E(Color) =  pL.    We also know that E(Color^2) = pL^2, so:

variance(Color) =  pL^2 - (pL)^2 = p(1-p)L^2

So what is the variance of N samples (N is the number of rays we average)?

First it is the sum of a bunch of these identical samples, so the variance is just the sum of the individual variances:

variance(Sum) = Np(1-p)L^2

But we don't sum the colors of the individual rays-- we average them by dividing by N.   Because variance is about the square of the error, we can use the identity:

variance(X / constant) = variance(X) / constant^2

So for our actual estimate of pixel color we get:

variance(Color) =   (p(1-p)L^2) / N

This gives a pretty good approximation to squared error.   But humans are more sensitive to contrast and we can get close to that by relative square-root-of-variance.   Trying to get closer to intuitive absolute error is common in many fields, and the square-root-of-variance is called standard deviation.   Not exactly expected absolute error, but close enough and much easier to calculate.    Let's divide by E(Color) to get our approximation to relative error:

relative_error(Color) is approximately   Q = sqrt((p(1-p)L^2) / N) / ( pL)

We can do a little algebra to get:

Q = sqrt((p(1-p)L^2) / (p^2 L^2 N) ) = sqrt( (1-p) / ( pN) )

If we assume a bright light then p is small,  then

Q is approximately sqrt(1/(pN))

So the perceived error for a given N (N is the same for a given image) ought to be approximately proportional to the inverse squareroot of pixel brightness, so we ought to see more noise in the darks.

If we look at an almost converged brute force cornell box we'd expect the dark areas to look a bit noisier than the bright ones.   Maybe we do.   What do you think?

Sunday, April 3, 2016

Debugging by sweeping under rug

Somebody already found several errors in my new minibook (still free for until Apr 5 2016).    There are some pesky black pixels in the final images.

All Monte Carlo Ray Tracers have this as a main loop:

pixel_color = average(many many samples)

If you find yourself getting some form of acne in the images, and this acne is white or black, so one "bad" sample seems to kill the whole pixel, that sample is probably a huge number or a NaN.   This particular acne is probably a NaN.   Mine seems to come up once in every 10-100 million rays or so.

So big decision: sweep this bug under the rug and check for NaNs, or just kill NaNs and hope this doesn't come back to bite us later.   I will always opt for the lazy strategy,  especially when I know floating point is hard.

So I added this:

 There may be some isNaN() function supported in standard C-- I don't know.   But in the spirit of laziness I didn't look it up.   I like to chase these with low-res images because I can see the bugs more easily.    It doesn't really make it faster-- you need to run enough total rays to randomly trip the bug.   This worked (for now!):

Left: 50x50 image with 10k samples per pixel (not enough for bug).    Middle 100k samples per pixel.   Right: with the NaN check. 


Now if you are skeptical you will not that by increasing the number of samples 10X I went from 0 bugs to 20+ bugs.   But I wont think about the possibly troublesome implications of that.   MISSION ACCOMPLISHED!

Saturday, April 2, 2016

Making an "In One Weekend" Kindle Book

Over the last few months my side project has been a series of three Kindle mini-books on ray tracing.   Ray tracing is a computer graphics programming area to produce nice images and ray tracing has been hot lately (most computer animated films are now ray traced, are are many of the special effects shots in regular movies).   This post is not about those books specifically, but is instead describing my experiences and encouraging others to write similar mini-books on other subjects. I promote and document the books at If you have something (book, youtube, blog, whatever) to help people learn something in a weekend, let me know and if I can learn from it I will promote it on my site!

Here are the books at Amazon: 

Ray Tracing: The Rest of Your Life

I set my price for each book at $2.99.   Conversions for other countries Amazon does automatically for you.   You get 70% of the sales if your book is priced from $2.99 to $9.99.   Amazon will let you give away the book for free for five days every quarter, and I began each book with a free promotion.   So far since early 2016 when I started, I have sold about 700 books and given away almost 3000.

CALL TO ACTION: It is easy and fun to make such books, and they make money, and give others a mechanism to see if they love the same things you do with just a weekend commitment.   I will show you the mechanics of how I wrote my instance of this.

THE MECHANICS WRITING THE TEXT:  Just write a Word file or a Google Doc and “download as” a Word file.    Really that’s it! Here is an example of my book on the Amazon cloud reader:
Two kindle pages with code screen shots, ray tracer output, and limnu drawing

THE MECHANICS OF CREATING FIGURES:  For drawings I used the shared whiteboard program from    I drew the figures on a tablet, and then opened them on my laptop (limnu stores your boards in the cloud so no file copying needed), and did a screen capture of the part of the image I wanted to make a figure (command-shift-4 on a mac), and then dragged the file into google docs.    For code samples I just screen-captured the code from vim. Here is my favorite limnu figure in the books:

THE MECHANICS OF CREATING A KINDLE BOOK:  Go to and create an account.    Upload the word file.    Upload a cover image which must be tif or jpeg.   Amazon also has some tools for cover creation. It is all super-easy and has a great interface and here is a screen shot of the style of data entry:

ADVERTISING THE BOOK:   I used word of mouth and twitter and hackernews and facebook.   I also created a website to promote the book.    If you do a book and I try it out and like it, I will make an article about your book and point to it.   You can feel free to use the “in one weekend” phrase in your title.

IT IS THAT EASY!   And now I feel like I have done some good spreading how-to information, made some cash, and helped my resume.   And it was surprisingly fun; I looked forward to working on the books when done with my other work.   I encourage you to try it, and if you write one please let me know and I will see if I can learn something new in a weekend.

Thursday, March 31, 2016

Converting area-based pdf to direction-based pdf

One thing I covered in my new mini-book is dealing with pdf management in a path tracer.     Most of my ray tracers (and many others do it too) are set up to sample directions.   So at a point being shaded, the integral is over directions:

color(direction_out) = INTEGRAL   brdf(direction_in, direction_out) cosine

the domain of integration is all direction_in coming from the sphere of all directions.   Often the brdf is zero for directions from inside the surface so it's the hemisphere.

Basic Monte Carlo integration says that if you choose a random direction_in with pdf pdf(direction_in), the unbiased estimate is:

       color(direction_out)  =  brdf(direction_in, direction_out) cosine / pdf(direction_in)

As long as you can generate random direction_in, and can compute pdf(direction_in) then you have a working ray tracer.   It works best when you are likely to cast random rays toward bright areas like lights.    If you sample a polygonal light, you normally just sample q uniformly on the area.   The direction is just q-p.    The key observation to get from the pdf in area space p_area(q) = 1/A (where A is the area of the light) is that by definition the probability of q being in a small area dA is

       probability = p_area(q) dA

Similarly the directional pdf of a direction toward dA is:

       probability = pdf(q-p) dw

Those probabilities must be the same:

      p_area(q) dA =  pdf(q-p) dw

By algebra:

pdf(q-p) =  p_area(q) dA/dw = (1/A) (dA/dw)

But what is (dA/dw)?

Let's do some basic geometry.   As is so often the case, the right figure makes that tons easier: 


You pick a point q on the light with pdf 1/A in area space, but what is the pdf in directional space?   Drawn in limnu whitboarding program.

If dA faces p dead-on (so its normal faces p), then it's foreshotening:

      dw = dA/distance_squared

But if dA is tilted then we get a cosine shift:

      dw = dA*cosine / distance_squared

So recall we are after

      pdf(q-p) = (1/A) (dA/dw)

So we can plug and chug to get:

       pdf(q-p) =length_sqaured(q-p) / (A*cosine)

We just apply this formula directly in our code.   For my xz rectangle class this is:



Third and final ray tracing mini-book is out

My third and final Kindle ray tracing mini-book is out.    It will be free April 1-5, 2016.

Ray Tracing: The Rest Of Your Life (Ray Tracing Minibooks Book 3)

From the intro:

In this volume, I assume you will be pursuing a career related to ray tracing and we will dive into the math of creating a very serious ray tracer. When you are done you should be ready to start messing with the many serious commercial ray tracers underlying the movie and product design industries. There are many many things I do not cover in this short volume; I dive into only one of many ways to write a Monte Carlo rendering program.   I don’t do shadow rays (instead I make rays more likely to go toward lights), bidirectional methods, Metropolis methods, or photon mapping.   What I do is speak in the language of the field that studies those methods.   I think of this book as a deep exposure that can be your first of many, and it will equip you with some of the concepts, math, and terms you will need to study the others.

Friday, March 18, 2016

My buggy implimentation of Schlick approximation

One of the most used approximations in all of graphics is the Schlick approximation by Christophe Schlick.    It says the Fresnel reflectance of a surface can be approximated by a simple polynomial of cosine(theta).    For dielectrics, a key point is that this theta is the bigger of the two regardless of which direction the ray is traveling.
Regardless of light direction, the blue path is followed.   Regardless of light direction, the larger of the two angles (pictured as theta) is used for the Schlick approximation.

A sharp reader of my mini-book pointed out I have a bug related to this in my code.   I was surprised at this because the picture looked right (sarcasm).      The bug in my code and my initial fix is shown below.
The old code shown in blue is replaced with the next two lines.
My mistake was to pretend that if snell's law applies to sines,  n1*sin(theta1) = n2*sin(theta2), it must also apply to cosines.   It doesn't.    (The fix is just to use cos^2 = 1 - sin^2 and do some algebra) I make mistakes like this all the time, but usually the wonky-looking picture, but in this case it didn't.    It only affected internal reflections, and it just picked some somehwhat arbitrary value that was always between 0 and 1.   Since real glass balls look a little odd in real life, this is not something I can pick up.   In fact I am not sure which picture looks right!

Old picture before bug fix.
New picture after bug fix.

I am reminded of spherical harmonic approximation to diffuse lighting.   It looks different than the "correct" lighting, but not worse.  (In fact I think it looks better).    What matters about hacks is their robustness.    It's best to do them on purpose though...

Sunday, March 13, 2016

An example of an indirect light

On the top you see a big reflection of the Sun off my not very polished wooden floor.   On the bottom is the view in the opposite direction.   Three interesting points:

1. The secondary light effect is surprisingly (to me) strong and un-diffused.
2. The secondary light effect is achromatic even through it is off a brown floor-- the specular component is achromatic.
3. Note the tertiary effect on the wall by the picture frame.    This would be tough for most renderers.

Thursday, March 10, 2016

A simple SAH BVH build

Here is a cut at a BVH build that cuts along the longest axis using the surface-area-heuristic (SAH).   The SAH minimizes:

SUM_left_right number_of_children_in_subtree*surface_area_of_bounding_box_of_subtree

This has been shown by many people to work shockingly well.

Here's my build code and it works ok.   I still have to sort because I need to sweep along an axis.   Is it worth it to tree each of three axes instead of longest?   Maybe.... bundles of long objects would be the adversarial case for the code below.

Tuesday, March 8, 2016

BVH builds

In the new mini-book I cover BVHs.   In the book I always went for simple conceptual code figuring people can speed things up later.   I have what must be close to a minimum BVH build, but it just gets us the log(N).     It picks a random axis, splits in the middle of the list:

I could have split geometrically and done a O(N) sweep and the code might have been as small, but I wanted to set people up for a top-down surface-area heuristic (SAH) build.     As discussed by Aila, Karras, and Laine in 2013 (great paper--- download it here) we don't fully understand why lazy SAH builds work so well.   But let's just be grateful.   So what IS the most compact top down build?   I am going to write one to be supplemental for the book and just sweeping on those qsorts above is what appears best to me, but I invite pointers to good practice.

Monday, March 7, 2016

New ray tracing mini-book is out

My second and probably final kindle mini-book Ray Tracing the Next Week is out.    It will be free for five days starting tomorrow Tu Mar 8.    I will be maintaining notes and links at

Saturday, March 5, 2016

Next mini-book on ray tracing

I am almost done with the next (and probably last) mini-book on ray tracing.   It will be free for the first five days at the kindle store (probably sometime this week) so do not buy it -- there may be a short time when Amazon hasn't made it free yet.   The associated web site will be at just like the first book.   This the the image with the features added:

Final image for Ray Tracing: the Next Week

The features added are solid texture, image texture, participating medium, motion blur, instancing, and BVH.   I decided not to add explicit direct light so it's still brute force path tracing (thus the caustic is implicit).  

Tuesday, March 1, 2016

Lazy debugging

When I get a chunk of time I have been beavering away on a second part to my mini-book.     I just added implicit direct lighting (where you send scattered rays preferentially toward lights) and I got a bunch of speckles.

What are those?   Bad importance sampling?   A bug?   Some correct behavior I don't understand?   Who knows.   Should I track it down, or keep adding features and hope it luckily goes away in various refactors that come along organically.

Which one is less work?   Hope it goes away!   Sold!

Wednesday, February 17, 2016

Ray-Object Intersection Repository at RTR

Until Eric H's comment on a previous post, I was somehow unaware of this page.   It really rocks and will be my first stop when I look again at triangles (next week?).   Here is the page.

Sunday, February 14, 2016

New simple ray-box test from Andrew Kensler

Andrew Kensler and Thiago Ize have been helping me tune up my ray-box code trying to find a sweet-spot of fast and simple.   I've updates a few test cases here and added the new method Andrew sent me.   Andrew's new code a super-simple version that on some compilers/machines is very competitive with the Amy Williams method, and you don't have to muck up your ray class.    It's not as fast under clang on my mac (but hard-coding swap helped a little) but it's so simple it will be my go-to method for the time being.

If there are NaN the compare will fail and it returns false.   It handles the inf cases right.    Very clean!

Saturday, February 6, 2016

ray-box intersection and fmin

In working on the code for the next mini-book, I have followed the philosophy of using the simplest code and trusting that it is good enough.   For bounding volume hierarchies I tried making a simpler ray-box test that people usually use.   I was especially impressed with this post by Tavian Barnes.

This is the simplest ray-box test I was able to write:

The overall code seemed pretty slow so I tried some old more complicated code that stores the sign of the ray propagation directions as well as the inverses of the ray direction components:

This was a lot faster in the overall ray tracer so I started digging into it a bit.   I wrote an isolation test that sends lots of rays from near the corner of a box in random directions (so a little less than 1/8 should hit).    It occurred to me that the fmax and fmin might be slower due to their robust NaN handling and that does appear to be the case.    Here is the test I used on my old macbook pro compiled with -O.   Perhaps it gives a little too much amortization advantage to the long code because 100 trials for each ray, but maybe not (think big BVH trees).

The runtimes on my machine are:

traditional code: 4.3 s
using mymin/mymax: 5.4s
using fmin/fmax: 6.9s

As Tavian B points out, the properties of fmax and NaN can be used to programmer advantage, and vectorization might make system max functions a winner.   But the gaps between all three functions were bigger than I expected.

Here is my code.   If you try it on other compilers/machines please let us know what you see.

Monday, February 1, 2016

Motion blur in a ray tracer

I implemented the first change in my ray tracer for my next mini-book.    I had forgotten how easy motion blur is to add to a ray tracer.   For linear motion anyway.    The ray gets a time it exists at, the camera generates a ray at a random time, and the object intersection takes a time in.

For a sphere whose center moves linearly, the change is just to make the center a function of time:

To test it I had the diffuse spheres have a random vertical motion.   This was a rare time my code worked on first run (after many typos on the way to compilation).

Sunday, January 31, 2016

I've decided to go ahead with a part-2 on the mini-book

The mini-book Ray Tracing in One Weekend got more interest than I expected.   Apparently ray tracing really is hot.   The book just gets a brute force path tracer with spheres up, so I decided it would be worth making a part 2 (to be written!).   I am seeking comments on what is missing from the list.   Here is my first cut:

Chapter 1: Motion Blur
Chapter 2: A Bounding Volume Hierarchy (BVH) Chapter 3: Solid Texture Mapping Chapter 4: Image Texture Mapping
Chapter 5: Volumes Chapter 6: A Polished Material Chapter 7: Environment Maps Chapter 8: Shadow Rays Chapter 9: Triangle Meshes

I would consider that a full-featured ray tracer.   That is not to say having all features!  

Friday, January 29, 2016

Some of Andrew Glassner's thoughts on publishing

Andrew Glassner left a reply on an earlier post that seemed too interesting to let sit in a comments section.   So here it is in its entirety.   I didn't ask Andrew, so keep in mind that he wrote this as a comment (not that I would change anything in an edit!).

Andrew's comment:

I like what you're doing here. To me, the interesting thing is that you're trying to avoid extra work that's been pushed on authors with the decline of the traditional publication model. That decline has been hailed as "democratizing" publication, which is true in some ways, but mostly not.

Here's what I mean. In the 1960's (as I understand it), to publish a book with math and figures, you'd type the book on your typewriter (or have someone do it for you from your longhand notes). You'd leave blank spaces for equations and figures, which you'd draw in by hand. The publisher would then often hire someone to redo your figures, and they'd lay out and typeset your book to make it look great.

Then TeX and LaTeX came along, and authors realized they could make their own pages. And they did. Before long, publishers required this, because why should they pay someone when they can get the author to do it for free? So now the author had to learn LaTeX and go through the sweat of typesetting math. But the publisher would still often hire an artist to redraw the figures. My first few books were developed this way.

Then drawing tools got better, and more authors started using them, and again the publishers chose to make that all but mandatory (if you swore you couldn't make figures, they would hire an artist, but I know that at least sometimes you gave up some royalties in return).

Then indexing packages became more widespread. And so, rather than hire a professional indexer (and this is a much harder job than you might imagine, if you haven't done it yourself), that too became the author's job.

And so it went, with authors now essentially required to produce beautiful, camera-ready works, with headers and footers and footnotes and properly formatted bibliographies and on and on.

The author's job went from "write a manuscript, indicate the math, provide sketches for the figures, and let the publisher take it from there," to the far more demanding "produce the entire book in every detail."

Since most people can get the tools required, this is indeed democratizing, in that most anyone can make a professional-looking book. On the other hand, it means the author must have enough leisure (or paid) time to learn the tools, and then devote significant more time to produce all the content to a professional standard. This is pretty much the opposite of democratizing - it says only people who have a lot of available time can afford to produce a book with equations and figures that holds up to modern standards.

You've found some great ways to reduce this burden. Well done! I've taken a similar attitude in my own works, when I can. I'm now very happy to illustrate my work with hand-drawn pictures, as long as they're clear and do the job. I wish I could get away from fiddling with LaTeX, but programs like the one at are a big help.

It's interesting to me that we've gone from the author's job being almost completely about writing words and merely indicating the rest, to the author becoming a self-contained and fully staffed publishing house (with typesetter, artist, indexer, etc.), to now where you're shedding some of those tasks (e.g., pagination) and automating others (e.g., screenshots of code with automatic coloring).

What you're doing really does make it easier to write a book (not merely cheaper for a publisher to print it), and I say "Hooray!" The easier it becomes to produce quality materials, the better off we all become.

Thursday, January 28, 2016

Figures in my new mini-book

In my new mini-book I used a new (to me) fun process.  The process I am referring to as agile writing, is based on the best low-pain tools I could find.   It would not be unfair to say I wrote a minimum viable book (MVB).   The tools are mainly google docs, limnu drawings, and screen captures of vim with auto-coloring.   The code was super-easy because vim auto-coloring works really well IMO:

Note that google docs has a nice crop interface so you don't need to screen capture precisely.

The white-boarding in limnu took me a little getting used to, but works very well.   Here's an example of a screenshot from limnu pasted into google docs:

I asked Dave Hart and Grue Debry for tips on how to do figures, and what is funny is that their advice mainly boiled down to "do what you do on a real whiteboard".   That advice may seem content-free but it's not; I did change my mentality that it was "fast and loose" and I needed to not be too uptight.    I know this from using real white boards, but somehow I wasn't in that mode with a tablet.   But once I just pretended it was a whiteboard and not a traditional computer drawing program I got much better results.   They wrote up the advice at their site.

Wednesday, January 27, 2016

Process for speed-writing a book

I recently speed-wrote a mini-book  Ray Tracing in One Weekend available on the kindle store.

I loved doing it.   This post is about the mentality and tools for this sort of endeavor.

Over the course of my career in computer science there have been many trends that I think are good signs of maturation of our discipline.  One, for example, is the rise of programming environments with heavy GUIs like xcode and visual studio.   The one I like the most is the rise of “agile” approaches (this would be a counter-trend to the GUI programming environments).   The most obvious example is agile programming methodologies.    In line with that is the YAGNI (you aint gonna need it) to feature evaluation.   The lean startup and MVP is the software business manifestation of agile.

Something that in my experience is the opposite of agile is writing a technical book.   I think this is one reason most people don’t write one.   The book I have the most knowledge of is the one I wrote with Steve Marschner on Computer Graphics.   Everything about making that book was not agile. That is ok from the point of view of “is the book good?”.   Yes, it is a very good book.   And I know from working with Steve Marschner I would like to read any book he was involved in.   But I would be surprised if he writes more.   Not because Steve doesn’t like explaining things-- he is in his element in front of a white board.   But writing a traditional book is as much about wrangling LaTeX and Adobe Illustrator as it is about explaining things.   I would call the process “epic”.
Last year I taught a graphics class at Westminster College in Utah.   One thing about the class is that half the majors were taking it so I decided to gear it toward making it a fun class that gives a feel for what graphics is all about.   This is as opposed to a class the punishes the students with the “spinach they should eat” if they are going to make a career in graphics.  I think the class was really fun.   It occurred to me that maybe I should write a mini-book on ray tracing based on the class assignments. Then I thought about the epic book writing process and said “no way”.

Over the next six months as I occasionally posted things on my blog, I realized how un-epic blogging was.   First, you can’t control the exact visual format-- different browsers and size setting make that impossible.   Second, there is no cultural expectation that the graphics design elements or the language be perfect so you can just concentrate on the information.   This is an example of an agile process.   Then it occurred to me-- why not write an “agile book”.   And what is that?

First because it is a graphics book, it needs diagrams and equations.   What is the easiest way to do those?  I considered drawing them on paper or a white board and photographing them.   Instead I used a white boarding program, limnu, to make the process more fluid.

For the code, I didn’t want people cut and pasting any code.   I am a big believer in typing it in.   But I also think seeing code is often the best way to communicate something.   So I put in screenshots of code. For the writing, google docs seemed like the path of least resistance and something very fluid.  That is the entire tool chain.

Writing the book this way was fast and fun.   And since 100% of my brain was focused on generating the information rather than fighting layout tools and getting uptight about look, I don’t think the book is any worse than if I had spent five times as long and make it a traditional book.
All in all, I think this is a good way to write some books.   Write it fast, make sure the information is right (for CS writing code as you go ensures this), and stick to a narrow subject with a well-defined goal for the reader.   After the experience I definitely encourage others to write books this way, and I would like to read them.

New mini-book: Ray Tracing in One Weekend

Ray Tracing in One Weekend is a $2.99 Kindle book with an associated blog where I will outline some other one weekend projects (or promote yours-- this is a fun thing to do).  It is very much book for novices to get to a cool picture ASAP.  

Here's the image it ends with:
And interesting aspect of that image is the glass balls seem to float because they may focus light but with a diffuse field that mostly cancels out.  That was news to me and it took me a while to confirm it is no bug.     Try it with a real glass sphere next time it is cloudy :)

Sunday, January 17, 2016

Book project by Eric Lengyel

Eric Lengyel is taking an interesting approach to publishing a technical book-- crowd fund it and self-publish.    I really like Eric's work so getting a nice physical book that will not go out-of-date in my lifetime (math!) shipped to me for $30 is a no-brainer.    Here's the link.

Wednesday, January 13, 2016

Which Perlin noise is the best?

When one says "Perlin Noise" it's not clear which version of the noise function you mean.   Even using it inthe strict sense of which noise Ken Perlin described is not enough-- he has modified it in a later siggraph paper!

I asked Andrew Kensler at Pixar what noise I should use because he knows the most about noise of anybody in my extended ecosystem.   It turns out Andrew has an awesome tool for looking at the Perlin variants and a pointer to other work to help decide for yourself, as well as the best description of noise I am aware of.   It's part of his newwish blog I hope we will see a lot of.   Here's a screen shot of the setting for the original Perlin noise so you can visually compare as you play with variants: