February 28, 2021
Hot Topics:

Environment Mapping Techniques

  • By Addison Wesley
  • Send Email »
  • More Articles »

7.3: Refractive Environment Mapping

Now that you have learned how to implement basic environment mapping, you can use it to simulate some related physical phenomena. The techniques you will learn in the following sections illustrate how easy it is to put theory into practice when you are using a high-level language like Cg. The same techniques could be implemented without Cg, but they would require a great deal of assembly-level coding skill. As a result, the techniques and resulting image quality would be out of reach for most developers, even though the effects would be supported by the underlying graphics hardware.

In this section, you are going to learn how to implement refraction using a little physics and a little environment mapping. Figure 7-5 illustrates the effect you will be trying to achieve.

Click here for a larger image.

Figure 7-5. Refractive Environment Mapping

7.3.1: The Physics of Refraction

When light passes through a boundary between two materials of different density (air and water, for example), the light's direction changes. This change in direction happens because light travels more slowly in denser materials (or media, as materials are called in the context of refraction). For example, light travels quickly in air, but more slowly in water. The classic example of refraction is the "bend" that appears in a straw when you place it in a glass of water.

Snell 's Law

Snell's Law describes what happens to light at a boundary (or interface, as such boundaries are called in the context of refraction) between two media, as shown in Figure 7-6. The refracted vector is represented by T, which stands for "transmitted." Snell's Law is expressed mathematically by Equation 7-2. The equation has four variables: the incident angle Ø I , the refracted angle Ø T , and an index of refraction for each medium, n 1 and n 2.

Figure 7-6. Snell 's Law

Table 7-2. Indices of Refraction

Material    Index of Refraction


Different types of glass have different indices of refraction, but 1.5 is a reasonable value for ordinary window glass. It is also a decent approximation for most plastics.

Equation 7-2. Snell's Law

A medium's index of refraction measures how the medium affects the speed of light. The higher the index of refraction for a medium, the slower light travels in it. Table 7-2 lists a few common materials and their approximate indices of refraction. (The index of refraction for a material actually depends not only on the material, but also on the wavelength of the incoming light, but we ignore this complexity for the moment.)

In this example, you will simulate refraction, as shown in Figure 7-7. Each incident ray from the eye is refracted, and each refracted ray is used to look up the environment map (just as each reflected ray was used to look up the environment map in the reflection mapping example).

Notice that we only simulate the first refracted ray. Figure 7-8 shows the difference for a simple object between our approach and a more accurate approach. The incident ray should really be refracted twice—once as it enters the object, and again as it leaves (as the vector T1). However, we do not simulate the second refraction, so we use T instead of T1 as the transmitted ray. The two rays end up intersecting the environment in different locations (labeled A and B in Figure 7-8). Fortunately, refraction is complicated enough that the resulting images are hard to distinguish in most cases. Especially for a casual viewer, it will be hard to tell that the generated refraction is not truly correct.

Figure 7-7. Refraction into an Environment Map

Figure 7-8. Multiple Refractions vs.One

This type of simplification occurs routinely in real-time computer graphics. The thing to remember is that the result is what matters. If your images look convincing, it often doesn't matter that they might be physically inaccurate. In many cases, if you were to compute a complete physical simulation, your frame rate would drop significantly. This is why, from its early days, real-time computer graphics has focused on finding new, efficient techniques to make images look good. Of course, the goal is still to find techniques that are both accurate and fast, but in most cases, the programmer must still make an appropriate trade-off between accuracy and performance.

The Ratio of Indices of Refraction

To calculate refraction, one of the key values you need is the ratio between the index of refraction of each medium. For the next example, the application needs to pass etaRatio, the ratio of indices of refraction of the two media, to the vertex program. Conventionally, the Greek letter n("eta") is used for a single material's index of refraction. However, the ratio of indices of refraction is more efficient in practice, because it saves the vertex program from having to calculate the ratio for each vertex (when it needs to be calculated only once per mesh).

