渲染管线概述
一、渲染的概念
渲染是指以軟件由模型生成圖像的過程
渲染管線(廣義)分為CPU應(yīng)用程序端渲染邏輯和GPU渲染管線(通常我們說的渲染管線)
預(yù)渲染與實時渲染
- 預(yù)渲染:預(yù)渲染的計算強度很大,需要大量的服務(wù)器運算完成,渲染需要很長時間,通常用于電影制作等
- 實時渲染:實時渲染需要在一秒鐘內(nèi)完成至少24幀圖像,如果想流暢就需要至少60幀圖像。所以實時渲染需要一些優(yōu)化手段急速渲染過程。實時渲染通常通過圖形處理器(GPU)完成這個過程。
二、CPU(當(dāng)相機調(diào)用render()時開始工作)
第一步 剔除(Culling)
1?? 視錐體剔除(Frustum Culling)
攝像機根據(jù)FOV(Field of View 視場角) 和遠近裁面形成一個錐臺,讓模型和這個錐臺進行碰撞檢測,如果沒有碰撞說明不在視野內(nèi),直接剔除,不需要渲染。
🎯 Tips 1: 有的模型表面的網(wǎng)格非常復(fù)雜(比如球體)
簡化處理:生成一個AABB包圍盒與錐臺進行碰撞檢測
2?? 遮擋剔除(Occlusion Culling)
3?? 層級剔除(Layer Culling Mask)
第二步 確定渲染順序—排序(Sort)
Render Queue 的數(shù)值越小,表示物體越先被渲染
如果Render Queue相等,會分成兩個渲染隊列,不透明渲染隊列和透明渲染隊列
1?? 不透明渲染隊列(Render Queue < 2500)
按攝像機距離從前到后排序
🍜Tips 1: Why?
這其實是一種優(yōu)化,離得近的如果覆蓋了遮擋了距離遠的,那后者就可以不用渲染了
2?? 半透明渲染隊列(Render Queue > 2500)
按攝像機距離從后向前排序
🍜Tips 1: Why?
這是為了保證渲染結(jié)果的正確性
第三步 打包數(shù)據(jù) 發(fā)送給GPU
包含大量數(shù)據(jù)和參數(shù)
第四步 調(diào)用Shader:SetPassCall、DrawCall 發(fā)送給GPU
三、GPU
收到指令SetPassCall、DrawCall 和 CPU 傳送的打包數(shù)據(jù)
第一步 通過一系列工作將模型渲染成2D圖像
1?? 頂點處理
頂點Shader:將模型空間頂點轉(zhuǎn)換成裁剪空間,然后又硬件來將這些頂點映射到屏幕上(3D變2D)
- 最重要的任務(wù):將頂點坐標(biāo)從模型空間變換到裁剪空間
- 經(jīng)過頂點Shader處理后,相機金字塔狀的視錐體被轉(zhuǎn)換變形成一個比例為221的立方體(CVV)
- 頂點Shader并不會產(chǎn)生2D圖像,僅使得場景中的3D對象產(chǎn)生變形效果
拍照過程:放置物體 -> 擺好相機 -> 摁下快門
通過矩陣完成以下空間變化
① 模型空間 -> 世界空間
② 世界空間 -> 相機空間
③ 相機空間 -> 裁剪空間
2?? 圖元裝配及光柵化(硬件操作階段)
圖元裝配:將點連接起來
光柵化:在圖元內(nèi)部插入片元(類似還沒有顯示的像素)
光柵化之后3D徹底變成2D
具體操作
① 裁剪操作
對裁剪空間進行裁剪。與視錐體相交的部分會被裁剪不渲染部分并生成新的三角面,完全在外面的就直接裁剪掉
② 透視除法
將裁剪后的物體坐標(biāo)縮放到標(biāo)準(zhǔn)化設(shè)備坐標(biāo)(NDC)
③ 背面剔除
根據(jù)索引列表來判斷是否為背面。
④ 視口轉(zhuǎn)換
將標(biāo)準(zhǔn)化設(shè)備坐標(biāo)轉(zhuǎn)化為屏幕坐標(biāo)(只轉(zhuǎn)化x,y坐標(biāo))
⑤ 圖元裝配
前面的所有操作都是頂點操作,圖元裝配環(huán)節(jié)將點進行連線
⑥ 光柵化
生成在圖形內(nèi)部生成片元
z坐標(biāo)值會通過插值儲存為片元的深度值等各種數(shù)據(jù)來幫我們處理前后遮擋關(guān)系等
插值:我們知道兩邊界點的值,算出中間的值
3?? 片元處理
每一個片元都會調(diào)用自己的片元Shader進行計算
片元Shader:對片元進行著色 ------ 光照著色,紋理著色
紋理圖像:一個二維數(shù)組,利用文素地址儲存一組顏色值
- 紋理技術(shù)
- 紋理采樣:給定一個數(shù)值,找對對應(yīng)的像素地址顏色值
- 紋理過濾機制:解決小圖->大屏幕問題
- 常規(guī)處理:對中間的值直接四舍五入為最接近的值進行采樣:會失真(對應(yīng)Unity中的Point)
- 優(yōu)化:對周圍四個值進行插值運算,最終結(jié)果會柔和很多(雙線性插值,對應(yīng)Unity中的Bilinear)
- Mipmap紋理鏈:解決大圖->映射到小塊區(qū)域問題 ------ 生成一系列不同大小的圖像,選用合適的來映射(對應(yīng)Unity中的Generate Mip Maps)
- 紋理尋址模式:確定紋理坐標(biāo)查出文素地址范圍時的處理方法(對應(yīng)Unity中的Wrap Mode)
- 紋理壓縮格式:將我們傳入的圖片轉(zhuǎn)換為各種平臺能夠使用的壓縮格式,不同壓縮格式對最終結(jié)果有很大影響
- 光照計算
- 光照形成
- 直接光照:考慮的是光線到達
- 間接光照
- 光照模型
- Phong光照模型:
- 一個物體表面的顏色由三個因素決定:
- 漫反射—反射出去的光線在各個方向上都是均等的
- 鏡面反射 光滑度:決定衰減范圍
- 環(huán)境光:間接光照
- 基本框架—這些光照效果相加就是最終呈現(xiàn)的效果
- 直接光漫反射
- 直接光鏡面反射
- 間接光漫反射
- 間接光鏡面反射
- More
- Phong光照模型:
- 光照形成
4?? 輸出合并
處理遮擋關(guān)系和顏色混合等等,并完成輸出
- 最重要的任務(wù):處理遮擋關(guān)系、處理半透明混合
- 通俗地講:片元通過重重考驗到達像素點位置的過程
流程:
① Alpha測試
檢測片元的Alpha值,如果太小就可以直接丟棄
② 模板測試
③ 深度測試
檢測片元的深度值:深度越小越應(yīng)該渲染(小于深度緩沖區(qū)深度值才能寫入,寫入后更新深度緩沖區(qū)的深度值)
- ZWrite 深度寫入:關(guān)閉ZWrite后,通過深度測試之后的片元仍然寫入,但深度緩沖區(qū)不更新
- ZTest 深度測試:默認是小于深度緩沖區(qū)的值才能寫入,但可以強制修改
- Early-Z 提前深度測試:發(fā)生在頂點Shader之后,片元Shader之前。是一種優(yōu)化
④ 混合
可以柔和地將片元都輸出到像素點,進行混合
- 從后到前(半透明混合之前提到過)
- 關(guān)閉ZWrite
🍪 Tips 1: Shader是什么?
Shader是運行在GPU上的一段可編程的程序
一個完整的Shader由頂點Shader和片元Shader組合而成
第二步 輸出到幀緩沖區(qū)
幀緩沖區(qū)相當(dāng)于是臨時的畫布,當(dāng)全部渲染完畢時,幀緩沖區(qū)的內(nèi)容可以顯示到屏幕中
緩沖區(qū)分為顏色緩沖區(qū)、深度緩沖區(qū)和模板緩沖區(qū)
第三步 后處理操作
顯示到屏幕前,CPU可以拿到幀緩沖區(qū)的內(nèi)容,進行二次修改(調(diào)色、Bloom等)然后再傳送給GPU渲染管線,最終才顯示在屏幕上
四、多個相機
每個相機會跑完整的渲染流程
相機通過Depth決定渲染順序,后渲染的可以通過Clear Flags確定是否清除前一個相機的渲染。
參考資料:視頻教程
總結(jié)
- 上一篇: BP神经网络处理iris数据集(Pyto
- 下一篇: 教你精确计算 I2C 上拉电阻阻值