This project was one of the largest ones so far, but the results were very fun to play with.
Adding reflections was fairly simple, but to make the refraction code nice I had to change my shading function a bit. However, as a result of my new shading function's structure, adding absorption took adding only 5 lines of code.
As far as refractive effects go, my ray tracer does Fresnel reflections via Schlick's approximation, but only when enterering an object; no Fresnel reflections are generated when moving from inside an object to the outside. Absorption is also implemented.
I set a bounce limit of 16 initially. I played around with setting it above that, but the output images didn't noticeably change in any of the scenes I tested, so I left it at 16.
Render times listed below only include actual rendering, not scene file or output image I/O.
All the images were rendered with 4 render threads on my late 2011 Macbook Pro with the following specifications:
This image is fairly standard, it's the provided scene file.
This image is the standard scene, but I added refractivity to the red sphere and got rid of diffuse shading on the blue sphere. The absorption of non-blue colors in the blue sphere should be clear; absorption on the red sphere is less prominent but still visible. It looks pretty cool.
The above two images are the same scene with differing camera positions; the first image has the camera in the position in the provided file, but the second image has the camera inside the blue sphere looking toward the red one. It's based off the provided box scene, but the index of refraction on the blue sphere is turned up quite a bit (2.52). The result when the camera is inside the sphere is interesting.
Putting the camera inside a refractive object exposed a bug in my program. For this image, the camera was in the middle of the blue refractive sphere, and some precision errors in the refraction direction calculation ended up making NaNs that killed about half the pixels in the image.
This is the z-buffer image of the color image above. It is noisy like this because of precision issues, but this can't really be fixed. I included it here because I thought it was a serious bug at first, but once I realized why this is actually the expected output, I stopped worrying about it.