CS 381 Fall 2013  >  Lecture Notes for Friday, October 25, 2013

CS 381 Fall 2013
Lecture Notes for Friday, October 25, 2013

Splines (cont’d)

See the Wednesday, October 23, 2013 lecture notes.

Front & Back of Polygons

Front- & Back-Facing

When a polygon is rendered, the user only sees one side of it, in any single animation frame. Thus each rendered polygon is either front-facing or back-facing. Which of these two categories a polygon lies in is determined by OpenGL at the end of Vertex Processing, after clipping.

For a primitive containing separate polygons (GL_TRIANGLES, GL_QUADS, GL_POLYGON), a front-facing polygon is one in which the vertices appear in the viewport in counterclockwise order. The vertices of a back-facing polygon appear in clockwise order.

Image not displayed: front-facing and back-facing triangles

For a primitive describing a ribbon of triangles (GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN), the above technique is used to determine whether the first polygon in the ribbon is front-facing. Then the rest are handled in a consistent manner, so that one side of the ribbon is the front, and the other is the back.

Image not displayed: front and back of a triangle strip

Lastly, GL_QUAD_STRIP is handled just as if it were GL_TRIANGLE_STRIP.

An important point:

You can reverse the vertex order used for front-facing determination. Call glFrontFace with parameter GL_CW to make clockwise vertex order indicate a front-facing polygon, and counter-clockwise order a back-facing polygon.

[C++]

glFrontFace(GL_CW);

Pass GL_CCW to restore the default behavior.

A GLSL fragment shader can determine whether the current fragment comes from a front- or back-facing polygon by reading gl_FrontFacing, a predefined bool.

Culling

Many objects are drawn so that the user never sees the back side of any polygons. Thus, if we avoid drawing them, we may save time. Throwing out polygons is called culling; when we throw out back-facing polygons, it is back-face culling. In the pipeline, culling is done at the end of Vertex Processing, after clipping.

In OpenGL, turn on culling with

[C++]

glEnable(GL_CULL_FACE);

and turn it off with the corresponding glDisable call.

OpenGL can cull back-facing polygons, front-facing polygons, or (oddly) both. Determine which is done using glCullFace, passing GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK. For example, to do back-face culling:

[C++]

glCullFace(GL_BACK);  // This is the default setting

We can produce the same effect in a fragment shader—although it is less efficient, since it requires the polygon to be rasterized:

[GLSL fragment shader]

if (!gl_FrontFacing)
    discard;

Note that back-face culling can be used as a simple HSR method. It works when the only thing drawn is a convex object (sphere, cube, etc.), with all polygons facing outward. More generally, it also works when many such objects are drawn, in back-to-front order.

Another application of culling is to render the two sides of a surface using different shaders. Render using one shader with back-face culling enabled, and render using another shader with front-face culling enabled.

Two-Sided Coloring

We may wish a shader to color the two sides of a polygon differently.

GLSL supports automatic choosing of different colors for front-facing and back-facing polygons. I am not terribly fond of this automatic method, but here it is.

To enable distinct front & back colors, do (in your application):

[C++]

glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);

Apparently some implementations also require the following in the vertex shader (and it does not seem to hurt):

[GLSL vertex shader]

#extension GL_VERTEX_PROGRAM_TWO_SIDE : enable

If you do the above, then you need to set both gl_FrontColor and gl_BackColor in the vertex shader. In the fragment shader, gl_Color is set to the interpolated color value, as usual. However, for back-facing polygons, the value of gl_BackColor is used. For front-facing polygons, the value of gl_FrontColor is used, as before.

Again, I am not fond of the above method, since it requires shader functionality to be enabled in the application; it seems to me that this is putting information in the wrong place. I prefer to send the color for back-facing polygons in my own varying variable.

[GLSL vertex shader]

varying vec4 mybackcolor;
...
gl_FrontColor = ...;  // Color for front-facing polygon
mybackcolor = ...;    // Color for back-facing polygon

[GLSL fragment shader]

varying vec4 mybackcolor;
...
vec4 mycolor = gl_FrontFacing ? gl_Color : mybackcolor;
    // Select color based on which side the user sees

Alternatively, just hard-code the back-facing color into the fragment shader.

[GLSL fragment shader]

vec4 mycolor = gl_FrontFacing ?  gl_Color
                              : vec4(0.2, 0.7, 0.2, 1.0);
    // Select color based on which side the user sees

Two-Sided Lighting

In order to light both sides of a polygon correctly, reverse the normal when the polygon is back-facing.

[GLSL fragment shader]

if (!gl_FrontFacing)
    mynorm = -mynorm;

For this to work properly, the normals specified for the surface should point toward the front side of the polygons.

See twoside_shaders.zip for examples of shaders that do two-sided coloring/lighting. These shaders are intended for use with useshaders.cpp.

Note: The teapot drawn by glutSolidTeapot has its normals facing outward, as we would expect. However, when we try two-sided lighting with the teapot, we find that, tragically, it has the back side of its polygons facing outward. Thus, the normals point toward the back side of the polygons. This can be fixed using glFrontFace as described above. I suggest doing this fix just before calling glutSolidTeapot and then restoring the default behavior just afterward.

[C++]

glFrontFace(GL_CW);
glutSolidTeapot(1.);
glFrontFace(GL_CCW);

Application useshaders.cpp has been modified so that the teapot is handled as above. The cylinder has also been fixed so that its polygons face outward.

Application bezierpatch.cpp has been similarly modified. (Apparently, the normals generated via enabling GL_AUTO_NORMAL are backwards—or else I am doing something wrong).


CS 381 Fall 2013: Lecture Notes for Friday, October 25, 2013 / Updated: 25 Oct 2013 / Glenn G. Chappell