您當前的位置:首頁 > 攝影

3.1 模板測試和深度測試

作者:由 蘇格拉沒有底 發表于 攝影時間:2022-01-22

一、開始前,先看一下舉例來理解

1。引例

3.1 模板測試和深度測試

左圖為顏色緩衝區中的一張圖,在模板緩衝區中我們會給這張圖的每一個片元分配一個0-255的數字(8位,預設為0)

中、右圖可以看到,我們修改了一些0為1,透過自定義的一些準則,如輸出模板緩衝區中1對應的片元的顏色;0的不輸出,最後透過模板測試的結果就如右圖所示

2。透過模板測試的應用,實現的效果舉例

①傳送門效果:可以看到左邊傳送門內的景象正是右側的場景

3.1 模板測試和深度測試

②Minions講解的一些效果,例如3D卡牌效果、偵探鏡效果等

連結:

https://www。

patreon。com/posts/14832

618

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

③每個正方體面顯示不同場景(每個面作為蒙版來顯示場景)

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3。理解

對於上述的例子總結一下,這些效果基本可以歸結為三層組成

以②中的傳送門為例子,三層分別對應:門外場景、門內場景、門

也就是說可以理解為:包括兩層物體/場景、和一層遮罩

二、什麼是模板測試

1。從渲染管線理解

下圖為從片元著色器到FrameBuffer的流程(逐片元操作)

3.1 模板測試和深度測試

3.1 模板測試和深度測試

PixelOwnershipTest:

簡單來說就是控制當前螢幕畫素的使用許可權

e。g。:遊戲引擎僅渲染遊戲視窗

ScissorTest(裁剪測試):

在渲染視窗再定義要渲染哪一部分

和裁剪空間一起理解,也就是隻渲染能看到的部分

e。g。只渲染視窗的左下角部分

AlphaTest(透明度測試)

提前設定一個透明度預值

只能實現不透明效果和全透明效果

e。g。 設定透明度a為0。5,如果片元大於這個值就透過測試,如果小於0。5就剔除掉

StencilTest(模板測試)

DepthTest(深度測試)

Blending(透明度混合)

可以實現半透明效果

完成接下來的其他一系列操作後,我們會講合格的片元/畫素輸出到幀緩衝區(FrameBuffer)

逐片元操作是可以配置但不可程式設計的(對應圖中為黃色背景),也就是說是由管線/硬體自身規定好的,我們只能對裡邊的內容進行配置。

2。從邏輯上理解

3.1 模板測試和深度測試

理解:

referenceValue:當前模板緩衝片元的參考值

stencilBufferValue:模板緩衝區裡的值

中間的comparisonFunction,就是做一個比較

結果:

如果透過,這個片元就進入下一個階段

未透過/拋棄,停止並且不會進入下一個階段,也就是說不會進入顏色緩衝區

總結:就是透過一定條件來判斷這個片元/片元屬性執行保留還是拋棄的操作

3。從書面概念上理解

模板緩衝區-FrameBuffer

模板緩衝區可以為螢幕上的每一個畫素點儲存一個無符號整數值(通常為8位int 0-255)。

這個值的意義根據程式的具體應用而定。

模板測試

渲染過程中,可以用這個值與預先設定好的參考值作(ReferenceValue)比較,根據結果來決定是否更新相應的畫素點的顏色值。

這個比較的過程就稱為

模板測試

模板測試在透明度測試之前後,深度測試之前。

如果模板測試透過,相應的畫素點更新,否則不更新。

三、基本原理和使用方法

1。語法表示/結構解釋

3.1 模板測試和深度測試

Ref

:當前片元的參考值(0-255)

ReadMask

:讀掩碼

WriteMask

:寫掩碼

Comp

:比較操作函式

Pass

:測試透過,之後進行操作(StencilOperation,後邊有詳細講解)

Fail

:測試未透過,也會進行一個操作

ZFail:

模板測試透過,深度測試未透過

2。ComparisonFunction

我們可以根據需求配置

3.1 模板測試和深度測試

3。StencilOperation 更新值

有不同的更新操作,根據自己的需求進行配置

