1. 程式人生 > >Unity ZTest 深度測試 & ZWrite 深度寫入(轉)

Unity ZTest 深度測試 & ZWrite 深度寫入(轉)

初學Shader,一開始對於渲染佇列,ZTest 和 ZWrite一頭霧水,經過多方查閱和實驗,有了一些自己的理解。發此文與初學Shader的朋友分享,也算是為自己做個筆記。不對或不足之處歡迎指正。

    不說廢話,直接進入正題。 

    首先是實驗場景,一藍一紅兩個Cube。藍在紅前。

     

    兩個方塊所使用的Shader都是最簡單的 V&F 著色程式,不同的是藍色方塊alpha返回值為0.6,紅色為1。

     

     但是藍色方塊並沒有絲毫透明的效果,這時我們在藍色方塊的Shader內加上這樣一行程式碼 : 

     Blend SrcAlpha OneMinusSrcAlpha 。

     

     稍微解釋一下,這行指令意思就是將本 Shader 計算出的顏色值(源顏色值,即藍色) * 源Alpha值(0.6) + 目標顏色值(可以理解為背景色) * (1-0.6),從而讓藍色方塊展示出了40%的透明度。

    然後我們看到了這樣的效果:

    

    似乎有些透明的樣子了,但是紅色方塊還是顯示不出來。我們再加上這樣一行程式碼:

     Tags {"Queue" = "Transparent"}

     

    意思是設定它在渲染佇列中的值為 Transparent (透明) = 3000,值越小越先渲染,而後渲染( Queue 值大)的物體會覆蓋先渲染的物體(紅塊未設定 Queue 值,預設為 Geometry(幾何體) = 2000)。在理想的世界中,我們應該讓遠處的物體先渲染,近處的物體後渲染,這樣遠處的物體就不會遮擋住近的物體。

    接下來我們看到了正確的結果:

    

    Queue 其他預定義的值為:Background = 1000 , AlphaTest = 2450,Overlay = 4000。預設值是Geometry 。

    例如:如果我們想讓遠處的紅色方塊遮擋住近處的藍色方塊,即讓藍色的先渲染,紅色的後渲染,只需將紅塊的Queue 也設定為 Transparent ,藍塊的Queue值-1。

    

    然後我們看看效果:

    

    好像並沒有什麼卵用。。。這是為什麼呢?

    原因在於這樣兩條指令:

    

    雖然我們的程式碼裡並沒有這兩行,但它們是預設存在的。

     ZTest ,深度測試;LEqual ,小於等於。

     ZWrite ,深度寫入,On ,開啟。

     ZTest 可取值為:Greater , GEqual , Less , LEqual , Equal , NotEqual , Always , Never , Off,預設是 LEqual,ZTest Off 等同於 ZTest Always。

     ZWrite 可取值為:On , Off,預設是 On。

    系統中存在一個顏色緩衝區和一個深度緩衝區,分別儲存顏色值和深度值,來決定畫面上應該顯示什麼顏色。

    深度值是物體在世界空間中距離攝像機的遠近。距離越近,深度值越小;距離越遠,深度值越大。

    例如在我們的場景中,藍色方塊比紅色更靠近相機,藍塊的深度值就比紅塊小。

    假設藍塊的深度值為 0.5,紅塊為 0.7。還記得在上面的例子中,我們讓藍塊在渲染佇列中排在紅塊前面,系統就先將藍色值存入了顏色緩衝區中對應的區域,將深度值 0.5 存入了深度緩衝區中對應的區域。接下來渲染紅塊,系統會將紅塊的深度值與深度緩衝區中的值進行比較(這個過程就是深度測試),由於預設的 ZTest 深度測試的方式是 LEqual 小於等於,即深度值小於等於 0.5 的顏色才會通過測試。如果通過了測試,且 ZWirte 處於 On 的狀態,該顏色的深度值就會替代深度緩衝區中的值,顏色值也會替代顏色緩衝區中的值,從而顯示出新顏色。

    很顯然,0.7 > 0.5,所以紅色並不能通過測試,紅塊也就不能顯示在藍塊前面。

    如果我們硬要遠處的紅塊遮擋住近處的藍塊,很顯然,我們應該改變或關閉深度測試,或者關閉深度寫入(關閉了深度測試或者深度寫入之後,物體顏色的遮擋關係就會和渲染佇列一致,即排在後面的會擋住前面的)。

    接下來我們試試關閉藍塊的深度寫入:

    

    得到了想要的結果:

    

    再試試單獨關閉紅塊的深度測試,註釋藍塊的深度寫入:

     

    

    結果還是一樣。但如果我們改變紅塊深度測試的方式呢:

    

    即深度值大於深度緩衝區中的值就能通過測試,還記得我們假設紅塊深度值為 0.7,藍塊為 0.5。理論上會得到我們想要的結果:

    

    奇怪的是,紅塊的另一半去哪了?

    答案是被背景擋住了。

    按照距離相機的遠近,我們可以假設背景的深度值為 1。在消失的另一半的深度緩衝區中的深度值應該是背景的深度值 1。而我們設定了 ZTest Greater,0.7 < 1,所以紅塊另一半沒有通過深度測試。