解決方案:
1, 在每個場景中,找到那個MainCamera,然后在Inspector上,找到MainCamera的屬性,Clipping Planes,需要做的是盡量放大near的值,盡量減小far的值。根據我的實驗結果,同樣改動Near值的幅度比Far值的幅度相對來說效果會更好。如Near從1到20可能修正了某個z-fighting,但是Far從1000改到500也還是沒有用。這個在實踐中可以注意。
2, 如果場景沒有辦法改動上述的值,那么還有的方式就是找到產生z-fighting的模型,讓模型產生這個現象的兩個面盡量離開一些距離,究竟多少距離只有通過實驗才知道。
3, 如果可能,程序上就可以用Polygon Offset,這個是OpenGL的接口,
- drawOnePlane();
- //Draw other plane in the almost same position, before use offset, it will fighting with the one we has drawn.
- glEnable( GL_POLYGON_OFFSET_FILL );
- glPolygonOffset( g_OffsetFactor, g_OffsetUnit );
- drawOtherPlane();
- glPolygonOffset( 0.0f, 0.0f );
- glDisable( GL_POLYGON_OFFSET_FILL );
4、如果是D3D,那么這篇文章提到3中方式,最后一種方式是跟上面的OpenGL思路一樣的。
http://software.intel.com/zh-cn/articles/alternatives-to-using-z-bias-to-fix-z-fighting-issues/
a, project matrix
- // 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);
- . . .
b, view port matrix
- // 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);
- . . .
c, depth - bias
- 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));
- }
- . . .
5,這里還有一篇文章教到怎么樣在面上畫出線的,相信你也會遇到同樣的問題。當然,核心還是用depth-bias,但是,人家把怎么做和做的時候要注意的問題都寫上了(主要就是用bias的時候值不要取的太大,否則線框是渲染出來了,但是也同時多出線來了,因為本來是該本剪切的,經過修正可能就不被剪切了)。值得一看。
http://www.catalinzima.com/samples/12-months-12-samples-2008/drawing-wireframes-without-z-fighting/
背景原理:
z-fighting的出現是的不同面上的像素在z-buffer中的值相近,導致前台取像素的時候一會去這個面的,一會取那個面的。改變照相機的near、far屬性會涉及到z-buffer中的值的精度。因為在各個平台上z-buffer位數不同,因此改變near和far能給z-buffer中的值的浮點數部分盡量留出空間,消除z-fighting。
這個是wiki上的z-fighting的例子,可以看到不同色彩的面,因為z-buffer的精度設置的小,然后兩個面放置的比較近,因此出現了相關的穿插顯示的問題。