Camera的Near值對Z-Fighting問題的影響

起因

項目測試報BUG,貼花功能在離相機接近500米處開始閃爍
從閃爍這個表現看基本斷定是Z-Fighting問題,一開始認爲是貼花Shader的問題,但是貼花使用的是類似Projector的方式,這種方式在進行ZTest的時候實際上是進行Projector透射的物體的Z進行比較,導致Z-Fighting的話實際上和貼花沒有太大關係
經過搭建簡單場景來看,也是和貼花沒關係,本質上還是2個Mesh的距離問題導致的Z-Fighting

嘗試解決

嘗試“物理”方式解決是最簡單,粗暴的方法,但是發現兩個Mesh相距超過了0.5個單位仍然出現閃爍(在接近Far平面的地方),過於拉大距離在遠處沒什麼關係,但是在近處,尤其對於貼花功能來說是十分不合適的
這麼大的距離還會造成Z-Fighting開始懷疑是不是Shader內數據精度聲明的有問題,或者是深度緩衝設置的有問題,通過截幀檢查這兩個都沒什麼問題
想起Camera的平面間距也會造成Z-Fighting,所以查看了Camera的平面設置,Near 0.03, Far 500

Near平面

我的關注點集中在了Far平面的設置上,500看起來設置的沒什麼問題,一度陷入無解狀態…
但是始終覺得0.5單位的差距應該在500以內的距離來看,應該不至於造成這麼厲害的Z-Fighting現象,懷疑是哪裏設置的不對,於是嘗試搭個簡單的場景進行差異比對,果然新場景在保證物體擺放位置相同情況下,Z-Fighting沒有出現
比對後,發現項目的Camera中的Near平面是0.03,Unity默認狀態設置的是0.3
但是這麼小的差距難道會造成這麼大的影響?

在這裏插入圖片描述

思考

zndc=f+nfn+2nffn1ze z_{ndc} ={{f+n}\over{f-n}} + {{2nf}\over{f-n}} * {1\over z_e}
這是NDC空間下Z的計算公式,對於Z-Fighting問題來說,關鍵是精度問題,以十進制舉例

  • 1000到5000,跨距很大,但是精度不變
  • 0.1到0.01,跨距很小,但是0.01的精度變大了

通過將Far從500調整到600,可以代入發現最終的結果始終在精度在0.0001這個上面
而將0.03調整到0.3,精度從0.0001下降到0.001上
所需的精度要求變低了,Z-Fighting自然會消失,對於調整Far平面來說,將500下降到50精度的變化才能保證精度的變化和Near平面的調整相同
所以看似Near的調整間隔很小,但是對精度的變化起到很重要的作用

總結

Z-Fighting關鍵的原因是精度問題,從調整Z-Buffer的bit位數,到降低Near到Far平面的間隔本質上是在調整最終 Zndc{Z_{ndc}} 的精度

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章