A Simple Algorithm?
The final myth is that of the natural simplicity and elegance of the ray tracing algorithm. In fact, while it is easy to write a ray tracer in a few lines of code (certain functional ray tracers can be written on the back of a business card), writing a high-performance ray tracer is another story.
David Luebke, an engineer at Nvidia, made the following remark, and it's totally in line with reality: "Rasterization is fast, but needs cleverness to support complex visual effects. Ray tracing supports complex visual effects, but needs cleverness to be fast."
The code for a minimal ray tracer was written by Paul Heckbert to fit on the back of a business card
All you need to do is read a few articles about the optimizations made to ray tracers to see how apt Luebke's remark really is. For example, the most powerful ray tracers don't handle rays independently, but instead use what's known as ray bundles, which optimize performance when the rays have the same origin and a similar direction. That kind of optimization is well suited for the single-instruction multiple-data (SIMD) units found on CPUs and GPUs, and so is very effective for primary rays that have a certain coherence or for shadow rays. But on the other hand, it's not at all suitable for refraction or reflection rays.
Further, as Daniel Pohl points out in his article on Quake Wars RT, using ray bundles can be problematic with transparent textures (the famous alpha textures used for trees), because if all the rays in a bundle don't have the same behavior (some touching the surface and others passing through it), an additional cost can quickly arise that's greater than the gains achieved by using ray bundles.
A visualization of the rendering cost of each pixel, with the red pixels being the most expensive. You can see that rendering the trees is particularly expensive in the ray-traced version of Quake Wars
Finally, as we mentioned, ray tracing requires the right data structure to store the different elements of the scene, and it will play a determining role in the resulting performance. But choosing and then managing that data structure is not easy. Some structures have better characteristics for static data, while others can be updated faster with dynamic data or take up less memory. As always, the key is finding an acceptable compromise. There's no miracle solution.
So as we've seen, ray tracing does not always serve as the model of simplicity and elegance that some make it out to be. Getting good performance with a ray tracer requires the use of just as much programming ingenuity as is used with rasterization to reproduce the most complex effects.