z-fighting問題是三維渲染中常見的問題,本文根據實際工作中遇到的一些場景,進行了系統的總結
一個實際工作中的問題
遇到深度檢測問題,最重要的是先搞明白是哪兩個面離得太近導致的問題。比如上面這個問題,一直以來我都以為是柱子的面跟底圖基礎底面的問題。所以嘗試了各種解決深度檢測的問題都沒起作用。
直到後面一次偶然的嘗試,開啟了CULL_FACE後,這個深度碰撞正常了。思考了很久才想到原來它發生深度碰撞的原因不是跟地圖底面,而是柱子的上頂面跟下頂面離得太近發生的碰撞。恍然大悟!
這張圖的表現很有欺騙性,底面是黑色的,而剛好碰撞部分也是一部分藍,一部分發暗,所以很讓人想當然的認為是底圖跟柱子之間的問題。這個原因是因為預設沒有面剔除,導致底面也被繪製了,而底面的法線方向與光線方向夾角很大,導致最後計算的顏色發暗。所以碰撞部分一部分明亮,一部分發暗。
最終這個問題的解決方式是,開啟CULL_FACE,剔除背面三角形,同時在著色中為頂點增加一點偏移
let parameters = { [GL.DEPTH_TEST]: true, [GL.CULL_FACE]: true, [GL.CULL_FACE_MODE]: GL.FRONT };
// 計算cube該頂點的位置, cube的X座標範圍是-1~1,(rotatedPosition.x * coverage + 1.0) / 2.0座標範圍在0~1之間 // cube的Z座標範圍是-1~1,(rotatedPosition.z * coverage - 1.0) / 2.0座標範圍在-1~0之間 // cubeTopLeftPosition在cube區域性座標系的(-1, 0, -1)位置 vec4 vertexPosition = cubeTopLeftPosition + vec4( vec2( (rotatedPosition.x * coverage + 1.0) / 2.0 * useRadius, (rotatedPosition.z * coverage - 1.0) / 2.0 * useRadius ), 1.0, 1.0 );
深度檢測根本原因
由於z-buffer的精度並不是線性相關的,而是在靠近near平面是精度非常大,但是靠近遠平面時精度非常低,所如果平面離著相機非常遠,那麼就很可能出現深度檢測問題。
解決方法
1. 首先搞明白是哪兩個面發生的深度碰撞
2. 資料層面永遠不要把兩個物體靠的太近,最好在使用者不太注意的地方稍微加一點偏移
3. 將near設定的大一些,這樣使得場景中的物體都在高精度範圍內,但這種方式也是需要調整,near設定的太大,會導致一些應當在視野範圍內的物體被裁切掉
6. 修改投影矩陣的第十位,增加一個小的偏移(http://note.youdao.com/noteshare?id=43a15cadb1afebb1b4ad24a4c159d1e0&sub=37ECF8DF031440D99B69D9CE60850F8A)