http://software.intel.com/en-us/articles/alternatives-to-using-z-bias-to-fix-z-fighting-issues/
Last Modified On : | October 2, 2008 5:51 PM PDT |
Rate
|
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.
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 D3DXMATRIX mProjectionMat; // Holds default projection matrix D3DXMATRIX mZBiasedProjectionMat; // Holds ZBiased projection matrix // Globals used for Projection matrix float g_fBaseNearClip = 1.0f; float g_fBaseFarClip = 100.0f; // Code indicates no change. ie states 'near and far clipping planes pushed out' but only far appears pushed float g_fNearClipBias = 0.0f; float g_fFarClipBias = 0.5f; // Projection Matrix work around // Best if calculation are done outside of render function. // The "zbiased" projection has it near and far clipping // planes pushed out... D3DXMatrixPerspectiveFovLH( &mZBiasedProjectionMat, D3DX_PI/4,(mProjectionMat._22/mProjectionMat._11), g_fBaseNearClip + g_fNearClipBias, g_fBaseFarClip + g_fFarClipBias ); . . . // Original projection is loaded m_pd3dDevice ->SetTransform( D3DTS_PROJECTION, & mProjectionMat); // Billboards are rendered... // The "zbiased" projection is loaded ... m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mZBiasedProjectionMat); // Posters are rendered... // Original projection is reloaded... g_pd3dDevice->SetTransform( D3DTS_PROJECTION, & mProjectionMat); . . . |
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 D3DVIEWPORT9 mViewport; // Holds viewport data D3DVIEWPORT9 mNewViewport; // Holds new viewport data // Global used for Viewport // Hard coded for ZBIAS of 1 using this formula // MinZ - 256/(2^24-1) and // MaxZ - 256/(2^24-1) // 2^24 comes from the amount of Zbits and the 256 works // for Intel (R) Integrated Graphics, but can be any // multiple of 16. float g_fViewportBias = 0.0000152588f; // Projection Matrix work around // Viewport work around m_pd3dDevice->GetViewport(&mViewport); // Copy old Viewport to new mNewViewport = mViewport; // Change by the bias mNewViewport.MinZ -= g_fViewportBias; mNewViewport.MaxZ -= g_fViewportBias; . . . // Original viewport is reloaded … m_pd3dDevice->SetViewport(&mViewport); // Billboards are rendered … // The new viewport is loaded … m_pd3dDevice->SetViewport(&mNewViewport); // Posters are rendered … // Original viewport is reloaded … m_pd3dDevice->SetViewport(&mViewport); . . . |
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 // Globals used for Depth Bias float g_fSlopeScaleDepthBias = 1.0f; float g_fDepthBias = -0.0005f; float g_fDefaultDepthBias = 0.0f; // Check for devices which support the new depth bias caps if ((pCaps->RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) && (pCaps->RasterCaps & D3DPRASTERCAPS_DEPTHBIAS)) { m_bDepthBiasCap = true; // TRUE, if DepthBias Caps } // Billboards are rendered... // DepthBias work around if ( m_bDepthBiasCap ) // TRUE, if DepthBias supported { // Used to determine how much bias can be applied // to co-planar primitives to reduce z fighting // bias = (max * D3DRS_SLOPESCALEDEPTHBIAS) + D3DRS_DEPTHBIAS, // where max is the maximum depth slope of the triangle being rendered. m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(g_fSlopeScaleDepthBias)); m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW(g_fDepthBias)); } // Posters are rendered... if ( m_bDepthBiasCap ) // TRUE, if DepthBias supported { // DepthBias work around // set it back to zero (default) m_pd3dDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, F2DW(g_fDefaultDepthBias)); m_pd3dDevice->SetRenderState(D3DRS_DEPTHBIAS, F2DW(g_fDefaultDepthBias)); } . . . |
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:
- Intel® Extreme Graphics 2 Home Page provides an in-depth overview of the chipset features and capabilities associated with Intel Extreme Graphics 2.
- 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.
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.