3.1 模板測試和深度測試

四、Demo效果展示和講解

1、案例一:3D卡牌效果

注:Unity中模板緩衝區預設都是0

在材質中將ReferenceValue改為0時的效果(模型直接擺放的效果)

3.1 模板測試和深度測試

課程shader截圖

①蒙版的shader

程式碼截圖

3.1 模板測試和深度測試

3.1 模板測試和深度測試

程式碼理解

只有一個int型別的屬性,命名了一個ID

渲染型別為不透明物體,佇列為Geometry+1(預設的不透明物體後進行蒙版的渲染)

ColorMask 顏色遮罩,0就是什麼都不輸出(是高度可配置的,可以改為RGBA(沒有遮罩)、輸出單通道R、G、 B)

ZWrite off 關閉深度寫入,防止顯示的東西被深度剔除(後邊深度測試細講)

Stencil { } 模板測試部分

Ref [_ID] 索引值就是前邊屬性宣告的ID

Comp always //預設比較

Pass replace //預設是keep

Fail、ZFail,不寫的話都是預設值,如程式碼所示

後續就是頂點、片元著色器

顏色給一個half4的就行,因為前邊已經ColorMask0了(什麼都不輸出)

②物體的shader

程式碼截圖

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

程式碼理解:

除了自身的屬性之外,同樣給了一個ID

渲染型別為不透明物體,佇列為Geometry+2(前邊蒙版後渲染)

Stencil {} 模板測試部分:

Ref [_ID] 同上

Comp equal ,當給定的索引值和當前模板緩衝區的值相等時,才會渲染這個片元。

後續不寫就是預設值

後邊就是自身的光照模型、顏色渲染等

③實現思路梳理

前提:Unity的模板緩衝區的預設值是0

預設物體(mask外邊的物體)的索引值也設為0,Comp設為always,也就是比較是一直透過的,且保持保持模板緩衝區的值不變(不進行模板測試操作的物體渲染完之後,模板緩衝區的值還是0)

然後開始渲染蒙版(mask)

mask的設定Comp也是always,但是不同的是:ID給了1(屬性部分定義),並且Pass的設定為replace,也就是說mask所在的模板緩衝區的值變成了1。

到這裡,總結一下,mask外的物體 值是0,mask的值是1

最後是mask裡邊的物體。

mask的模板測試是這樣的:ID是1,Comp是equal。翻譯一下就是:模板緩衝區的值為1,比較的條件是相等

此時,裡邊物體的模板緩衝區的值是1,外邊物體的模板緩衝區是0,Comp的條件是相等,結果很明顯不相等,這樣的效果就是:除mask顯示的部分,外邊的場景不渲染。

回顧前邊,我們mask的緩衝區的值也為1,通過了測試,所以mask部分(卡牌部分)渲染了出來。

2。案例二:盒子不同面顯示不同場景

3.1 模板測試和深度測試

3.1 模板測試和深度測試

實現思路

和卡牌效果類似,一個用蒙版遮罩的物體,盒子每個面用一個蒙版遮罩

同樣利用預設的值為0來做,只是面多了,蒙版和裡邊顯示的物體也多了,ID依次為1、2、3、4

蒙版對應物體同一個ID,最終的效果也就是在對應的蒙版顯示相應的物體

shader

屬性和模板測試部分程式碼截圖

3.1 模板測試和深度測試

程式碼理解:

屬性中使用了一個內建的列舉,這樣就可以在外邊自己選擇可配置的屬性了

五、模板測試的總結

最重要(用來比較的)兩個值:

當前模板緩衝區值(StencilBufferValue)

模板參考值(ReferenceValue)

模板測試主要就是對這兩個值進行特定的比較操作,例如Never、Always、Equal等,具體參考上文的表格

模板測試後,要對模板緩衝區的值進行更新操作,例如Keep,Replace等,具體參考上文表格

模板測試之後,可以透過不同的結果對模板緩衝區做不同的更新操作,例如模板測試成功的操作Pass、模板測試失敗的操作Fail、深度測試失敗的操作ZFail、還有正對正面和背面更新操作Passback,Passfront,Failback等。。。

