by Matt McClellan and Kipp Owens
There are many instances in 3D applications where two polygons may lie on the same plane, as in the cases of effects like bullet holes or posters on walls. Because these polygons lie on the same plane, they share the same z-buffer values, and this can result in "z-fighting" issues, where results vary based on rendering order. In the past, DirectX* allowed developers to resolve z-fighting issues by applying a “z-bias” to co-planar polygons. While applying a z-bias is an effective solution, it does not generate the same results on all graphics hardware.
Unfortunately, in versions of DirectX prior to DirectX 9, different graphics vendors interpreted the DirectX specification details on the z-bias feature differently. As a result, different graphics vendors applied slightly different algorithms to address the application of z-bias. Worse, a legacy of applications taking these different driver behaviors into account meant that the different hardware vendors could not subsequently change their driver behaviors to be more consistent.
For the developer community, this ambiguity resulted in a lot of custom ‘tweaking’ of the z-bias values and subsequent testing across a wide array of hardware; in short, each piece of hardware might behave differently. Microsoft has resolved this issue in DirectX 9 by replacing z-bias with "depth-bias," in hopes of providing a more predictable and uniform technique for removing z-fighting issues.
The D3DRS_ZBIAS render state was used on DirectX 8 and earlier applications, while the D3DRS_DEPTHBIAS render state is used in DirectX 9. This article outlines three alternatives to using the legacy method of D3DRS_ZBIAS.
Figure 1 above shows the affects of z-fighting on co-planar polygons. ZFightingDemo is a modified version of Billboard, available in the DirectX SDK, that demonstrates z-fighting.
Alternative Method 1: Projection Matrix
The first method considered here is the use of a new projection matrix. This new projection matrix is loaded with near and far clipping planes pushed out (away from the viewer). The new, 'closer' projection matrix is loaded after the 'far' object and before the object or objects that the developer would like to appear in front. The desired 'front' objects are effectively placed closer to the viewer in the z-buffer, but their location in the view space is not noticeably changed. The sample code below accomplishes this technique. In this case it is applying a z-bias to the posters.
The following code snippet shows the Projection Matrix alternative to using a DirectX z-bias call:
// ZFighting Solution #1 - Projection Matrix
While some adjustments to the projection matrix may still be necessary to get the desired results, this technique is more consistent across a variety of graphics hardware. The result of the alternate solution is pictured below:
Alternative Method 2: Viewport
The viewport method is similar to the projection matrix method, in that it effectively pushes the selected object nearer to the user in the z-buffer. The viewport method achieves this resolution by loading a new viewport object with new minimum and maximum z-values. The sample of code below accomplishes this by applying a z-bias to the posters, so that they are correctly displayed on the billboards.
The following code snippet shows the viewport alternative to using a DirectX z-bias call:
// ZFighting Solution #2 - Viewport
Again, some adjustments to the new viewport values may still be necessary to get the desired results, but this technique is more consistent across a variety of graphics hardware than using z-bias. The hard-coded example above is the equivalent of D3DRS_ZBIAS = 1. The result of the alternate solution is pictured below:
Alternative Method 3: Depth Bias
The last method addressed in this article uses the DirectX 9 Depth Bias method to solve z-fighting. A check to verify that the graphics card is capable of performing depth bias is needed. Intel Integrated Graphics will support depth bias in the next graphics core code named Grantsdale. After checking the cap bits to verify that depth bias is supported, this technique merely requires setting D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS to the proper values to get the desired effect.
The following code snippet shows the depth-bias alternative to using a DirectX z-bias call:
BOOL m_bDepthBiasCap; // TRUE, if device has DepthBias Caps
Like the other methods (and like the original z-bias), some tweaking may be necessary, but using D3DRS_SLOPESCALEDEPTHBIAS and D3DRS_DEPTHBIAS is a relatively consistent technique for resolving z-fighting issues across a wide selection of graphics devices. The figure below shows the result of this alternate solution:
Z-fighting is an inevitable issue when dealing with co-planar polygons. The three methods shown in this paper – loading a new projection matrix, loading a new viewport, and using the new DirectX 9 Depth Bias – can all be used as alternatives to z-bias with broad success. These techniques cannot eliminate the need for solid testing, but they can limit the amount of tweaking that is required as new problems arise stemming from the inconsistent behavior of z-bias.
The included sample code provides the developer with simple examples of z-bias alternatives that can be used to eliminate z-fighting.
The following materials will be of particular interest to the audience of this article:
- Microsoft DirectX** contains the DirectX* runtime and software required to create DirectX-compliant applications.
- ATI Depth Bias Example* is a sample application that demonstrates the use of depth bias to eliminate z-figh ting.
- Intel® Digital Media Developer Center provides insight, tips, tools, and training to create top-notch media applications.
- Intel® Games Developer Center presents coding resources for game developers on Intel® architecture.
About the Authors
Matt McClellen is a applications engineer with Intel Corporation in Folsom, CA. He has held various positions since joining Intel in 1996. His current focus is predominantly in the area of software optimization. He has a Bachelors of Science in Computer Engineering from California State University, Sacramento.
Kipp Owens (photo not available) is an applications engineer with Intel Corporation in Folsom, CA.