# Environment Mapping Techniques

### 7.4 The Fresnel Effect and Chromatic Dispersion

You now know how to implement reflection and refraction. The next example combines them and throws in a few other extensions. You will learn about two new effects: the Fresnel effect and chromatic dispersion.

#### 7.4.1 The Fresnel Effect

In general, when light reaches an interface between two materials, some light reflects off the surface at the interface, and some refracts through the surface. This phenomenon is known as the *Fresnel effect* (pronounced "freh-'nell"). The Fresnel equations describe how much light is reflected and how much is refracted. If you have ever wondered why you can see fish in a pond only when you're looking practically straight down, it's because of the Fresnel effect. At shallow angles, there is a lot of reflection and almost no refraction, so it is hard to see through the water's surface.

The Fresnel equations, which quantify the Fresnel effect, are complicated. (You can learn more about them in most optics textbooks.) Once again, the idea here is to create images that look plausible, not necessarily to describe accurately the intricacies of the underlying physics. So, instead of using the equations themselves, we are going to use the empirical approximation in Equation 7-3, which gives good results with significantly less complication:

**Equation 7-3. An Approximation of the Fresnel Equation**

The concept underlying this equation is that when *I* and *N* are nearly coincident, the reflection coefficient should be 0 or nearly 0, indicating that most of the light should be refracted. As *I* and *N* diverge, the reflection coefficient should gradually increase and eventually abruptly increase (due to the exponentiation) to 1. When *I* and *N* are sufficiently divergent, almost all the light should be reflected, with little or none of it being refracted.

The range of the reflection coefficient is clamped to the range [0, 1], because we use the reflection coefficient to mix the reflected and refracted contributions according to the following formula (where *C* stands for color):

*Click here for a larger image.*

**Figure 7-9. Understanding Chromatic Dispersion**

#### 7.4.2 Chromatic Dispersion

The earlier discussion of refraction was somewhat simplified. We mentioned that refraction depends on the surface normal, incident angle, and ratio of indices of refraction. In addition to these factors, the amount of refraction also depends on the wavelength of the incident light. For example, red light gets refracted more than blue light. This phenomenon is known as*chromatic dispersion*, and it is what happens when white light enters a prism and emerges as a rainbow.

Figure 7-9 illustrates chromatic dispersion conceptually. The incident illumination (assumed to be white) is split into several refracted rays. You will simulate what happens to the red, green, and blue components of the light, because these are the standard components of colors in computer graphics. You will use the refracted red, green, and blue rays to look up into the environment map, just as you did for a single ray in the refraction example.

Keep in mind that real light is a band of wavelengths rather than three particular and discrete wavelengths. Still, this approximation is effective enough to be useful.

*Click here for a larger image.*

**Figure 7-10. The Fresnel Effect and Chromatic Dispersion**

Combining the Fresnel effect with chromatic dispersion creates a rainbow effect, as if the rendered object were made of crystal, as shown in Figure 7-10. Plate 11, in the book's center insert, shows this image in color.

#### 7.4.3 Application-Specified Parameters

Because we are now using a more complicated lighting model for our object's surface, the application needs to send extra uniform parameters to the vertex and fragment programs. These additional parameters are listed in Table 7-3.

The ` x`,

`, and`

**y**`components in etaRatio, respectively, store the ratio of indices of refraction for red, green, and blue light. The`

**z**`,`

**fresnelPower**`, and`

**fresnelScale**`variables provide a way to shape the function that we use to approximate the Fresnel equations. Together, all the application-specified parameters define the material properties of your object.`

**fresnelBias****Table 7-3. The** `C7E5v_dispersion` **Program Parameters**

Parameter | Variable Name | Type |

Ratio of indices of refraction for red, green, and blue light (packed into one float3) | etaRatio | float3 |

Fresnel power | fresnelPower | float |

Fresnel scale | fresnelScale | float |

Fresnel bias | fresnelBias | float |

#### 7.4.4 The Vertex Program

The ` C7E5v_dispersion` vertex program in Example 7-5 calculates the reflected vector, along with red, green, and blue refracted vectors. In addition, you will use the approximation of Fresnel's formula to compute the reflection coefficient. All this information is then interpolated and received by the fragment program.

##### Calculating the Reflected Vector

The reflected vector calculation stays the same:

R =reflect(I, N);

##### Calculating the Refracted Vectors

You compute refracted vectors using an approach that is similar to the one that you used in the earlier refraction example. The difference is that now you have to calculate a refraction vector for each color component, instead of just one that applies equally to red, green, and blue:

TRed =refract(I, N, etaRatio.x);TGreen =refract(I, N, etaRatio.y);TBlue =refract(I, N, etaRatio.z);