六、擴充套件及參考資料

1。擴充套件用法

描邊操作

3.1 模板測試和深度測試

多邊形填充

3.1 模板測試和深度測試

反射區域控制

3.1 模板測試和深度測試

shadow volume陰影渲染

3.1 模板測試和深度測試

2。參考資料

https://

blog。csdn。net/u01104717

1/article/details/46928463

https://

blog。csdn。net/liu_if_el

se/article/details/86316361

https://

gameinstitute。qq。com/co

mmunity/detail/127404

https://

learnopengl-cn。readthedocs。io

/zh/latest/04%20Advanced%20OpenGL/02%20Stencil%20testing/

https://www。

patreon。com/posts/14832

618

https://www。

udemy。com/course/unity-

shaders/

一、什麼是深度測試

幫助我們處理物體的遮擋關係

1。從渲染管線理解

3.1 模板測試和深度測試

深度測試同樣位於逐片元操作過程中,在模板測試之後,透明度混合之前。

2。從邏輯上理解

3.1 模板測試和深度測試

3.1 模板測試和深度測試

理解:

和模板測試差不多,都是透過一個比較來判斷一系列操作

圖1:

如果ZWrite On,且當前深度值和深度緩衝區的值作比較,如果透過就寫入深度,不透過就忽略深度

圖2:

當前深度值和深度緩衝區中的值做比較,如果透過就寫入顏色緩衝區,不透過就不寫入顏色緩衝區

3。從書面概念上理解

所謂深度測試,就是針對當前螢幕上(更準確的說是FrameBuffer)對應的畫素點,將物件自身的深度值與當前深度緩衝區的深度值做比較,如果通過了,這個物件在該畫素點才會將顏色寫入顏色緩衝區

4。從發展上理解

3.1 模板測試和深度測試

我們要渲染一個場景的話,通常會有多個物體。

首先要

控制渲染順序

畫家演算法:

這是是指油畫的畫法,也就是畫一幅油畫,是從遠處開始畫,然後近處的東西一點點疊加在上面(GAMES系列的課提到過多次)

存在的問題:例如一列物體,最前面的物體最大,站在正前面看只能看到最前面的物體,這樣一來後邊的就不用畫了,不然就是效能浪費。

Z-Buffer演算法:

透過深度緩衝區來控制渲染順序

控制Z-Buffer對深度的儲存

例如:什麼時候更新深度緩衝區、什麼時候使用深度緩衝區

兩個典型的功能:

Z Test

Z Write

具體後邊會講

控制不同型別物體的渲染順序

透明物體

不透明物體

渲染佇列(很有用的概念,後邊會講)

減少OverDraw

Early-Z,一種最佳化手段,後邊會講

Z-cull

Z-check

二、基本原理和使用方法

1。Z-Buffer(深度緩衝區)

和顏色緩衝區一樣,在每個片段中儲存了資訊,並且通常和顏色緩衝有著一樣的寬度和高度

顏色緩衝區

就是最終在顯示屏硬體上顯示顏色的GPU視訊記憶體區域了,這個緩衝區儲存了每幀更新後的最終顏色值,圖形流水線經過一系列測試,包括片段丟棄、顏色混合等,最終生成的畫素顏色值就儲存在這裡,然後提交給顯示硬體顯示。

深度緩衝是由視窗系統自動建立的,它會以16、24、32位float形式儲存深度值。大部分系統中深度值是24位的

Z-Buffer中儲存的是當前的深度資訊,對於每個畫素儲存一個深度值。

透過Z-Write 、Z-Test來呼叫Z-Buffer,來達到想要的渲染效果

2。Z Writer(深度寫入)

深度寫入包括兩種狀態

ZWrite On 、 ZWrite Off

當我們開啟深度寫入,物體被渲染時針對物體在螢幕(FrameBuffer)上每個畫素的深度都寫入到深度緩衝區。

關閉深度寫入狀態,物體的深度就不會寫入深度緩衝區。

除了ZWrite的是否寫入深度緩衝區,更重要的是:是否透過深度測試,也就是Z-Test

