For my final project for the class I wanted something that could be developed as a co-project with CPE 419 Applied Parallel Computing. To that end, I decided to implement a ray tracer in C++ that involved parallelizing code using Nvidia's CUDA framework. Ray tracing lends itself well to parallelization for a few reasons, but I eventually decided to take advantage of the independent nature of the ray-sphere intersection calculation.
To step back and explain the ray tracing a bit (feel free to skip this paragraph if you know what ray tracing is), the basic idea is that light is simulated via "backwards ray tracing" where a light ray is traced from the eye/camera to each individual pixel and beyond to check if any object intersects with that ray. If multiple objects intersect with the ray, then the closest object is chosen and the pixel is colored according to a Phong shading calculation. A final check for the color is determined by sending a "shadow ray" from the point of intersection to the light source and checking for any objects between the light and the object. If a blocking object is detected, the point is then "in shadow" and only colored using ambient lighting.
My ray tracer supports both spheres and planes for object intersection, along with both Phong shading and shadows. Test cases are hard coded (future work will most likely include implementing a POV file reader to allow for more complex scenes), but are easily modified to change the scene. It has been tested with up to 103,823 spheres, but could theoretically handle larger numbers as long as you are willing to wait for it to render!
While my parallel implementation did not see an amazing speed-up (I had hoped for 10x or more) it still saw a speed-up of roughly 2x, with 3x seen for the 100k sphere test (meaning the gap should continue to widen with more spheres). Times comparing the serial and parallelized run times are given below.
Number of Spheres | Serial (using Intel's icpc C++ compiler) | Parallel (using Nvidia's nvcc C++ compiler) |
---|---|---|
2 | 0.077 | 4.910 |
125 | 1.089 | 5.271 |
1,000 | 8.446 | 8.708 |
8,000 | 68.635 | 30.361 |
32,768 | 289.549 | 114.915 |
103,823 | 896.257 | 318.501 |
This project stretched my ability to work with and learn many new technologies at once, while also improving abilities I had been learning throughout the quarter. I used many C++ features for the first time (as this class is the first time I've used the language in any meaningful way), such as classes, operator overloading, and some other STL features. From a graphics perspective most of the challenge came from understanding the math behind the ray casting and ray intersections with spheres and planes, while using stuff I learned this quarter like Phong shading in a non-OpenGL environment. I also improved my ability to convert a serial implementation of a program to a parallel implementation along with my skill using CUDA and interacting with the GPU on a lower level. In addition I gained a better understanding of how to do parallel reductions when attempting to add a minimum reduction to my CUDA kernel for determining the closest sphere.
My main takeaway is a better understanding of how to answer "What color is that pixel?", which is a question I find fascinating!