The color patterns in soap bubbles and oil films are caused by a phenomenon called thin film interference. Our goal is to recreate those color patterns in a more or less physically accurate way.
Unlike the scales and hexagon shaders we developed earlier, this shader does not simply generate a color pattern but produces colors that are dependent on the angle of incidence. Because the incidence vector
I
is already provided in OSL as are many vector operations, this irridescence shader is surprisingly simple to implement.surface irridescence ( float nmedium = 1, // approximate refractive index of air float nfilm = 1.3, // approximate refractive index of water float d = 1000, // 1000 nm = 1 micron output color Color = 0 ) { // condition for constructive interference: // 2 * nfilm * d * cos(t2) == (m-0.5)*lambda // d and lambda in nm float eta = nmedium/nfilm; // note that N should be the perturbed normal vector T = normalize(refract(I,N,eta)); // no need to divide by (len(-I) * len(T)) as these are normalized float cost2 = dot(-I , T); float opd = 2*nfilm*d*cost2; int mmin = int(ceil(opd/750+0.5)); int mmax = int(floor(opd/350+0.5)); // if mmax < mmin the film is too thin to show an effect int m = (mmin + mmax)/2; if (m > 0){ float lambda = opd / (m - 0.5); color c = wavelength_color(lambda); Color = c; } }
In the code shown above the trick is that we calculate the length of the optical path
opd
first and then (in line 18) calculate the minimum and maximum number of wavelengths (plus a half to correct for a phase shift, check the Wikipedia article to see why) that fit in this path. The minimum number of wavelengths is calculated by dividing by the wavelength of the longest waelength we can see (red, 750 nm), the maximum by dividing by the shortest wavelength (blue, 350 nm). If the film is too thin, mmin
will be smaller tban zero.The next step is to pick any integer that lies between those extremes (line 21) and calculate the wavelength
lambda
that corresponds with this integer (line 24). The final trick is converting this wavelength to a RGB-color with OSLs built-in wavelength_color()
function.
No comments:
Post a Comment