本系列為作者學(xué)習(xí)UnityShader入門精要而作的筆記,內(nèi)容將包括:
- 書本中句子照抄 + 個(gè)人批注
- 項(xiàng)目源碼
- 一堆新手會(huì)犯的錯(cuò)誤
- 潛在的太監(jiān)斷更,有始無(wú)終
總之適用于同樣開(kāi)始學(xué)習(xí)Shader的同學(xué)們進(jìn)行有取舍的參考。
上節(jié)復(fù)習(xí)
在上節(jié)筆記中,我們學(xué)習(xí)了圖像渲染流水線的基本過(guò)程,從應(yīng)用階段的CPU處理,輸出渲染圖元到幾何階段,再輸出屏幕空間的頂點(diǎn)信息到光柵化階段。
上節(jié)詳細(xì)介紹了應(yīng)用階段,在這一階段主要由我們?nèi)藶榭刂?,在程序中設(shè)定材質(zhì),網(wǎng)格,紋理,著色器等數(shù)據(jù)的渲染,并對(duì)不必要的渲染進(jìn)行剔除。整個(gè)渲染流程是從硬盤加載數(shù)據(jù)到RAM再到VRAM由顯卡進(jìn)行調(diào)用,RAM中的數(shù)據(jù)在被調(diào)用到VRAM后就會(huì)被丟棄(除了部分用于進(jìn)行物理計(jì)算的網(wǎng)格信息),所有工作在渲染狀態(tài)中打包成數(shù)據(jù)準(zhǔn)備好后,將由CPU進(jìn)行DrawCall來(lái)通知GPU對(duì)相應(yīng)的圖元(primitives)進(jìn)行處理。那么接下來(lái)就是GPU流水線階段,也對(duì)應(yīng)了我們后面的幾何階段和光柵化階段。
GPU流水線
在GPU流水線階段,開(kāi)發(fā)者無(wú)法完全操控整個(gè)GPU流水線,不過(guò)GPU還是為我們提供了一些階段的控制權(quán),如下圖所示:
上圖可以抽象成2個(gè)大階段,其中起點(diǎn)是接收應(yīng)用階段加載到顯存的頂點(diǎn)數(shù)據(jù),準(zhǔn)備好了由CPU通過(guò)DrawCall調(diào)用GPU。接下來(lái)就是GPU的處理流程,幾何階段和光柵化階段。最后處理完成輸出為屏幕圖像。
接下來(lái)是書中的介紹,請(qǐng)對(duì)照上圖查看,可能初學(xué)會(huì)難懂拗口,不過(guò)沒(méi)關(guān)系,先記個(gè)名字,后續(xù)會(huì)逐一介紹。
在幾何階段,頂點(diǎn)著色器(Vertex Shader) 是完全可編程的,它通常用于實(shí)現(xiàn)頂點(diǎn)的空間變換,頂點(diǎn)著色等功能。曲面細(xì)分著色器(Tessellation Shader) 是一個(gè)可選的著色器,用于細(xì)分圖元。幾何著色器(Geometry Shader) 也是可選的著色器, 可以被用于執(zhí)行逐圖元(Pre-Primitive) 的著色操作,或者被用于產(chǎn)生更多圖元。(其實(shí)這三個(gè)階段可以簡(jiǎn)單理解為點(diǎn)到線到面的處理,在我理解里幾何階段就是一種對(duì)圖元在幾何性質(zhì)的點(diǎn)線面上的規(guī)劃和渲染)
經(jīng)歷了著色器渲染后,接著進(jìn)行裁剪(Clipping) ,這一階段的目的是將那些不被渲染的頂點(diǎn)裁剪掉,并剔除某些三角面元的面片。這一階段我們可配置但不可編程(也就是說(shuō)我們只決定裁剪哪些,而裁剪的算法是固定的)。我們可以使用自定義的裁剪平面來(lái)配置裁剪區(qū)域,也可以通過(guò)指令控制裁剪三角圖元的正面還是側(cè)面。(接觸過(guò)Shader中的Clip的同學(xué)們應(yīng)該更有體會(huì))
幾何階段的最后一個(gè)流水線是屏幕映射(Screen Mapping) ,這一階段是不可配置和編程的,它負(fù)責(zé)把每個(gè)圖元的坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)中,畢竟在從CPU到GPU處理這些數(shù)據(jù)的時(shí)候,它們常常不是在同一個(gè)坐標(biāo)空間下的。
接著是光柵化階段,其中的三角形設(shè)置(Triangle Setup) 和三角形遍歷(Triangle Traversal) 階段都是固定函數(shù)(Fixed-Function)的階段。接下來(lái)的片元著色器(Fragment Shader) 則是完全可編程的,用于實(shí)現(xiàn)逐片元(Pre-Fragment) 的著色操作,在逐片元操作(Pre-Fragment Operations) 階段負(fù)責(zé)執(zhí)行很多重要的操作,例如修改顏色、深度緩沖、進(jìn)行混合等,它不是可編程的,但具有很高的可配置性。
上述內(nèi)容看著復(fù)雜,但是學(xué)習(xí)shader必須掌握的,接著我們要一一描述這些概念
頂點(diǎn)著色器
頂點(diǎn)著色器(Vertex Shader) 是流水線的第一個(gè)階段,學(xué)習(xí)幾何的時(shí)候總是由點(diǎn)到線到面嘛。它的輸入來(lái)自于CPU,對(duì)每個(gè)輸入的頂點(diǎn)都會(huì)調(diào)用一次頂點(diǎn)著色器。它本身不創(chuàng)建或銷毀頂點(diǎn),無(wú)法得到頂點(diǎn)與頂點(diǎn)的關(guān)系,因此它無(wú)法判斷某幾個(gè)點(diǎn)是不是同屬于一個(gè)三角網(wǎng)格。由于其獨(dú)立性,只要計(jì)算就好了,因此頂點(diǎn)著色器處理速度也很快。
頂點(diǎn)著色器主要完成的工作是:坐標(biāo)變換和逐頂點(diǎn)光照。除此之外還可以輸出后續(xù)所需的數(shù)據(jù)。下圖展示了頂點(diǎn)著色器對(duì)頂點(diǎn)進(jìn)行坐標(biāo)變換并計(jì)算頂點(diǎn)顏色的過(guò)程:
我們可以通過(guò)坐標(biāo)變換改變頂點(diǎn)位置,從而實(shí)現(xiàn)頂點(diǎn)動(dòng)畫,例如模擬水面,布料等等。但無(wú)論我們?cè)陧旤c(diǎn)著色器中如何改變頂點(diǎn)的位置,一個(gè)最基本的頂點(diǎn)著色器必須完成的一個(gè)工作是:把頂點(diǎn)坐標(biāo)從模型空間轉(zhuǎn)換到齊次裁剪空間 。
在頂點(diǎn)著色器中可能會(huì)經(jīng)??吹饺缦麓a:
o.pos = mul(UNITY_MVP, v.position);
上述代碼的功能就是將頂點(diǎn)坐標(biāo)轉(zhuǎn)化為齊次坐標(biāo),通常再由硬件做透視算法后,最終得到歸一化的設(shè)備坐標(biāo)(Normalized Device Coordinates,NDC)。(其實(shí)看到歸一化不少同學(xué)可能就理解了,就是為了將不同坐標(biāo)轉(zhuǎn)化到同一個(gè)齊次坐標(biāo)再進(jìn)行處理嘛)
(上圖給出的分量范圍是OpenGL同時(shí)也是Unity使用的NDC,z分量范圍為[-1,1]。在DirectX中z分量范圍為[0,1])
(左圖是模型空間,右圖是NDC,齊次裁剪坐標(biāo)空間是四維的)
頂點(diǎn)著色器可以有不同的輸出方式,最常見(jiàn)的輸出路徑是經(jīng)光柵化后交給片元著色器進(jìn)行處理,而在現(xiàn)代的Shader Model中還可以將數(shù)據(jù)發(fā)送給曲面細(xì)分著色器或幾何著色器。
裁剪
為什么裁剪。簡(jiǎn)單來(lái)說(shuō)我們不需要渲染不在攝像機(jī)視野內(nèi)的物體,因此這些部分需要被裁剪掉。
一個(gè)圖元和攝像機(jī)的視野有三種位置關(guān)系:完全在視野內(nèi),部分在視野內(nèi),不在視野內(nèi)。完全在視野內(nèi)的處理完就傳遞給下一個(gè)流水線階段,不在視野內(nèi)的就不傳遞,因?yàn)樗伙@示也就不參與渲染,而部分在視野內(nèi)的則需要進(jìn)行裁剪處理:例如,一條線段的一個(gè)頂點(diǎn)在視野內(nèi),而另一個(gè)頂點(diǎn)不在視野內(nèi),那么在視野外部的頂點(diǎn)應(yīng)該使用一個(gè)新的頂點(diǎn)來(lái)替代,這個(gè)新頂點(diǎn)位于線段和視野邊界的交點(diǎn)處。
(上圖的單位立方體代表的是NDC,而實(shí)際裁剪工作是在裁剪空間內(nèi)完成的)
如上圖所示,視野邊界就是NDC的坐標(biāo)分量的上界和下界,我們繪制NDC的單位立方體,則保留在立方體內(nèi)的部分進(jìn)行渲染,被立方體邊緣裁剪的部分產(chǎn)生新頂點(diǎn)。
雖然我們無(wú)法通過(guò)編程來(lái)控制裁剪的過(guò)程,不過(guò)是可以自定義裁剪操作的。
屏幕映射
屏幕映射是幾何階段的最后一步,其輸出將作為光柵化階段的輸入。這一步接收的輸入坐標(biāo)是歸一化的齊次坐標(biāo)。屏幕映射(Screen Mapping) 的任務(wù)是將每個(gè)圖元的x和y坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)系(Screen Coordinates) 下。屏幕坐標(biāo)系是一個(gè)二維坐標(biāo)系,它和我們顯示畫面的分辨率相關(guān)。
實(shí)際上屏幕映射就是二維上對(duì)齊次坐標(biāo)的縮放變換。屏幕坐標(biāo)系的最小坐標(biāo)是左下角(x1,y1),而最大坐標(biāo)是右上角(x2,y2),與圖元的齊次坐標(biāo)系是不一樣的。
(屏幕映射對(duì)齊次坐標(biāo)進(jìn)行了x和y分量上的縮放變換,并且對(duì)應(yīng)的坐標(biāo)也改變了,其中x1<x2且y1<y2)
那么z軸呢?z跑哪里去了?屏幕映射不會(huì)對(duì)z軸進(jìn)行任何處理,屏幕坐標(biāo)會(huì)和z軸一起構(gòu)成一個(gè)新坐標(biāo)系,稱為窗口坐標(biāo)系(Window Coordinates) ,這些值會(huì)被一起傳遞到光柵化階段。
屏幕映射得到的屏幕坐標(biāo)決定了這個(gè)頂點(diǎn)對(duì)應(yīng)屏幕上哪個(gè)像素以及離這個(gè)像素有多遠(yuǎn)。
此外,OpenGL和DirectX的屏幕坐標(biāo)也存在差異,OpenGL將屏幕左下角作為最小窗口值,而DirectX將屏幕右下角作為最小窗口值。
如果你發(fā)現(xiàn)得到的圖像是倒轉(zhuǎn)的,那么很有可能就是這個(gè)原因造成的。
三角形設(shè)置
三角形設(shè)置是光柵化的第一個(gè)階段,上一個(gè)階段屏幕映射給出了屏幕坐標(biāo)系下的頂點(diǎn)信息和其他額外信息,例如深度值(z坐標(biāo)),法線方向,視角方向等。光柵化階段有兩個(gè)重要的目標(biāo):計(jì)算每個(gè)圖元覆蓋了哪些像素,以及為這些像素計(jì)算它們的顏色。
三角形設(shè)置會(huì)計(jì)算光柵化一個(gè)三角網(wǎng)格所需的信息。具體來(lái)說(shuō),在幾何階段輸出的都是三角網(wǎng)格的頂點(diǎn),即我們所得到的是三角形網(wǎng)格每條邊的兩個(gè)端點(diǎn)。但如果需要得到整個(gè)三角網(wǎng)格對(duì)像素的覆蓋情況,我們就必須計(jì)算每條邊上的像素坐標(biāo)。為了能夠計(jì)算邊界像素的坐標(biāo)信息,我們就需要得到三角形邊界的表示方式。這樣一個(gè)計(jì)算三角網(wǎng)格表示數(shù)據(jù)的過(guò)程叫做三角形設(shè)置。
說(shuō)白了,說(shuō)人話就是連線,把點(diǎn)連成三角形或者邊。
三角形遍歷
三角形遍歷階段會(huì)檢查每個(gè)像素是否被一個(gè)三角網(wǎng)格所覆蓋。如果被覆蓋的話,就會(huì)生成一個(gè)片元(fragment) 。而找到哪些像素被三角網(wǎng)格覆蓋的過(guò)程就是三角形遍歷,這個(gè)階段也被稱為掃描變換(Scan Conversion) (我想是因?yàn)閽呙杈€算法?)。
根據(jù)三角形設(shè)置的計(jì)算結(jié)果來(lái)判斷每個(gè)像素是否被一個(gè)三角網(wǎng)格覆蓋,并使用三角網(wǎng)格3個(gè)頂點(diǎn)的頂點(diǎn)信息對(duì)整個(gè)覆蓋區(qū)域的像素進(jìn)行插值。下圖展示了三角形遍歷階段簡(jiǎn)化的計(jì)算過(guò)程:
這一步的輸出結(jié)果得到一個(gè)片元序列。一個(gè)片元并不是真正意義上的像素,而是包含了很多種狀態(tài)的集合,這些狀態(tài)用于計(jì)算每個(gè)像素的最終顏色(最終結(jié)果)。狀態(tài)包括且不限于:屏幕坐標(biāo),深度信息,以及其他從幾何階段輸出的頂點(diǎn)信息,例如法線、紋理坐標(biāo)等。
(圖元和片元雖然在英文上是fragment,如果翻譯成碎片很容易被誤解為個(gè)體,實(shí)際上它們應(yīng)當(dāng)被視為多種狀態(tài)的集合,一個(gè)元包括了很多的信息,而不僅僅是某個(gè)圖形或者某個(gè)像素)
簡(jiǎn)單拓展:重心坐標(biāo)系
推薦閱讀計(jì)算機(jī)圖形學(xué) 1:重心坐標(biāo)系(Barycentric coordinate system)詳解
上圖展示的片元顏色渲染,我們看到重心插值的深度為-10。既然要計(jì)算插值,如果我們以三角形某一個(gè)頂點(diǎn)為原點(diǎn),去構(gòu)建一個(gè)直角坐標(biāo)系再計(jì)算,顯然并不是那么好,最簡(jiǎn)單的方案構(gòu)建一個(gè)非正交的坐標(biāo)系,這個(gè)坐標(biāo)系就是重心坐標(biāo)系,請(qǐng)看下圖:
上圖三角形,以abc代表頂點(diǎn)。假設(shè)我們以點(diǎn)
a
a
a為原點(diǎn),那么
a
b
→
=
b
?
a
\overrightarrow {ab} = b-a
ab=b?a,
a
c
→
=
c
?
a
\overrightarrow {ac} = c-a
ac=c?a。如果以
a
b
→
,
a
c
→
\overrightarrow {ab} ,\overrightarrow {ac}
ab,ac作為基向量建立坐標(biāo)系。
p
p
p點(diǎn)為三角形的重心,設(shè)
p
p
p點(diǎn)的坐標(biāo)為
(
β
,
γ
)
(\beta,\gamma)
(β,γ),那么點(diǎn)
p
p
p的坐標(biāo)表示即為:
p
=
a
+
β
a
b
→
+
γ
a
c
→
p= a + \beta \overrightarrow {ab} + \gamma \overrightarrow {ac}
p=a+βab+γac
p
=
a
+
β
(
b
?
a
)
+
γ
(
c
?
a
)
p= a + \beta (b-a) + \gamma(c-a)
p=a+β(b?a)+γ(c?a)
p
=
(
1
?
β
?
γ
)
a
+
β
b
+
γ
c
p= (1-\beta - \gamma)a + \beta b+ \gamma c
p=(1?β?γ)a+βb+γc
因此令
(
1
?
β
?
γ
)
=
α
(1-\beta - \gamma) = \alpha
(1?β?γ)=α 即為:
p
(
α
,
β
,
γ
)
=
α
a
+
β
b
+
γ
c
p(\alpha,\beta,\gamma)= \alpha a + \beta b+ \gamma c
p(α,β,γ)=αa+βb+γc
其中
α
+
β
+
γ
=
1
\alpha+\beta +\gamma = 1
α+β+γ=1
好了,這樣重心坐標(biāo)系就建立好了。在這個(gè)坐標(biāo)系下,三角形內(nèi)任意一點(diǎn)的位置可視為三個(gè)頂點(diǎn)的線性組合,通過(guò)重心坐標(biāo)系我們可以很簡(jiǎn)單判斷某個(gè)點(diǎn)是否在三角形內(nèi)部,只需
0
<
α
<
1
,
0
<
β
<
1
,
0
<
γ
<
1
0<\alpha<1,\newline 0<\beta<1,\newline 0<\gamma<1\newline
0<α<1,0<β<1,0<γ<1即可
當(dāng)
α
=
β
=
γ
=
1
3
\alpha = \beta = \gamma = \frac{1}{3}
α=β=γ=31?時(shí)則為重心位置。
片元著色器
片元著色器(Fragment Shader) 是另一個(gè)非常重要的可編程著色器階段,在DirectX中,片元著色器也被稱為像素著色器(Pixel Shader) ,但是我們說(shuō)過(guò)片元包含像素,但不等同于像素,所以片元著色器是更適合的名字。
前面的光柵化階段實(shí)際并不影響屏幕上每個(gè)像素顏色,而是產(chǎn)生一系列數(shù)據(jù)信息,用于描述一個(gè)三角形網(wǎng)格是怎樣覆蓋每個(gè)像素的,而每個(gè)片元負(fù)責(zé)存儲(chǔ)這一系列信息。真正會(huì)對(duì)像素產(chǎn)生影響的是逐片元操作(Pre-Fragment Operation)階段 。
片元著色器的輸入是三角形遍歷階段對(duì)頂點(diǎn)信息進(jìn)行插值后得到的結(jié)果,更具體的說(shuō)是對(duì)頂點(diǎn)著色器的輸出數(shù)據(jù)進(jìn)行插值后得到的。而片元著色器的輸出是一個(gè)或多個(gè)的顏色值,如下圖所示。
在這一階段會(huì)完成許多重要的渲染技術(shù),其中最重要的技術(shù)之一就是紋理采樣,為了在片元著色器進(jìn)行紋理采樣,我們會(huì)在頂點(diǎn)著色器階段輸出每個(gè)頂點(diǎn)對(duì)應(yīng)的紋理坐標(biāo),經(jīng)過(guò)插值之后就能得到其覆蓋的每個(gè)片元的紋理坐標(biāo)了。
雖然片元著色器很重要,但其局限性在于僅能影響單個(gè)片元。也就是說(shuō)當(dāng)執(zhí)行片元著色器時(shí),它不可以將自己的任何結(jié)果直接發(fā)送給它的鄰居(相鄰的其他片元)。除了當(dāng)片元著色器可以訪問(wèn)到導(dǎo)數(shù)信息(gradient或者說(shuō)derivative)時(shí)例外(本章拓展閱讀部分補(bǔ)充)。
逐片元操作
最后一步是逐片元操作,在DirectX中稱為輸出合并階段(Output-Merger)。最主要的目的還是Merge合并,合并的目標(biāo)就是每一個(gè)片元。
這一階段有幾個(gè)主要任務(wù):
- 決定每個(gè)片元的可見(jiàn)性。這涉及很多測(cè)試工作,例如深度測(cè)試、模板測(cè)試等。
- 如果一個(gè)片元通過(guò)了所有的測(cè)試,就需要把這個(gè)片元的顏色值和已經(jīng)存儲(chǔ)在顏色緩沖區(qū)中的顏色進(jìn)行合并,或者說(shuō)是混合。
首先要進(jìn)行的就是片元測(cè)試,這些測(cè)試決定了哪些片元可以被渲染,哪些片元會(huì)被舍棄。簡(jiǎn)單來(lái)說(shuō)就是一個(gè)資格考試,淘汰不合格的片元。只要有一個(gè)測(cè)試沒(méi)通過(guò)就會(huì)被舍棄,之前為這個(gè)片元做的一切工作都會(huì)白費(fèi)。只有通過(guò)測(cè)試的片元才有資格和顏色緩沖區(qū)合并。
書中給出了模板測(cè)試和深度測(cè)試的簡(jiǎn)化流程圖:
片元所需要經(jīng)歷的模板測(cè)試和深度測(cè)試這兩大測(cè)試,都是可以由開(kāi)發(fā)者自行配置的。在模板測(cè)試中,GPU首先讀?。ㄊ褂米x取掩碼)模板緩沖區(qū)中該片元位置的模板之,然后將該值與參考值(也使用讀取掩碼讀?。┻M(jìn)行比較判斷是否舍棄(舍棄條件可以是小于或者大于等于)。然后根據(jù)模板測(cè)試和深度測(cè)試結(jié)果來(lái)修改模板緩沖區(qū)。這個(gè)修改操作也是由開(kāi)發(fā)者指定的,模板測(cè)試通常用于限制渲染的區(qū)域,另外還有例如渲染陰影,輪廓渲染等高級(jí)用法。
如果片元通過(guò)模板測(cè)試,那么還會(huì)進(jìn)行深度測(cè)試。這個(gè)測(cè)試同樣是高度可配置的,GPU會(huì)將片元的深度值與深度緩沖區(qū)的深度值進(jìn)行比較。比較舍棄和上述模板測(cè)試一樣可以定義,通常是小于等于保留,大于等于舍棄。因?yàn)槲覀兿脘秩倦x攝像機(jī)更近,深度更低的物體。與模板測(cè)試不同的是,模板測(cè)試在保留或舍棄時(shí)都可以修改模板緩沖區(qū),但是如果一個(gè)片元沒(méi)有通過(guò)深度測(cè)試,它沒(méi)有權(quán)利更改深度緩沖區(qū)的值,如果它通過(guò)了測(cè)試,開(kāi)發(fā)者可以指定是否用這個(gè)片元的深度值覆蓋掉原有片元的深度值,這是通過(guò)開(kāi)啟/關(guān)閉深度寫入做到的。透明效果和深度測(cè)試以及深度寫入的關(guān)系非常密切。
最后這些片元需要被合并。現(xiàn)在模板緩沖區(qū)已經(jīng)修改了,深度緩沖區(qū)也進(jìn)行了對(duì)應(yīng)操作。其實(shí)所謂的渲染過(guò)程是一個(gè)物體一個(gè)物體地畫到屏幕上的,因此我們還需要對(duì)像素顏色進(jìn)行處理,而每個(gè)像素的顏色信息都被存儲(chǔ)在一個(gè)名為顏色緩沖區(qū)的地方。當(dāng)我們執(zhí)行完這次渲染后,相同位置的顏色緩沖已經(jīng)有了上次處理的結(jié)果,那么這次是直接覆蓋?還是其它操作?這就是合并需要解決的問(wèn)題。
例如對(duì)于不透明的物體,我們可以關(guān)閉混合(Blend) 操作,讓顏色直接覆蓋顏色緩沖。而對(duì)于半透明物體,我們需要混合顏色像素讓其看起來(lái)像是透明的。
混合操作也是高度可配置的,我們可以選擇是否開(kāi)啟混合,如果開(kāi)啟混合,GPU就會(huì)去除源顏色和目標(biāo)顏色,源顏色指的是片元著色器得到的顏色值,而目標(biāo)顏色是已經(jīng)存在于顏色緩沖區(qū)的顏色值。之后使用一個(gè)混合函數(shù)來(lái)進(jìn)行混合操作,這個(gè)混合函數(shù)與透明通道息息相關(guān),例如根據(jù)透明通道的值進(jìn)行相加、相減、相乘等。
那么我們就有疑問(wèn)了,既然有的片元會(huì)在測(cè)試階段被舍棄,這樣不是很浪費(fèi)嗎?那么為什么不先進(jìn)行測(cè)試再進(jìn)行渲染呢?這樣不是可以提高性能嗎?就像下圖的例子一樣:
(上圖先渲染球再渲染長(zhǎng)方體,但是由于球先被渲染且深度更低,因此長(zhǎng)方體大部分片元無(wú)法通過(guò)深度測(cè)試,對(duì)這些片元執(zhí)行片元著色器造成了很大的性能浪費(fèi))
提前進(jìn)行測(cè)試當(dāng)然是可以的,例如文中就提到了可以提前進(jìn)行深度測(cè)試的技術(shù)(Early-Z)。但是如果將測(cè)試提前的話,其檢驗(yàn)結(jié)果可能與片元著色器中的一些操作沖突。例如,如果片元著色器中的代碼進(jìn)行了透明度測(cè)試,而片元沒(méi)能通過(guò),那么它將在著色器中被調(diào)用API(例如clip函數(shù))被手動(dòng)舍棄。這就導(dǎo)致GPU無(wú)法提前進(jìn)行各種測(cè)試。因此,現(xiàn)代的GPU會(huì)判斷片元著色器中的操作是否和提前測(cè)試沖突了,如果有沖突就會(huì)禁用提前測(cè)試。這樣反而導(dǎo)致性能下降了,本來(lái)可以提前測(cè)試,由于添加了透明度測(cè)試反而不能提前測(cè)試了。
最終圖元被渲染完成后會(huì)被呈現(xiàn)在屏幕上,我們的屏幕顯示的就是顏色緩沖區(qū)中的顏色值。但是,為了避免我們看到那些正在進(jìn)行光柵化的圖元,GPU會(huì)使用雙重緩沖(Double Buffering) 的策略,這意味著,對(duì)場(chǎng)景的渲染是在幕后發(fā)生的,即在后置緩沖(Back Buffer) 中。一旦場(chǎng)景被渲染到了后置緩沖中,GPU就會(huì)交換后置緩沖區(qū)和前置緩沖(Front Buffer) 中的內(nèi)容。而前置緩沖區(qū)是之前顯示在屏幕上的圖像。因此保證了我們看到的圖像總是連續(xù)的。(巧妙的方法,避免了渲染導(dǎo)致的畫面不連續(xù)問(wèn)題)
總結(jié)
雖然上述流程描述了很多(其實(shí)曲面細(xì)分著色器和幾何著色器都沒(méi)講),但實(shí)際過(guò)程要更加復(fù)雜。當(dāng)然上述內(nèi)容與其他資料會(huì)產(chǎn)生差異,這是由于圖像編程接口的實(shí)現(xiàn)不盡相同,而GPU在底層也做了很多優(yōu)化?;驹矶际侨跁?huì)貫通的,未來(lái)可在學(xué)習(xí)Games101或者RTR4時(shí)重拾。
在Unity中為我們封裝了很多功能,更多時(shí)候我們只需要在一個(gè)Unity Shader設(shè)置一些輸入,編寫頂點(diǎn)著色器和片元著色器,設(shè)置一些狀態(tài)就能達(dá)到大部分常見(jiàn)的屏幕效果。(更別說(shuō)現(xiàn)在Unity提供了URP和SRP等渲染管線)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-835895.html
雖然概念生疏,但是堅(jiān)持才是勝利。無(wú)論經(jīng)歷了什么,選擇了什么,既然選擇了從事這個(gè)行業(yè),那么都應(yīng)該貫徹到底。勉勵(lì)自己,也勉勵(lì)諸位。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-835895.html
到了這里,關(guān)于【UnityShader入門精要學(xué)習(xí)筆記】第二章(2)GPU流水線的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!