7.3.2 The Vertex Program

Refraction is, in many ways, similar to reflection. In both cases, an incident ray hits a surface and something happens to it (it bounces off in the case of reflection, and it changes direction inside the surface in the case of refraction). These similarities hint that the Cg code for refraction is similar to the code for reflection. And indeed, it is.

The vertex program C7E3v_refraction in Example 7-3 for refraction needs to compute and output the refracted ray, rather than the reflected ray as in C7E1v_reflection. You do not need to apply Snell's Law yourself, because Cg has a refract function that will do it for you. Here is the function definition:

refract(I, N, etaRatio)Given incident ray direction I, surface normal N, and relative index of refraction etaRatio, this function computes refraction vector T, as illustrated in Figure 7-6. The vector N should be normalized. The refracted vector's length is equal to the length of I. etaRatio is the ratio of the index of refraction in the medium containing the incident ray to that of the medium being entered. This function is valid only for three-component vectors.

Here is a sample implementation of the refract Standard Library routine:

float3 refract(float3 I, float3 N, float etaRatio){  float cosI = dot(-I, N);  float cosT2 = 1.0f - etaRatio * etaRatio *                       (1.0f  cosI * cosI);  float3 T = etaRatio * I +             ((etaRatio * cosI - sqrt(abs(cosT2))) * N);  return T * (float3)(cosT2 > 0);}void C7E3v_refraction(float4 position : POSITION,                      float2 texCoord : TEXCOORD0,                      float3 normal   : NORMAL,                  out float4 oPosition : POSITION,                  out float2 oTexCoord : TEXCOORD0,                  out float3 T         : TEXCOORD1,              uniform float etaRatio,              uniform float3 eyePositionW,              uniform float4x4 modelViewProj,              uniform float4x4 modelToWorld){  oPosition = mul(modelViewProj, position);  oTexCoord = texCoord;  // Compute position and normal in world space  float3 positionW = mul(modelToWorld, position).xyz;  float3 N = mul((float3x3)modelToWorld, normal);  N = normalize(N);  // Compute the incident and refracted vectors  float3 I = positionW  eyePositionW;  T = refract(I, N, etaRatio);}

Example 7-3. The C7E3v_refraction Vertex Program

When light passes from a dense medium to a less dense medium, the light can refract so much that total internal reflection occurs. For example, if you are under water in a pool and the surface of the water is smooth enough, the surface of the water will look like a mirror when viewed at a glancing angle. In this case, cosT2 is less than or equal to zero and the refract routine returns a zero vector.

The key difference between the earlier C7E1v_reflection example and the C7E3v_refraction example is the use of the refract function (rather than the reflect function) to calculate the refracted vector T.

7.3.3 The Fragment Program

The fragment program does not have to be changed because its role remains the same: it looks up the environment map based on the incoming vector. The incoming vector is now the refracted vector instead of the reflected vector, but the fragment program still behaves exactly the same way that it did in the reflection mapping example. The fragment program looks up the environment map, mixes the result with the decal texture color, and returns the result. For correctness, the fragment program C7E4f_refraction in Example 7-4 renames reflectedColor to refractedColor and reflectivity to transmittance, but those are only cosmetic changes from the earlier C7E2f_reflection program.

void C7E4f_refraction(float2 texCoord : TEXCOORD0,                      float3 T        : TEXCOORD1,                  out float4 color : COLOR,              uniform float       transmittance,              uniform sampler2D   decalMap,              uniform samplerCUBE environmentMap){  // Fetch the decal base color  float4 decalColor = tex2D(decalMap, texCoord);  // Fetch refracted environment color  float4 refractedColor = texCUBE(environmentMap, T);  // Compute the final color  color = lerp(decalColor, refractedColor, transmittance);}

Example 7-4. The C7E4f_refraction Fragment Program

Page 3 of 5

This article was originally published on March 24, 2003

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date