如果Z-Test都沒透過,也就不會寫入深度了。

也就是說,只有ZTest和ZWrite都可行的情況下才寫入深度緩衝區

綜上,ZWrite有On、Off兩種情況;ZTest有透過、不透過兩種情況,兩者結合的四種情況如下:

3.1 模板測試和深度測試

3。Z-Test的比較操作

3.1 模板測試和深度測試

預設:ZWrite On、ZTest LEqual

深度緩衝一開始為無窮大

4。渲染佇列

Unity內建的幾種渲染佇列

3.1 模板測試和深度測試

按照渲染順序從先到後排序,佇列數越小,越先渲染;反之同理。

Unity中設定渲染佇列

語法:Tags { “Queue” = “Transparent”}

預設是Geometry

Unity中不透明物體的渲染順序:從前往後

也就是說深度小的先渲染,其次再渲染深度大的

Unity中透明物體的渲染順序:從後往前(類似畫家演算法,會造成OverDraw)

可以在shader的Inspector面板中檢視渲染佇列相關屬性

3.1 模板測試和深度測試

5。簡述Early-Z技術

是位於三角形遍歷之後、逐片元操作之前的。

傳統的渲染管線中,ZTest是在Blending階段,這時進行深度測試的話,所以物件的畫素著色器都會計算一遍,沒有效能提升,只是為了得到正確的效果,造成了大量的無用計算。(深度測試失敗的片元是已經經過計算的,到這一步不透過被拋棄,那麼前邊的計算就是無用功了)

為了減少這些不必要的計算,現代GPU運用了Early-Z技術,在頂點和片元階段之間(光柵化之後,片元著色器之前)進行一次深度測試(如下左圖黑框部分)。

如果這次深度測試失敗,那就不用在片元著色器中作無關緊要的計算了,這樣一來就會帶來效能提升。

最終的ZTest仍然要進行,以保證正確的遮擋關係。

如右圖前一次的Z-Cull是為了裁剪達到效能最佳化的目的,後一次的Z-check是為了保證正確的遮擋關係。

3.1 模板測試和深度測試

3.1 模板測試和深度測試

6。深度值

正確的理解深度值的概念

首先先了解一下模型在渲染管線中的幾次空間變換

3.1 模板測試和深度測試

模型一開始所在的模型空間:

無深度。

透過M矩陣變換到世界空間,此時模型座標已經變換到了齊次座標(x,y,z,w):

深度存在z分量

透過V矩陣變換到視察空間(攝像機空間):

深度存在z分量(線性)

透過P矩陣變換到裁剪空間:

深度緩衝中此空間的z/w中(已經變成了非線性的深度)

最後透過一些投影對映變換到螢幕空間

為什麼深度緩衝區中要儲存一個非線性的深度?

詳細連結

https://

learnopengl-cn。readthedocs。io

/zh/latest/04%20Advanced%20OpenGL/01%20Depth%20testing/

原因1:給近處更多的精度

在深度緩衝區中的深度值是介於 0。0~1。0之間的,從觀察者看到的內容與場景中所有物件的z值作比較。

這些z值可以投影平截頭體(就是視錐)的近平面和遠平面之間的任何值。

//補充:

平截頭體

:又稱視景體、視錐,是三維世界中在螢幕上可見的區域,即虛擬攝像機的視野

下圖中紅框的位置是平截頭體,就是攝像機拍攝的範圍。

貼上維基百科:

https://

zh。wikipedia。org/wiki/%

E8%A7%86%E4%BD%93

3.1 模板測試和深度測試

要轉換這些檢視空間的z值到[0,1]範圍內,方法之一就是線性轉換,具體如下圖

3.1 模板測試和深度測試

然而實踐中幾乎不使用線性深度緩衝區,正確的投影特性的非線性深度方程是和1/z成正比的。這樣一來會有如下效果:在Z很近的時候有高精度,Z很遠的時候低精度,這符合我們生活中的情況,具體如下圖

其實可以回想前幾節課中伽馬校正部分對比理解一下,也是根據實際情況(人眼特性),給暗部更多的精度,這裡是近處給更多精度。

