Acceleration Structure

I implemented a Bounding Volume Hierarchy along the lines of Pharr, Jakob, and Humphreys’s description in Physically Based Rendering 4e, alongside an efficient intersection algorithm for axis-aligned bounding volumes given by Ericson’s Real-Time Collision Detection.

A comparison of render times can be found below. The program was compiled with MSVC using /O2 optimization and /openmp paralellization, and it was run on my laptop’s Intel i7-12700H.

Scene With BVH No BVH
scene4-ambient 0.1s 0.0s
scene4-diffuse 0.1s 0.1s
scene4-emission 0.1s 0.1s
secen4-specular 0.1s 0.1s
scene5 0.1s 1.8s
scene6 0.1s 0.1s
scene7 0.4s 323.3s

Scene render times with BVH vs. without BVH. Notice how using the BVH was actually slower for very simple scenes, since tree traversal is slower than naive for-loops over few elements.

CSE 167 image-grader report. (The high accuracy of 0-10 hot pixels was achieved using precise intersection algorithms described by Wachter, Binder (2019) and Haines et al. (2019), both of which are found in Ray Tracing Gems)

Using the BVH, I was able to render the following scene of a reflective Stanford dragon in a highly reflective box, just for fun.

Stanford Dragon: shininess 70 specular .7 .7 .7, 3840x2160, 2m06s

Transmission

I added transmittance and ior (index of refraction) commands. The implementation is imperfect, as there are some effects missing (e.g. total internal reflection, intersections, shadows etc.). However, the effect is still decently realistic. For example, the following images demonstrate how a transparent sphere warps light at different refractive indices. Notably, a glass ball (ior 1.5) seems to turn the image upside down, which is physically accurate.

Sphere: ior 1.015, 1920x1440, 0m15s

Sphere: ior 1.5, 1920x1440, 0m15s

Just to experiment, I also rendered a few scenes of the Stanford dragon with varying refractive indices and transmittance. These scenes were pretty taxing, and I actually had to implement an approximate squareroot formula to significantly increase performance. Though std::sqrt out-performed my approximation in standalone tests (modern CPUs have a built-in squareroot unit), it drastically slowed down under high volume. I’m not entirely sure why, though.

Stanford Dragon: ior 1.015 transmittance .37 .74 .47, 3840x2160, 16m32s

Stanford Dragon: ior 1.5 transmittance .37 .74 .47, 3840x2160, 26m59s

Stanford Dragon: ior 1.5 transmittance .95 .95 .95, 3840x2160, 26m32s

It’s interesting how chaotic/noisy the final image is, as the refractive index is decently high and the model is quite complex/layered. There are also some dark spots near the tail caused by maxdepth being too low, but increasing maxdepth exponentially increases render times.

Gamma Correction

I also added a colorspace command for scene files which allows input/output colors to be in either linear (default) or sRGB. The original assignment required not performing gamma correction. However, PNGs assume sRGB values, which leads to linear outputs looking harsh/wrong. But since the scenes used values based on those linear outputs, simply adding colorspace output srgb without tweaking the values looked quite odd, as shown below. Note that all of the previously shown images were rendered with colorspace output srgb.

Scene 6: colorspace input linear colorspace output linear, 1920x1440, 0m01s

Scene 6: colorspace input linear colorspace output srgb, 1920x1440, 0m01s

Scene 6: colorspace input srgb colorspace output srgb, 1920x1440, 0m01s