初學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,所以紅塊另一半沒有通過深度測試。
本文到此結束,由於是第一次寫博客,還希望大家能多多指正!