透明混合爲什麼要關閉深度寫入,不關閉會怎麼樣

原文:https://github.com/candycat1992/Unity_Shaders_Book/issues/153

 

如果半透明物體開啓了深度寫入的話,就無法看到在該fragment處後面渲染的fragment,這個主要是爲了在半透明物體互相交叉、無法得到正確渲染效果時,我們折中的一種方式。

舉個例子,我們來創造一個半透明物體互相交叉的例子:

 

這兩個方塊使用的Shader是一樣的,但使用了兩個各自的材質。爲了讓效果明顯我故意把它們材質的透明度調成不同的值,攝像機靠後的方塊透明度較低,靠前的較高。

在不採用其他方法的前提下,如果我們使用書裏這種傳統的透明混合的方式(指關閉深度寫入進行混合)會得到下面的效果:

 

實際上,這種效果是有問題的。錯誤的地方在於中間兩個方塊互相重疊的地方,這個混合效果有問題。我們可以在腦海裏重現這個渲染過程:首先Unity會基於物體中心對兩個方塊進行排序,來實現半透明物體的從後往前渲染的目的。所以,Unity會先渲染方塊B、再渲染方塊A(參見第一張圖裏面兩個方塊在攝像機空間下的位置)。然而在重疊區域,正確的渲染順序應該是先渲染方塊A,因爲在這部分區域內,它被方塊B覆蓋住了,它位於後面。出現錯誤的本質原因是因爲我們的排序都是基於object level的,而不是基於pixel level的排序。

如果此時我們把深度打開,則會得到下面的效果:

 

 

你可以一眼就看出來這裏面的錯誤,那就是方塊A的重疊部分別完全剔除掉了,這部分完全沒有渲染!它被剔除掉的 原因就是因爲Unity會先渲染方塊B,由於方塊B進行了深度寫入,所以等到方塊A渲染的時候,重疊部分A的像素根本無法通過depth test,會直接被剔除掉。

除了半透明物體之間的問題,儘管理論上來說,理想情況下半透明物體應該在所有不透明物體渲染完之後再渲染,但如果一個不透明物體因爲某些原因在某個半透明物體後面被渲染了,也可能會因爲半透明物體開啓了深度寫入而出現非常明顯的渲染錯誤(不透明物體被半透明物體完全遮擋掉沒有渲染)。

我覺得看到這裏你應該知道我們爲什麼要關閉深度寫入。總結一下的話,可以參考知乎上Milo Yip的回答

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

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

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

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

簡而言之,就是因爲,傳統的半透明混合總是會在物體交叉、渲染重疊的情況下,出現錯誤的混合效果。如果開啓深度寫入,會令到渲染錯誤很明顯,而關掉的話影響較小一點。

回到你的圖裏,由於你的兩個方塊擺放規則不存在相互重疊,所以Unity對於兩個物體的排序在pixel level也是正確的排序,即每個像素也都是滿足從後往前渲染的,所以你不會發現問題。

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