3.1 模板測試和深度測試

另一個原因:深度衝突(Z-Fight)

當兩個平面或三角形緊密相互平行的時候,深度緩衝區不具有足夠的精度來確定哪一個考前。

結果就是這兩個形狀不斷切換順序,導致怪異問題,看起來像是兩個形狀在爭奪靠前的位置。

這就被稱為

深度衝突

深度衝突是深度緩衝區的普遍問題,當物件的距離越遠一般越強(因為深度緩衝區在z值非常大的時候沒有很高的精度)

深度衝突無法避免,但是有技巧可以防止出現:

物理上的做法,就是讓物體不要靠得太近。

儘可能的把近平面設定的遠一點。

放棄一些效能來得到更高精度的深度值。

五、Demo效果展示和講解

1。案例一:三個正方體遮擋關係

3.1 模板測試和深度測試

場景中有三個正方體,並賦予了不同的顏色。正常的情況應該是從前到後依次為藍、綠、紅

圖1詳解:

3.1 模板測試和深度測試

梳理渲染過程:

沒渲染時,此時Unity的深度緩衝區預設值為無窮大

渲染藍色正方體

3.1 模板測試和深度測試

相對於預設深度緩衝區的無窮大,肯定是小於等於,所以測試透過

渲染綠色正方體

此時藍色物體位置的深度緩衝區的值已經不是無窮大了,其它位置還是

注:深度緩衝區和顏色緩衝區都是相對於片元來講的(片元可以理解為未完成的一個畫素,還處於渲染管線中的畫素)

綠色正方體進行深度測試,深度測試同樣是LessEqual,並且綠色的深度值比藍色正方體的大。

結果就是:兩個正方體重疊部分是大於深度緩衝區的,也就是測試不透過,所以重疊部分沒有寫入綠色,還是藍色的

沒有重疊部分,深度當然比無窮大小,所以寫入, 渲染出來了綠色正方體未重疊的部分。

紅色同理。

圖2詳解:

3.1 模板測試和深度測試

梳理渲染過程:

設定:將藍色正方體的深度寫入ZWrite 關掉了;

思路:第一個藍色正方體的渲染時,測試透過,但是並沒有寫入深度。

也就是說,渲染完藍色正方體時,深度緩衝區的值還是無窮大。

這就是藍綠重疊部分,顯示綠色的原因。

圖3詳解:

相較於圖2,只是把綠色正方體的ZTest改為了always

無論是LessEqual還是always,測試都透過,所以效果和圖2一樣

圖4詳解:

3.1 模板測試和深度測試

將紅色正方體的ZTest也改為了always,這樣一來紅色正方體的深度測試也是一直透過,並且寫入。

因為是從前往後渲染的,所有依次為藍、綠、紅,深度緩衝區中的值也是後邊渲染的

可以理解為後邊遮住前邊的效果。

圖5詳解:

3.1 模板測試和深度測試

相對於圖4,改變了綠色正方體的渲染佇列為Geometry+1

此時的幀緩衝區面板如下

3.1 模板測試和深度測試

儘管綠色正方體在紅色正方體前面,因為佇列+1,它的渲染順序變為了紅色正方體後

也就是說,渲染佇列優先順序 > 透明物體的渲染順序(從前到後)

圖6詳解:

3.1 模板測試和深度測試

相對於圖1,將綠色正方體的ZTest改為了Greater,

也就是說藍色正方體和綠色正方體重疊部分,大於模板緩衝區的部分透過測試,寫入模板緩衝區

結果就是重疊部分為綠色,而未重疊部分的深度當然小於無窮大,所以沒透過測試,自然也就不渲染。

紅色部分正常。

shader截圖

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

2。案例二:X-Ray效果

3.1 模板測試和深度測試

實現思路:

分為三部分:前邊的牆、被牆擋住的X-Ray效果部分、高出牆部分的物體

回想一下前邊6張圖,哪張圖是前邊渲染完,後邊渲染顯示在先渲染完前邊的? ——->圖6

也就是說,X-Ray效果部分我們使用到了ZTest :Greater,深度寫入關閉

