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!