Soap bubbles—a view-dependent shader

Some materials change the way they look depending on the angle at which we look at them. Bird feathers, some fancy car paints, oil spills on water, and soap bubbles are some examples. This phenomenon of changing colors is known as iridescence. If we want to implement something like that we need access to the view vector and the surface normal. In our soap bubble shader we see one way of doing this.

First some mathematics: Why is it that soap bubbles show all those different colors? Soap bubbles are basically curved sheets of water (with a little soap), and at the interface between air and water, light is reflected. An incident ray will therefore be partially reflected when it hits the outer surface of the bubble and be reflected again when it reaches the inner surface. The reflected light that reaches the eye is therefore a mixture of light that has traveled different distances; part of it has traveled the extra distance of twice the thickness of the soap bubble.

Now, light behaves like a wave and waves that interfere can either dampen or amplify each other depending on their phase, and two light rays that have traveled distances whose difference is not an exact multiple of their wavelength will cancel each other. The result is that white light (a continuum of colors) reflecting off a soap bubble with a thickness equal to half the wavelength of some specific color will show only that single color because all of the other colors are dampened as they do not "fit" properly between the inner and outer surface. (There is much more to soap bubbles. For more and more accurate information refer to: http://www.exploratorium.edu/ronh/bubbles/bubble_colors.html.)

Soap bubbles—a view-dependent shader

Now we know that the distance traveled between the two reflecting surfaces determines the color we perceive, we can also understand why there will be color variations in a soap bubble. The first factor is the curvature of the bubble. The distance traveled will be dependent on the angle between the incident light and the surface: the shallower this angle, the longer the distance the light has to travel between the surfaces will be. As the angle of incidence changes as the surface curves so will the distance and, hence the color. The second source of color variation is the unevenness of the surface; slight variations due to gravity or swirls caused by air currents or temperature differences also cause different colors.

All this information translates to a surprisingly short piece of code (the full code is available as irridescence.py in irridescence.blend together with a sample node setup).

Beside the coordinates, we have two input sockets—one for the thickness of the water film and one for the variation. The variation will get added to the thickness and can be hooked up to a texture node to generate swirls and the like. We have a single output socket for the calculated distance:

class Iridescence(Node.Scripted):
def __init__(self, sockets):
sockets.input = [ Node.Socket('Coords', val= 3*[1.0]), Node.Socket('Thickness', val=275.0, min=100.0, max=1000.0), Node.Socket('Variation', val=0.5, min=0.0, max=1.0)]
sockets.output = [Node.Socket('Distance', val=0.5, min=0.0, max=1.0)]

The calculations of the reflected color start off with getting a list of all lamps in the scene as we will want to calculate the angle of the incident light rays. For now, we take into account only the contribution of the first lamp that we find. However, a more complete implementation would consider all lamps and maybe even their color. For our calculations we have to make certain that the surface normal N and the incidence vector of the light L are in the same space. As the surface normal provided will be in camera space we will have to transform this vector by the transformation matrix of the camera as we did for our slope-dependent shader (highlighted in the following code snippet):

def __call__(self):
P = vec(self.input.Coords)
scn=Scene.GetCurrent()
lamps = [ob for ob in scn.objects if ob.type == 'Lamp']
lamp = lamps[0]
cam=scn.objects.camera
rot=cam.getMatrix('worldspace').rotationPart().resize4x4();
N = vec(self.shi.surfaceNormal).normalize().resize4D() * rot

N = N.negate().resize3D()
L = vec(lamp.getLocation('worldspace'))
I = (P L).normalize()

Next, we calculate the angle between the surface normal and the incidence vector (VecT is an alias for Mathutils.angleBetweenVecs()) and use this incidence angle to calculate the angle between the surface normal inside the water film as this will determine the distance the light travels. We use Snell's law to calculate this and use 1.31 as the index of refraction of the water film. Calculating the distance is then a matter of simple trigonometry (highlighted below):

angle = VecT(I,N)
angle_in = pi*angle/180
sin_in = sin(angle_in)
sin_out = sin_in/1.31
angle_out = asin(sin_out)
thickness = self.input.Thickness + self.input.Variation
distance = 2.0 * (thickness / cos (angle_out))

The calculated distance is equal to the wavelength of the color that we will perceive. However, Blender does not work with wavelengths but with RGB colors so we still need to convert this wavelength to a (R, G, B) tuple that represents the same color. This might be done by applying some spectral formula (see for example http://www.philiplaven.com/p19.html) but it might even be more versatile to scale this calculated distance and use it as an input for a color band. In this way we might produce non-physically accurate iridescence (if desired):

self.output.Distance = distance

To use this Pynode there are some things to keep in mind. First, make sure that the calculated color only affects the specular color of the soap bubble material otherwise everything will show up washed out.

Furthermore, it is important to add some variation to the thickness of the layer as no real soap bubble has an exactly uniform thickness. The choice of noise texture can make quite a difference to the appearance. In the next node setup example, we have added the contribution of a slightly noisy wood texture to obtain the swirly bands often seen on soap films.

Finally, make the material of the soap film very transparent but with a high specular reflectance. Experiment with the values to get the exact effect desired and do take into account the lighting setup. The example shown in the illustration has been tweaked to get some of the issues across in a black and white rendition and is therefore not realistic, but the setup in the example file iridescence.blend is tweaked to produce a pleasingly colorful result when rendered.

Soap bubbles—a view-dependent shader

The use of a color ramp and a noise texture is shown in the previous screenshot where we added some division nodes to scale our distance to a range within [0,1] that can be used as input for the color ramp:

Soap bubbles—a view-dependent shader
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.5.15