為什麼半透明模型的渲染要使用深度測試而關閉深度寫入?
找了好幾個說深度測試和深度寫入的區別的文章,看懂了只是混合顏色後把不把深度寫入緩存的區別。但是這和透明模型有什麼關係嗎?
對於不透明(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?