Sometimes it can be useful for highlighting purposes to draw a silhouette edge around a complex object. A silhouette edge defines the outer boundaries of the object with respect to the viewer as shown in Figure 46.
The stencil buffer can be used to render a silhouette edge around an object. With this technique, you can render the object, then draw a silhouette around it, or just draw the silhouette itself [84].
The object is drawn 4 times; each time displaced by one pixel in the x or ydirection. This offset must be done in window coordinates. An easy way to do this is to change the viewport coordinates each time, changing the viewport transform. The color and depth values are turned off, so only the stencil buffer is affected.
Every time the object covers a pixel, it increments the pixel's stencil value. When the four passes have been completed, the perimeter pixels of the object will have stencil values of 2 or 3. The interior will have values of 4, and all pixels surrounding the object exterior will have values of 0 or 1.
Here is the algorithm in detail:
One of the bigger drawbacks of this algorithm is that it takes a large number of drawing passes to generate the edges. A somewhat more efficient algorithm suggested by Akeley[4] is to use glPolygonOffset() to draw an offset depth image and then draw the polygons using GL_LINE polygon mode. The stencil buffer is again used to count the number of times each pixel is written. However, instead of counting the absolute number of writes to a pixel, the stencil value is inverted on each write. The resulting stencil buffer will contain a one wherever a pixel has been drawn an odd number of times. This ensures that lines drawn at the shared edges of polygon faces have stencil values of zero since the lines will be drawn twice. While this algorithm is a little more approximate then the previous algorithm it only requires two passes through the geometry.
The faster algorithm does not generate quite the same result as the first algorithm since it counts even and odd transitions and relies on the depth image to ensure that other non-visible surfaces do not interfere with the stencil count. The differences arise in that boundary edges within one object that are in front of another object will be rendered as part of the silhouette image. By boundary edges we mean the true edges edges of the modeled geometry and do not include the interior shared-face edges. In many cases this artifact is useful as silhouette edges by themselves often do not provide sufficient information about the shape of objects. It is possible to combine the algorithm for drawing silhouettes with an additional step in which all of the boundary edges of the geometry are drawn as lines to produce a hidden line drawing displaying boundary edges plus silhouette edges.
The steps of the combined algorithm are:
Since the algorithm uses an offset depth image it is susceptible to minor artifacts from the interaction of the lines and the depth image similar to those present when using glPolygonOffset() for hidden line drawings.