「技美之路」图形 1.1 渲染流水线
今日起開始分享學(xué)習(xí)技美之路專欄,文章來源聽課筆記以及業(yè)界大佬分享的經(jīng)驗(yàn)文章,主要來自CSDN_知乎等。技美路漫長 一定要堅(jiān)持??開始吧!
一.整體流程
整體流程(渲染管線可分為四個(gè)階段)每一個(gè)階段的輸出為下一個(gè)階段的輸入
?
應(yīng)用階段:準(zhǔn)備的是場景,你的對(duì)象的基本數(shù)據(jù),比如說場景里面的物體他們的位置朝向、大小以及物體對(duì)應(yīng)的模型里邊每一個(gè)頂點(diǎn)的位置,法線、切線等等;場景光源的位置朝向和一些基本屬性,還有攝像機(jī)的位置朝向等等。這些數(shù)據(jù)用處在哪里,進(jìn)入下一個(gè)階段
幾何階段:首先在頂點(diǎn)著色器里,我們有可能需要計(jì)算頂點(diǎn)光照,那么頂點(diǎn)光照就需要知道光源的位置和朝向以及攝像機(jī)的位置和朝向,還有當(dāng)前頂點(diǎn)的世界位置,通過這些數(shù)據(jù)來進(jìn)行計(jì)算,曲面細(xì)分著色器,需要通過現(xiàn)有的頂點(diǎn)來生成更多的頂點(diǎn),那么也需要知道現(xiàn)有頂點(diǎn)在模型里的位置信息。幾何著色器,需要通過現(xiàn)有的圖元來做一些幾何方面的操作,生成更多的頂點(diǎn)和圖元比如對(duì)現(xiàn)有圖源所在的平面生成法線 那么同樣需要知道現(xiàn)有圖源的頂點(diǎn)的位置,同樣的幾何階段要為光柵化階段準(zhǔn)備數(shù)據(jù)
比如要干掉看不到的屏幕以外的頂點(diǎn),這就是頂點(diǎn)裁剪
還需要把頂點(diǎn)位置從 3D坐標(biāo)空間轉(zhuǎn)換到2D坐標(biāo)空間,這就是屏幕映射
光柵化階段:拿到映射到2D空間里的頂點(diǎn)位置,我們要把它組裝成三角形,這就是三角形設(shè)置然后還要知道三角形包含了哪些2D空間的像素點(diǎn),這就是三角形遍歷最后我們要對(duì)這些點(diǎn)使用它們包含的數(shù)據(jù)來著色,并且為后面的逐片元著色準(zhǔn)備數(shù)據(jù)
逐片元操作:我們的操作對(duì)象就變成了光柵化操作輸出的片元數(shù)據(jù),片元可以理解成為屏幕上的某一個(gè)像素點(diǎn),對(duì)于這些片元我們需要進(jìn)行一系列的測試。比如透明度測試,深度測試和模板測試,通過測試的片元就保留起來,否則就丟棄掉,然后在2D屏幕坐標(biāo)系當(dāng)中,同一個(gè)位置上的像素點(diǎn)有可能會(huì)對(duì)應(yīng)于多個(gè)不同的片元,那么我們可能還需要把這些通過測試的片元的顏色進(jìn)行一個(gè)混合操作,從而得到像素點(diǎn)最終輸出的顏色,逐片元操作完成以后,我們就得到了一個(gè)類似于貼圖的數(shù)據(jù)保存在內(nèi)存里,然后我們對(duì)這個(gè)數(shù)據(jù)還可以做一個(gè)后處理,可以理解成為圖像處理,比如模糊、景深、高光等等,那么這樣的話渲染管線每個(gè)階段之間的關(guān)系大概就講清楚了。
二.分階段介紹
?
應(yīng)用階段
?
在渲染管線中,應(yīng)用階段是在CPU中進(jìn)行處理的
?
- 首先是準(zhǔn)備場景,從磁盤或是內(nèi)存上讀取模型或者貼圖數(shù)據(jù),將其加載進(jìn)應(yīng)用程序中,對(duì)象為基本數(shù)據(jù):包括不限于場景中的物體的位置,朝向,大小,物體網(wǎng)格數(shù)據(jù),頂點(diǎn)位置,UV貼圖,法線,切線等;場景的光源位置朝向,類型,參數(shù)屬性等;攝像機(jī)位置朝向,模式,視口長寬比等等…
補(bǔ)充:光源和陰影
設(shè)置光源:
1.方向光,顏色,方向等
2.點(diǎn)光源:顏色,位置,范圍等
3.聚光源:顏色,位置,方向,內(nèi)外圓錐角等
設(shè)置陰影:
1.是否需要陰影:判斷該光源可見范圍內(nèi)是否有可投陰影的物體
2.陰影參數(shù):對(duì)應(yīng)光源序號(hào),陰影強(qiáng)度,級(jí)聯(lián)參數(shù),深度偏移,近平面偏移等
逐光源繪制陰影范圍:
1.近平面偏移
2.逐級(jí)聯(lián)
計(jì)算當(dāng)前光源+級(jí)聯(lián)對(duì)應(yīng)的觀察矩陣,投影矩陣,以及對(duì)應(yīng)到陰影貼圖里的視口區(qū)域
繪制到陰影貼圖
?
- 加速算法,粗粒度剔除:處理遮擋的問題,不會(huì)看到的,就不渲染,降低渲染成本,提高渲染性能
- 可見光裁剪:點(diǎn)光和聚光有衰減,聚光錐體有區(qū)域;若離相機(jī)距離較遠(yuǎn),或者光錐與相機(jī)的視錐體不相交,則剔除渲染;
- 可見場景物體裁剪:遮擋啥的,相關(guān)算法:八叉樹,BSP樹,k-D樹,PVH包圍盒等
- 說起裁剪就不由想起圖形學(xué)里的經(jīng)典裁剪算法:Liang-Barsky算法,Cohen-Sutherland算法(編碼裁剪算法)這兩個(gè)算法是用于將圖像裁剪到可見范圍內(nèi)
- 設(shè)置渲染狀態(tài),準(zhǔn)備渲染參數(shù):渲染UI和場景,其參數(shù)和模式可能不一樣,通俗解釋:場景中的網(wǎng)格如何被渲染,渲染順序是啥,使用哪個(gè)頂點(diǎn)著色器/片元著色器,光源屬性,材質(zhì),最后會(huì)渲染到哪里,渲染模式等等…
- 繪制設(shè)置:使用著色器,合批方式(gpu 動(dòng)態(tài)合批)
- 繪制物體順序:相對(duì)相機(jī)距離,材質(zhì)RenderQueue, UICanvas等
- 渲染目標(biāo):FrameBuffer, RenderTexture...
- 渲染模式:前向渲染(ForwardBase ForwardAdd),延遲渲染
- 調(diào)用DrawCall,輸出渲染圖元到顯存:圖元從CPU邁向GPU
- DrawCall是一個(gè)命令,發(fā)起方是CPU,接收方是GPU。僅指向一個(gè)需要被渲染的圖元(Primitives)列表。
- 頂點(diǎn)數(shù)據(jù):位置,顏色,法線,紋理uv坐標(biāo),其他頂點(diǎn)數(shù)據(jù)
- 其他數(shù)據(jù):MVP變換矩陣,紋理貼圖,其他數(shù)據(jù)
幾何階段
?
- 頂點(diǎn)著色器(VertexShader):完全可編程,實(shí)現(xiàn)頂點(diǎn)的空間變換、頂點(diǎn)著色等
- 曲面細(xì)分著色器(TessellationShader):可選著色器,用于細(xì)分圖元
- 幾何著色器(GeometryShader)可選著色器,執(zhí)行逐圖元著色操作
- 裁剪(Clipping):將不在相機(jī)視野內(nèi)的頂點(diǎn)裁剪掉,可配置
- 屏幕映射(ScreenMapping):不可配置和編程
幾何階段,光柵化,逐片元這些操作都是在GPU中進(jìn)行處理的,那么在講幾何階段前,我們先聊聊為什么要用GPU渲染?
答:GPU的特點(diǎn)是并行性較好。當(dāng)我們在對(duì)頂點(diǎn)數(shù)據(jù)進(jìn)行處理時(shí),他們雖然數(shù)據(jù)不同,但光照,幾何運(yùn)算方式啥都一樣的時(shí)候,那么我們將他們放在GPU的不同工作單元上進(jìn)行同時(shí)執(zhí)行,速度會(huì)更快。
?
頂點(diǎn)著色器:必須完成的一個(gè)工作:將頂點(diǎn)坐標(biāo)從模型空間轉(zhuǎn)換到齊次裁剪空間(投影坐標(biāo)系),同時(shí)它還有計(jì)算頂點(diǎn)光照的功能,這需要獲取應(yīng)用階段中光源位置朝向,攝像機(jī)位置朝向,當(dāng)前頂點(diǎn)的世界位置(獲取該位置需知道頂點(diǎn)在模型空間的位置,模型本身的位置旋轉(zhuǎn)縮放…);
?
頂點(diǎn)著色器-視圖變換:模型坐標(biāo)系--(模型變換) --> 世界坐標(biāo)系--(視圖變換)-->視圖坐標(biāo)系 --(投影變換)-->投影坐標(biāo)系--(視口變換)-->視口坐標(biāo)系 上圖中的前三個(gè)變換對(duì)應(yīng)MVP(model view projection)矩陣,在頂點(diǎn)著色器中,頂點(diǎn)從模型坐標(biāo)系轉(zhuǎn)換到投影坐標(biāo)系,最后一步由Unity幫忙完成
曲面細(xì)分著色器:通過現(xiàn)有頂點(diǎn)生成更多的頂點(diǎn),需獲取頂點(diǎn)在模型中的位置信息
它是一個(gè)可選著色器,使用頂點(diǎn)著色器輸出的頂點(diǎn),按照一定規(guī)則算法生成更多頂點(diǎn),將現(xiàn)有的網(wǎng)格和圖元細(xì)分(其效果類似于MAYA中的“平滑”效果,模型圓滑了但面數(shù)增大了)
幾何著色器(基于圖元):通過現(xiàn)有的圖元做些幾何方面操作,二手手機(jī)號(hào)出售生成更多頂點(diǎn)和圖元,比如對(duì)現(xiàn)有圖元所在平面生成法線,需獲取現(xiàn)有圖元頂點(diǎn)位置
圖元是啥?
答:可以為頂點(diǎn),線段,倆頂點(diǎn),三角形...基礎(chǔ)的幾何圖形
投影:將3D空間投到2D空間
對(duì)于頂點(diǎn)在裁剪空間里的位置,xyzw進(jìn)行透視除法:xyz除以w完成投影。使其從投影坐標(biāo)系轉(zhuǎn)換到標(biāo)準(zhǔn)設(shè)備坐標(biāo)系(NDC);
由于正交和透視視角下w值不同,故而呈現(xiàn)效果不同,正交顯得像截圖,透視則近大遠(yuǎn)小
頂點(diǎn)裁剪:消去屏幕外的頂點(diǎn);
不在相機(jī)視野內(nèi)的物體不需要被處理。一個(gè)圖元和相機(jī)視野有3種關(guān)系:
完全在視野內(nèi):繼續(xù)傳遞給下一階段
部分在視野內(nèi):需要進(jìn)行裁剪(Clipping),使用新的頂點(diǎn)來代替
完全在視野外:不會(huì)向下傳遞
?
- 投影里又說要進(jìn)行除法操作,當(dāng)xyz超過-1~1范圍,則判斷其不在范圍內(nèi),
舍棄進(jìn)行經(jīng)典的圖形學(xué)裁剪算法;
- 投影和頂點(diǎn)裁剪在《Shader入門精要》中都是歸屬于裁剪一節(jié)中,這個(gè)操作過程無法由代碼控制,是硬件上固定操作,但可以自定裁剪操作進(jìn)行配置
- 設(shè)備坐標(biāo)系在opengl和DirectX中不一樣,opengl xyz三維度取值范圍都是-1~1,DirectX只有xy是-1~1,z為0~1
屏幕映射:
將頂點(diǎn)位置從3D坐標(biāo)空間轉(zhuǎn)換到2D坐標(biāo)空間;
屏幕映射(ScreenMapping)的任務(wù)是把每個(gè)圖元x和y坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)系(ScreenCoordinates)。不處理z坐標(biāo)。opengl和DirectX原點(diǎn)不同,opengl左下方,DirectX左上方
?
按照《Shader入門精要》所言:屏幕映射任務(wù)是把每個(gè)圖元的x和y坐標(biāo)轉(zhuǎn)換到屏幕坐標(biāo)系。
如應(yīng)用階段為幾何階段準(zhǔn)備數(shù)據(jù)一樣,幾何階段同樣會(huì)為光柵化階段準(zhǔn)備數(shù)據(jù)
光刪化階段
三角形設(shè)置:拿到映射于2D空間里的頂點(diǎn)位置,組裝成三角形;
三角形遍歷:尋找被三角形覆蓋的所有像素的過程,知曉包含哪些2D空間像素點(diǎn)
《Shader入門精要》:三角形遍歷階段將檢查每個(gè)像素是否被一個(gè)三角網(wǎng)格所覆蓋,若覆蓋,則生成一個(gè)片元。
片元非像素,它是包含很多狀態(tài)的集合,這些狀態(tài)用于計(jì)算每個(gè)像素的最終顏色,這些狀態(tài)包含不限于,屏幕坐標(biāo),深度信息,從幾何階段輸出的頂點(diǎn)信息,法線,紋理坐標(biāo)等。屏幕同一個(gè)像素位置可能有對(duì)應(yīng)多個(gè)三角形的不同片元(如兩片重疊的交集)
抗鋸齒(MSAA):
1.SSAA:
渲染到一個(gè)分辨率放大n倍的buffer:屏幕分辨率1024x1024,渲染得到buffer可為2048x2048,放大四倍,對(duì)其采樣后再輸出屏幕
對(duì)方打n倍的buffer下采樣
2.MSAA
只有它發(fā)生在光柵化階段
計(jì)算多個(gè)覆蓋樣本:覆蓋測試看子采樣點(diǎn)是否在三角形以內(nèi),遮擋測試看這個(gè)子采樣度的深度和,即與深度緩存中數(shù)值進(jìn)行比較,看能否通過,若能通過兩測試,則說明采樣點(diǎn)屬于三角形,得到覆蓋信息并保存,用于之后的著色混合
3.FXAA/TXAA
后處理技術(shù)
逐片元操作
?
決定可見性:
模板測試(StencilTest):將片元位置的模板值,和參考值進(jìn)行比較
深度測試(DepthTest):將片元的深度值,和深度緩沖區(qū)的深度值進(jìn)行比較
合并顏色。對(duì)于不透明物體,可以關(guān)閉混合,用片元著色器得到的顏色值覆蓋顏色緩沖區(qū)的像素值。對(duì)于半透明物體,要混合。
如果在執(zhí)行片元著色器之前就進(jìn)行這些測試,可以提高GPU性能,早點(diǎn)知道那些片元會(huì)被舍棄。深度測試提前執(zhí)行的技術(shù)Early-Z。透明度測試會(huì)導(dǎo)致禁用提前測試,使性能下降。
為了避免我們看到正在進(jìn)行光柵化的圖元,GPU會(huì)使用雙重緩沖(DoubleBuffering)。渲染在幕后,在后置緩沖(BackBuffer)中,一旦完成,GPU會(huì)交換后置緩沖區(qū)和前置緩沖(FrontBuffer)的內(nèi)容。
后處理
Bloom,HDR,FXAA,景深,邊緣檢測,徑向模糊
什么是OpenGL/DirectX
OpenGL/DirectX圖像應(yīng)用編程接口。運(yùn)行在CPU上的應(yīng)用程序->調(diào)用OpenGL/DirectX等圖形接口,將數(shù)據(jù)存在顯存,
發(fā)出DrawCall->顯卡驅(qū)動(dòng)翻譯成GPU能理解的代碼。
?
什么是HLSL、GLSL、CG
著色語言(ShadingLanguage):
DirectX的HLSL(HighLevelShadingLanguage)
OpenGL的GLSL(OpenGLShadingLanguage)
NVIDIA的CG(C for Graphic)
在UnityShader中,可以選擇使用哪種,但有所區(qū)別。
什么是DrawCall
DrawCall,CPU調(diào)用圖像編程接口,以命令GPU進(jìn)行渲染的操作。
問題一:CPU和GPU是如何實(shí)現(xiàn)并行工作的?
命令緩沖區(qū)(CommandBuffer),讓CPU和GPU可以并行工作。CPU向其中添加命令,GPU從中讀取命令,添加和讀取的過程是相互獨(dú)立的。
?
問題二:為什么DrawCall多了會(huì)影響幀率?
GPU渲染能力很強(qiáng),速度往往快于CPU提交命令的速度。如果DrawCall的數(shù)量太多,CPU會(huì)耗費(fèi)大量時(shí)間造成過載。
?
問題三:如何減少DrawCall?
這里討論批處理方法(Batching)。把很多小的DrawCall合并成一個(gè)大的DrawCall,更適合合并靜態(tài)的物體,因?yàn)橹恍韬喜⒁淮巍?/span>
?
為了減少DrawCall的開銷,需要注意:
避免使用大量很小的網(wǎng)格,合并小網(wǎng)格
避免使用過多的材質(zhì),盡量在不同網(wǎng)格之間共用同一個(gè)材質(zhì)
什么是固定管線渲染
固定函數(shù)的流水線(Fixed-Function Pipeline),簡稱為固定管線,只給開發(fā)者一些配置操作。隨著時(shí)代的發(fā)展,可編程渲染管線應(yīng)運(yùn)而生,如頂點(diǎn)著色器、片元著色器。
那么,你明白什么是Shader了嗎
Shader所在階段,就是渲染流水線的一部分:
GPU流水線上一些可高度編程的階段,由著色器編譯出來的最終代碼會(huì)在GPU上運(yùn)行
有一些特定類型的著色器,如頂點(diǎn)著色器、片元著色器
依靠著色器我們可以控制流水線中的渲染細(xì)節(jié)
總結(jié)
以上是生活随笔為你收集整理的「技美之路」图形 1.1 渲染流水线的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「技美之路」图形 1.2.1 向量基础
- 下一篇: 设计总结:腾讯光子《和平精英》全新UI