Spectral Decomposition

Raytracing of Dispersive Media

Some time ago, in the german computer magazin c't there was an article stating `not even raytracer [...] can handle dispersive media'. This was motivation for finishing the implementation of spectral ray decomposition within the Light C++ Raytracing Library. The structure had already been ready for this, but it simply needed something like the final `kick'. It turned out, that the usual rgb model is by far to crude to handle this problemacy in a satisfying way. Roughly, the rgb model can be seen as the three colors at wavelengths 450nm, 550nm, 650nm. A spectrum constructed by these three wavelenghts looks like this:

While the lower bar shows the corresponding colors themselves, the upper bar shows the integrated color, integrated from left to right, such that the resulting color becomes white. Clearly the 100nm rgb model is unattractive. It becomes a bit better with 50nm decomposition:

But even 50nm rarely is good enough to produce `smooth' colors for refracted, spectral-decomposed images. At least 25nm should be used:

25nm are ok for most `normal' situations. Nethertheless for extreme cases like direct views through a prisma, 10nm become necessary.

And just for comparision: This is the `exact' spectrum, with the wavelength computed for each pixel (with an gray scale of the same color intensity, spectral sensitivity according to the human eye):

It was not told yet that for a good spectrum not only the spectral resolution is essential, but also the used spectral sensitivity for each color. For the above spectra and the following raytracing simulations, a Gauss function (e^{-x^2}) is used, with an halfwidth of 80nm and peaks of 450nm for the blue channel, 550nm for the green channel and 650nm for the red channel. The intuitive first guess of a halfwidth of 100nm (the distance of the color sensitivity peaks) turns out to produce not so good spectra as with 80nm. Of course, a halfwidth too small also becomes unattractive, in the extreme case of a zero halfwidth (exact wavelength sensitivity), the spectral model becomes equal to the rgb model. So a halfwidth too small turns to approach the unuseable rgb model, while a halfwidth too big results in fading colors. These effects are not shown here, but the C++ source code for these images is available as the demo test program 3D/demo/spectrum/spectrum.cpp) in the Light C++ Library, such that everyone interested in these aspects can play with it.

The spectral color sensitivity is defined via the Spectral class in <3D/spectrum.hpp>. Any spectral behaviour may be defined by overloading the virtual member functions double Spectral::operator()(double lambda) and double Spectral::operator()(double lambda1, double lambda2), with the second function beeing the integral of the first one, i.e. the error function if the spectral sensitivity is the Gauss function. These classes may be used directly for raytracing also.

Images (prisma images generated by <3D/demo/prisma/prisma.cpp>

A first simulation shows a standard scenery with white neon bars shining through a glass prisma on a spherical zebra-horizont, grey in grey due to the colorless objects. A nice image.
When the prisma is rotated, somewhen the case of total reflection occurs, as visible in this monochrome simulation. A nice image.
Now when dispersion is `switched on', the refracted images of the neon bars split up into colorized ones. Here the refraction indices are 1.49, 1.50, 1.51 for red, green, blue respectively. A nice image.
Such a low refraction is quite unrealistic. Using the more realistic values of (1.45,1.5,1.55) with a spectral resolution of a mere 10nm the dispersed images are split up quite a lot. A nice image.
Raytracing dispersed pointlike objects is much more sensitive to spectral resolution than raytracing extended sources like neon bars. If the spectral resolution is too rough, there will be no smooth spectrum but an ensemble of images of the same object, each for one of the scanned wavelength.

For this star-prisma simulation a spectral resolution of 1nm was used, each view ray is split up into 400 rays when entering the first refractive surface!

A nice image.
Since the prisma itself is hardly visible in the former simulation, some additional light source was used here to enlighten the prisma's glass surfaces (it's not perfectly transparent). A nice image.
Why always use triangular plane prismas? It's also effectful to see a sphere dispersing the star light. Something like a radial prisma. Here also a spectral resolution of 1nm was used. A nice image.
Now back to some `earth-near' scenery: 40 glass spheres with dispersion in front of a zebra-horizont (please ignore the far aliasing effects), rendered with 10nm spectral resolution. A nice image.
And, at last: 40 dispersive ikosaeders colorizing the grey horizont (ikosaeders lying at the same positions as the spheres in the above image). A nice image.

© Werner Benger, Jan. 1997
Referenced by the Light Page, accesses.