The goal for my final project was to render prismatic effects. Ideally, I hoped to produce an image where the splitting of light was both obvious as well as beautiful. Unfortunantly, I was not entirely successful. Although I was able to produce images that showed the splitting of light, I was not able to achieve the effects I hoped for.
There were two basic technical issues to solve for this project. The first was representing rgb colors as their component wavelengths, and vice versa. The second was varying the index of refraction of various materials to separate light rays when they hit transparent surfaces. The former turned out to be much more difficult than I anticipated.
Design for Spectrum Class
The most basic addition to lrt for this project was to expand the Spectrum class. I added an array of Floats, which kept track of the energy of that Spectrum at various wavelengths (The visual range is 380 nm to 780 nm, and I divided this up into 5nm buckets.) I also added x, y, and z variables to keep track of the color in it's CIE form.
Of course, various functions were needed to convert to and from the various representations. The conversion from wavelength to RGB is fairly straight forward, although rather expensive. RGB to wavelength was a bit more tricky for me, and I ended up accepting a less than optimal compromise. I decided that all lights in the system would be modeled as black body radiators, according to Plank's law, and I was able to generate the energy at the various wavelenghts according to that.
The hardest thing about the different types of spectra I introduced was keeping them straight. I wanted to avoid changing the code in too many places to handle my special case, but I also wanted to avoid changing back and forth between spectrum and RGB spectral represenations. In the end, I decided for a simplistic approach, which involved adding a "monochromatic" int to each Spectrum. A Spectrum could be in one of three states: 0 meant it was simple a RGB spectrum, with no wavelength information. 1 meant it was a monochromatic spectrum. In this case, the wave_bucket variable was set to indicate the wavelength of the monochromatic light. 2 meant the Spectrum contained energy at many wavelengths.
Design for Refraction
The system currently only supports wavelength effects through glass surfaces. This is a result of the hard coding of various constants involved in determining the angle of refraction based on the wavelength. The index of refraction equation I used was Ni = Nd - (Nb - Ng) * ((W - Wd)/(Wb - Wg)) where Nd is the index of refraction at the sodium D wavelength, and Nb and Ng at the B and G wavelengths. W is the wavelength we are interested in, while Wd, Wb, and Wg are the wavelengths of the D B and G sodium lines. Because all of these figures are found in the literature, I precomputed the math and was left with a single addition and division.
For the sake of simplicity, I decided to divide up full spectrum waves into a series of monochromatic rays as soon as they hit a refracting surface. In reality, this is wasteful, since sometimes it is not necessary to divide the rays completely. For instance, if the spread of the fully divided rays is not discernable at the eye location, there is little point in the extra overhead for the system. Although I planned to go back and experiment with various adaptive methods for this splitting (there are many examples int he literature) I did not have time.
Because the incident angle is known at the time of creation of the SpectralTransmission object for a particular intersection, all of the various transmission angles can be calculated at that time as well. I added an array of Vectors to the SpecralTransmission class to keep track of the exit angles of various wavelengths. Then, during calls to SampleSpecular, the transmission vector would be quickly returned.
This image was the firt that I produced which showed the splitting of light. The picture shows a glass sphere, hanging in front of a spherical area light source, which is slightly off center. The various wavelength effects are only visible on the outer edge of the white light. Essentially, for each bit of the area light, it projected a full spectrum, but because they mostly overlapped, the various spectrums added up to white light everywhere except at the boundaries.
This was the image I presented at the Contest on Friday. This image shows a glass sphere hanging in front of a lit, shinymetal surface. On some monitors, the far left corner of the sphere appears as a bright yellow, slowly fading to a bright red on the right side. On some monitors, it all looks orange. Such are, unfortunantly, the vagaries of monitor differences.
This is the final image I produced, which more clearly shows the various wavelength effects.
Here is the gziped tar file of my source directory. I have compiled and run the program on both sun and linux without problems. The rib file for the bluepurple.tiff is included.