next up previous contents
Next: 11.2.2.3 Advantages and Disadvantages Up: 11.2.2 Dual-Paraboloid Environment Mapping Previous: 11.2.2.1 The Mathematics of   Contents

11.2.2.2 Using Dual-Paraboloid Maps

For the rationale for these transformations, consult Heidrich and Siedel [54]. The implication of this math is that these successive transformations can be concatenated into a single 4 by 4 projective matrix and then installed as OpenGL's texture matrix. Then supplying a per-vertex eye-space reflection normal via glTexCoord3f(), the 3D vector will be transformed into a 2D texture coordinate in a front or back paraboloid map, depending on how $\vec{d}$ is oriented.

An alternative to supplying the reflection vector through glTexCoord3f() is using the NV_reflection_vector extension's capability to generate automatically the eye-space reflection vector for the $(s,t,r)$ texture coordinates. Recall that this is the same extension used in Section 6.15 though we are generating the reflection vector instead of the normal vector. Assuming the extension is available, here is how to generate the eye-space reflection vector as a 3D texture coordinate:

  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_NV);
        
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_GEN_T);
  glEnable(GL_TEXTURE_GEN_R);
Here is how to set up OpenGL's texture matrix given the transformation described above:
  GLfloat mapMatrix[16] = {
    0.5, 0,   0,  0,
    0,   0.5, 0,  0,
    0,   0,   1,  0,
    0.5, 0.5, 0,  1
  };
  GLfloat projectMatrix[16] = {
    1,  0,  0,  0,
    0,  1,  0,  0,
    0,  0,  1,  1,
    0,  0,  0,  0
  };
  GLfloat diffFrontMatrix[16] = {
    -1,  0,  0,  0,
     0, -1,  0,  0,
     0,  0,  1,  0,
     0,  0, -1,  1
  };
  GLfloat diffBackMatrix[16] = {
    1,   0,  0,  0,
    0,  -1,  0,  0,
    0,   0,  1,  0,
    0,   0,  1,  1
  };
  GLfloat mv[16], ilmv[16];

  glGetFloatv(GL_MODELVIEW_MATRIX, mv);  
  mv[3]  = 0;
  mv[7]  = 0;
  mv[11] = 0;
  mv[12] = 0;
  mv[13] = 0;
  mv[14] = 0;
  mv[15] = 1;
  invert_matrix(mv, ilmv);

  glMatrixMode(GL_TEXTURE);
  glLoadIdentity();
  glMultMatrixf(mapMatrix);
  glMultMatrixf(projectMatrix);
  if (frontSide)
    glMultMatrixf(diffFrontMatrix);
  else
    glMultMatrixf(diffBackMatrix);
  glMultMatrixf(ilmv);


% latex2html id marker 12846
\fbox{\begin{tabular}{c}
\vrule width 0pt height 0....
...igure \thefigure . The Sweet Circles of a Dual-Paraboloid Map}\\
\end{tabular}}

Each dual-paraboloid texture contains an incomplete version of the environment. The two texture maps overlap as shown in Figure 75 at the corner of each image. The corner regions in one map are distorted so that the other map has better sampling of the same information. There is also some information in each map that is simply not in the other map; for example, the information in the center of each map is not shared. Figure 76 shows that each map has a centered circular region containing texels with better sampling than the corresponding texels in the other map. We call this centered circular region of each dual-paraboloid map the sweet circle.

What remains to be done is making sure that the front dual-paraboloid map is used for pixels best sampled from the front dual-paraboloid map and vice versa. In the projective transformation discussed above, if a reflection vector falls within the sweet circle of one dual-paraboloid map, it will be guaranteed to fall outside the sweet circle of the opposite map.

With OpenGL's alpha testing capability, we can discard texels outside the sweet circle of each texture. The idea is to encode in the alpha channel of each dual-paraboloid texture an alpha value of 1.0 if the texel is within the sweet circle and 0.0 if the texel is outside the sweet circle. Be conservative about whether a texel is inside the circle to avoid in cracks the transition between the two maps.

Now, we can render an object in two passes. First, bind to the front dual-paraboloid texture and use a $\vec{d}$ value of $(0,0,-1)$ when constructing the texture matrix. Then in a second pass, bind to the back dual-paraboloid texture and use a $\vec{d}$ value of $(0,0,1)$ when constructing the texture matrix. During both passes, enable alpha testing to eliminate fragments with an alpha value less than 1.0. Set up the texture environment to make the fragment's alpha value be the texture's alpha value. The result is a complete dual-paraboloid mapped object.

When multitexturing is available, the two passes can be collapsed into a single multitextured rendering pass. As described in Section 6.2, each texture unit has its independent texture matrix. We load the first texture unit to use the front texture matrix and the second texture unit to use the back texture matrix. The first texture unit uses a GL_ REPLACE texture environment while the second texture unit uses a GL_ BLEND texture environment. This effect is to blend the two textures based on the alpha component of the second texture. One side benefit of the multitextured approach is that the transition between the two dual-paraboloid map textures is harder to notice. Even with simple alpha testing the seam is quite difficult to notice.


next up previous contents
Next: 11.2.2.3 Advantages and Disadvantages Up: 11.2.2 Dual-Paraboloid Environment Mapping Previous: 11.2.2.1 The Mathematics of   Contents
2001-01-10