為什麼半透明模型的渲染要使用深度測試而關閉深度寫入?

找了好幾個說深度測試和深度寫入的區別的文章,看懂了只是混合顏色後把不把深度寫入緩存的區別。但是這和透明模型有什麼關係嗎?


對於不透明(opaque)的 fragment,最後只需要看到最接近視點的 fragment。在實時渲染一般是通過深度緩衝來取得這個最近的 fragment。

但對於半透明的 fragment,每一個都會影響最終的結果,需要從遠至近地渲染。由於深度緩衝不能用於排序多個 fragment,所以只能用於保存最接近視點的不透明 fragment 深度,遠於該深度的透明 fragment 不用渲染,所以仍需要深度測試(depth test)。

由於需要手動排序半透明的物體,寫入深度已沒有意義。如果能完美地手工排序不透明 fragment,寫入深度也沒有影響;但若物體在深度方向有重疊,有些 fragment 的順序會有誤,如果開啟深度寫入,會令到渲染錯誤很明顯,而關掉的話影響較小一點。

當然理想的話,應該用順序無關透明(order independent transparency, OIT)技術,例如用逐像素鏈表存儲多個 fragment,以像素為單位排序渲染。


zwrite會自動把depth信息寫到zbuffer裡面,比如一個物體在z等於80的地方render,另一個物體在z等於100的地方render,深度80的物體會擋住100的。當然這個過程是不會減少overdraw的,完全看運氣或者你設置的渲染順序。

也就是說先渲染了z等於100的物體,就還會再渲染z等於80的物體,儘管前面的物體會擋住後面的。

理解上述,如果是半透明的物體:假設先渲染了z等於80的物體,那麼z等於100的物體就不會渲染了,因為在depth buffer裡面這個物體更遠。

常用辦法是關掉zwrite,增加一個pass來單獨做ztest,再第二個pass裡面來根據sorting信息來渲染


首先結論不對。對於半透明的渲染, 是可以同時開啟深度測試和深度寫入的。方法是使用2個Pass。一個先只負責保證像素級片元深度正確,一個負責渲染。

對於這種交叉物體的渲染,就可以採取這種方式。

深度測試的意義在於捨棄片元與否。

深度寫入的意義在於深度測試的基礎上,要不要覆蓋深度緩衝,即重新設立深度測試的標準。

如果沒有配合深度寫入來保證像素級的深度關係。

就會出現右邊的圖形的情況。

回答你這個問題的關鍵詞是「渲染順序」。

GPU的渲染流程

深度測試的大概流程

混合的大概流程:

2份源碼和一個模型你參考體會下:

http://pan.baidu.com/s/1i5onCpf

馮樂樂的《UnityShader入門精要》裡面第八章寫的挺詳細的,可以參考一下。


想像一下,一個圓環depth是10,圓環後面有個物體,depth是100,你如果zwrite=on,那透過圓環就看不到後面了(zbuffer現在的值是10,測試不過),所以unity中用blend需要關掉zwrite


流水線通常先做深度測試後做Blend。所以,被透明物體遮擋的不透明物體會先被深度測試給剔除掉,而沒有機會去做接下來的Blend。那麼,為了保證結果正確,在繪製透明物體時,禁止其改寫Depth,這樣,就會以不透明物體Depth為準,不透明物體不會被剔除掉,進而有機會與透明物體做接下來的Blend。


http://www.jianshu.com/p/e953e937e210 舉了幾個詳細的例子,可以參考下~


因為半透明的物體是無法遮擋半透明的物體


當時我也有過和LZ一樣的疑問,總結成兩條吧:

關閉Zwrite的目的是:

1.保證半透明的物件不影響不透明的物件,即使在渲染順序出問題的時候

2.兩個互相遮擋的半透明物件,開Zwrite,那麼就只能看到在前面的物件,不開ZWrite,就可以看到兩個物件在混合了,即使混合有可能是有問題的。


有時候也可以不關閉。

從下往上看,假設有個C形的半透明物體需要渲染,在不開啟zwrite的情形下,若C形物體下半部分先渲染,上半部分後渲染,那麼最終顯示的結果是C的上半部分在前面。


推薦閱讀:

iOS 9 用的是哪種模糊演算法?
Unity5.X中屏幕空間陰影投射技術(Screenspace ShadowMap)如何產生陰影圖?
unity移動開發如何依據性能選擇shader?

TAG:計算機圖形學 | shader | 著色器 |