Recall that the ` x`,

`, and`

**y**`components in`

**z**`respectively store the ratio of indices of refraction for red, green, and blue light.`

**etaRatio**voidC7E5v_dispersion(float4position :POSITION,float3normal :NORMAL,out float4oPosition :POSITION,out floatreflectionFactor :COLOR,out float3R :TEXCOORD0,out float3TRed :TEXCOORD1,out float3TGreen :TEXCOORD2,out float3TBlue :TEXCOORD3,uniform floatfresnelBias,uniform floatfresnelScale,uniform floatfresnelPower,uniform float3etaRatio,uniform float3eyePositionW,uniform float4x4modelViewProj,uniform float4x4modelToWorld){ oPosition =mul(modelViewProj, position); // Compute position and normal in world spacefloat3positionW =mul(modelToWorld, position).xyz;float3N =mul((float3x3)modelToWorld, normal); N =normalize(N); // Compute the incident, reflected, and refracted vectorsfloat3I = positionW eyePositionW; R =reflect(I, N); I =normalize(I); TRed =refract(I, N, etaRatio.x); TGreen =refract(I, N, etaRatio.y); TBlue =refract(I, N, etaRatio.z); // Compute the reflection factor reflectionFactor = fresnelBias + fresnelScale *pow(1 +dot(I, N), fresnelPower);}

**Example 7-5. The** `C7E5v_dispersion` **Vertex Program**

##### Calculating the Reflection Coefficient

Translating Equation 7-3 into Cg code is straightforward. Use the dot and pow functions. The program outputs reflectionFactor as an interpolated color, as indicated by its associated COLOR semantic. Interpolated colors are automatically clamped to the range [0, 1], so there is no need to perform this clamping explicitly.

reflectionFactor = fresnelBias + fresnelScale *pow(1 +dot(I, N), fresnelPower);

#### 7.4.5 The Fragment Program

The ` C7E6f_dispersion` fragment program in Example 7-6 receives all the interpolated data for the reflected and refracted vectors, along with the reflection coefficient that is clamped to [0, 1]. The fragment program looks up the various reflected and refracted vectors in an environment map and blends the results appropriately. Notice that the program expects the same environment cube map texture for each of the four texture units. The application must bind the environment map to each of these four texture units, because the program is written to run on both basic and advanced fragment profiles. Recall that basic fragment profiles can only sample a given texture unit with that texture unit's corresponding texture coordinate set, so the environment map must be replicated. Advanced fragment profiles do not have this limitation, so a single

`cube map sampler would suffice.`

**environmentMap**##### Performing the Texture Lookups

First, the program performs four cube map lookups—one for the reflected color, and one for each component of the three refracted colors:

// Fetch the reflected environment colorfloat4reflectedColor =texCUBE(environmentMap0, R);// Compute the refracted environment colorfloat4refractedColor;refractedColor.r =texCUBE(environmentMap1, TRed).r;refractedColor.g =texCUBE(environmentMap2, TGreen).g;refractedColor.b =texCUBE(environmentMap3, TBlue).b;

For each of the three refracted texture lookups, the program uses swizzling to extract only the matching color component. That is, you extract the red component of the texture value sampled at ` TRed`, the green component of the texture value sampled at

`, and the blue component of the texture value sampled at`

**TGreen**`. The program then combines the respective`

**TBlue***r*,

*g*, and

*b*components of

`.`

**refractedColor**voidC7E6f_dispersion(floatreflectionFactor :COLOR,float3R :TEXCOORD0,float3TRed :TEXCOORD1,float3TGreen :TEXCOORD2,float3TBlue :TEXCOORD3,out float4color :COLOR,uniform samplerCUBEenvironmentMap0,uniform samplerCUBEenvironmentMap1,uniform samplerCUBEenvironmentMap2,uniform samplerCUBEenvironmentMap3){ // Fetch the reflected environment colorfloat4reflectedColor =texCUBE(environmentMap0, R); // Compute the refracted environment colorfloat4refractedColor; refractedColor.r =texCUBE(environmentMap1, TRed).r; refractedColor.g =texCUBE(environmentMap2, TGreen).g; refractedColor.b =texCUBE(environmentMap3, TBlue).b; refractedColor.a = 1; // Compute the final color color =lerp(refractedColor, reflectedColor, reflectionFactor);}

**Example 7-6. The** `C7E6f_dispersion` **Fragment Program**

##### Computing the Final Result

Finally, the program blends the reflected and refracted colors according to the fraction given by the reflection factor:

color =lerp(refractedColor, reflectedColor, reflectionFactor);

And there you have it: the Fresnel effect with chromatic dispersion.

Page 4 of 5