高出牆體部分是預設的渲染:LessEqual、ZWrite On

shader截圖

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

3.1 模板測試和深度測試

程式碼理解

寫CGINCLUDE的好處:將頂點和片元著色器寫在裡邊,在多passshade的時候,直接呼叫就可以了。

X-Ray繪製部分

和之前實現思路相同,ZWrite Off,ZTest Greater

Cull back 是剔除背面,為了最佳化

Blend SrcAlpha One :由於有一個透明的效果,除了上邊的,還需要一步Blend,來做透明度混合

渲染型別和渲染佇列為Transparent

正常繪製部分略

案例三、粒子系統中的深度測試

建立一個粒子系統ParticleSystem,可以看到預設的是透明的

3.1 模板測試和深度測試

為了理解,我們自己建立一個材質,給到粒子上

此時粒子系統變成了這樣

3.1 模板測試和深度測試

建立一個shader(Unlit),把粒子的貼圖選上,附到材質上,效果如下(是不透明的),這顯然不是我們要的效果

3.1 模板測試和深度測試

開啟shader修改程式碼

首先回顧前邊說的:Unity中預設的ZWrite On、ZTest是LessEqual、渲染佇列是Geometry

我們想要讓粒子透明,就需要做如下配置

渲染佇列改為透明物體的渲染佇列:Transparent

ZWrite Off,對於透明物體,是有相互疊加關係的,所以關掉寫入

ZTest 預設(LessEqual),對於透明物體是這樣的:如果透明物體前有不透明物體,此時 透明物體看不到;如果透明物體後面有不透明物體,此時透明物體可以看到。

要渲染透明物體,還要進行Blend操作:Blend One One(加法混合,疊加效果的顯示)

修改完成後效果如下:(正是我們想要的效果)

3.1 模板測試和深度測試

七、深度測試的總結

最重要的兩個值:當前深度緩衝區的值(ZBufferValue) 和 深度參考值(ReferenceValue)。透過比較操作還實現理想的渲染效果

Unity中的渲染順序

先渲染不透明物體(從前到後),再渲染透明物體(從後往前)

透過對ZWrite和ZTest的相互組合配置來控制半透明物體的渲染(關閉深度寫入,快開啟深度測試,透明度混合)

引入Early-Z之後深度測試相關的內容(Z-Cull、Z-Check)

深度緩衝區中儲存的深度值為[0,1]的非線性值

八、擴充套件及參考資料

1。深度測試的擴充套件用法

基於深度的著色

如:湖水的效果

3.1 模板測試和深度測試

陰影貼圖(shadowma)

比較攝像機空間和燈光空間的深度值得到陰影範圍

透明物體、粒子渲染

透視X-Ray效果

切邊效果

2。參考資料

https://

blog。csdn。net/puppet_ma

ster/article/details/53900568

https://

learnopengl-cn。readthedocs。io

/zh/latest/04%20Advanced%20OpenGL/01%20Depth%20testing/

https://

docs。unity3d。com/cn/201

8。4/Manual/SL-CullAndDepth。html

https://

blog。csdn。net/yangxuan0

261/article/details/79725466

https://

roystan。net/articles/to

on-water。html

《shader入門精要》

《Unity ShaderLab 開發實戰詳解》

補充

深度測試是做特效永遠繞不開的話題

模板測試實際專案中應用的相對較少,建議能不用盡量不用(佔用一個buffer的記憶體?)

作業:根據課程內容,用深度測試和模板測試做些有意思的效果

Emmm目前的段位只能做一些簡單的效果

1。【模板測試部分】嘗試還原一下不同正方體面的不同場景顯示。

實現思路:

也是分為兩個shader,分別是蒙版和物體

蒙版部分和課程內的相同,同樣定義了一個ID方便後邊操作

3.1 模板測試和深度測試

物體部分在模型著色的基礎上加上了模板測試相關的程式碼

3.1 模板測試和深度測試

重點也就是ID的設定,第一個面的蒙版和物體ID設為1;第二個面的蒙版和物體ID設為2。僅此而已

效果如下:

標簽: 深度  緩衝區  渲染  模板  測試