(原)Unreal渲染模組 管線 - 程式和場景查詢
@author: 白袍小道
檢視隨意,轉載隨緣
第一部分:
這裡主要關心加速演算法,和該階段相關的UE模組的結構和元件的處理。
What-HOW-Why-HOW-What(嘿嘿,老規矩)
1、渲染模組這裡有個主要任務需要完成:將需要在螢幕上(或者某裝置)顯示出來的Primitives(幾何體,或者繪製圖元)輸入到pipeline的下一階段。
2、渲染的每幀,計算Camera,Light,Primitives輸出到幾何階段(非幾何著色)
插一句:Geometry State包含了視點變換,頂點著色,投影、裁剪、對映
3、幾個空間資料結構和演算法:
層次包圍,入口裁剪、QuadTree, 空間分隔樹, Kd樹,八叉樹,場景圖、細節裁剪
空間資料結構:
是將幾何體組織在N維空間中的一系列層次(上抱下,下抱下下,類推)資料結構
層次包圍體BVH
入口裁剪PortalCulling
細節裁剪( 螢幕尺寸裁剪 )
具有包圍體的問題,將這個包圍體投射到投影平面,然後以畫素為單位來估算投影面積,如果畫素的數量小於使用者定義的閾值,那麼不對這個物體進行進一步處理。
遮擋刪除
遮擋剔除必要性:
不難理解,可見性問題可以通過Z緩衝器的硬體構造來實現,即使可以使用Z緩衝器正確解決可見性問題,但其中Z緩衝並不是在所有方面都不是一個很"聰明"的機制。例如,假設視點正沿著一條直線觀察,其中,在這條直線上有10個球體,雖然這10個球體進行了掃描轉換,同時與Z緩衝器進行了比較並寫入了顏色緩衝器和Z緩衝器,但是這個從這個視點渲染出的影象只會顯示一個球體,即使所有10個球體都將被光柵化並與Z緩衝區進行比較,然後可能寫入到顏色緩衝區與Z緩衝區。
上圖中間部分顯示了在給定視點處場景的深度複雜度,深度複雜度指的是對每個畫素重寫的次數。對於有10個球體的情形,最中間的位置,深度複雜度為
兩種主要形式的遮擋裁剪演算法,分別是基於點的遮擋裁剪和基於單元的遮擋裁剪
虛擬碼--------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
下面是常用幾種遮擋演算法
1、硬體遮擋查詢(UE中有,也可以自己先寫寫,然後測試對照)
硬體遮擋查詢的基本思想是,當和Z緩衝器中內容進行比較時,使用者可以通過查詢硬體來找到一組多邊形是否可見的,且這些多邊形通常是複雜物體的包圍體(如長方體或者k-DOP)。如果其中沒有多邊形可見,那麼便可將這個物體裁剪掉。硬體實現對查詢的多邊形進行光柵化,並且將其深度和Z緩衝器進行比較
2、HZB(同上)
層次Z-緩衝演算法用八叉樹來維護場景模型,並將畫面的Z緩衝器作為影象金字塔(也稱為Z-金字塔(Z-pyramid)),該演算法因此在影象空間中進行操作。其中,八叉樹能夠對場景的遮擋區域進行層次剔除,而Z-金字塔則可以對單個基元和邊界體積進行層次Z緩衝。 因此Z-金字塔可以作為此演算法的遮擋表示。
通過從前到後遍歷八叉樹並裁剪遇到的八叉樹節點,此演算法可以僅訪問可見的八叉樹節點及其子節點(右上角的節點),
的容器只對可見包圍體中的多邊形進行渲染。
3、遮擋地平線演算法
通過從前到後渲染一個場景,我們可以定位到地平線在哪裡進行渲染,而任何在當前地平線之後和之下的物體都可以被裁剪掉。
4、遮擋物收縮與視錐擴張演算法(也有類似處理)
可以使用基於點的遮擋演算法來生成基於單元的可見性,根據給定的量來縮小場景中所有遮擋物來達到延伸有效可見點的目的,
通常與Occluder Shrinking演算法一起配合使用
5、LOD這個放到後面細說。【篇幅不少】
6、裁剪圖策略:後面加入
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二部分:
下面按照延時渲染來過一下。
涉及主要類
DeferredShadingSceneRenderer
SceneRender
SceneOcclusion
FSceneViewState
TStaticMeshDrawList
FRenderTask
FDrawVisibleAnyThreadTask
DrawingPolicy
一、FDeferredShadingSceneRenderer::InitViews
這裡主要通過檢測可見性,透明排序等,完成檢視初始化。這裡我們關注檢測可見性
1、 燈光資訊的可見分配。
2、預處理可見性
位於檔案:SceneVisibility.cpp
FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList)
2.1 |
得到當前預處理可見性的資料 |
FSceneViewState::GetPrecomputedVisibilityData
完成任務:
*返回給定檢視位置的可見性資料陣列(資料),如果不存在,則返回NULL。
*資料位通過場景中每個原語的VisibilityId進行索引。
*此方法在必要時解壓縮資料,並基於檢視狀態中的bucket和chunk(優化時候也需要注意)索引快取資料
(這裡若需要檢視可以通過幾個除錯選項【詳細在後面備註】,然後烘培)
如何完成:
a、計算盒子的ViewOrigin是否在格子中,這裡利用反過來將盒子雜湊到bucket去減少了計算量。
這裡盒子偏移,Bucket索引計算可以看看。
b、若有必要解壓資料
2.1後(構建有時會覆蓋截錐體,就是迭代覆蓋視口的圖元可見性Map【view.PrimitiveVisibilityMap】)
2.2 |
計算使用標準視錐體裁剪的圖元的數目---FrustumCull |
接下來是引擎特性(處理view.PrimitiveVisibilityMap)
2.2a |
更新了檢視的原始fade狀態(略)。 |
2.2b |
(掃描VisibilityMap後面就說VMP)如果幾何體標記為Hide,view.PrimitiveVisibilityMap標記 |
2.2c |
檢視屬性標記了只顯示幾何體的,那其他同樣標記 |
2.2d |
反射捕獲(Reflection Captures)的處理:只對接受非移動的. |
2.2e |
剔除線框中的小框物件【就一個投射矩陣判斷】【主要是提高編輯器,因為線框模式的禁止了遮擋,我去】 |
2.2f |
(不線上框中的)進行剔除 |
2.3 |
OcclusionCull |
這裡才是演算法實現的開始,包括使用前面說的預計算資料,根據特徵級別(opengl,dx)做不同的OC處理
a、軟處理(自己整CPU處理)FSceneSoftWareOCclusion。
b、FetchVisibilityForPrimitives處理(還有FHZBOcclusionTester)
c、標記到非OC(沒得整)組
2.3.1 |
FSceneSoftWareOCclusion |
幾個重要事情:
SubmitScene
CollectOccludeeGeom
Sort potential occluders by weight
Add sorted occluders to scene up to GSOMaxOccluderNum
reserve space for occludees vis flags
ProcessOcclusionFrame:
上面基本是資料的規整,這裡才是執行演算法過程
2.3.1.1 |
ProcessOccluderGeom,對著演算法來一遍(嘿嘿) |
每個模型
a\ 轉換模型到裁剪空間【矩陣操作】
每個三角形
b\ 修正三角形:ClippedVertexToScreen,TestFrontface,AddTriangle
【滿足裁頂點加或修正三角形:按深度(獲取離屏最遠的)】
(詳細稍後補齊)
2.3.1.2 |
按深度整理【最接近螢幕的在前】 柵格化遮擋刪除 |
2.3.2 |
FetchVisibilityForPrimitives |
這裡先略(那啥,放到另外一個地方)
1、若支援並行處理:構建資料FVisForPrimParams,利用上多工FetchVisibilityForPrimitivesTask處理FHZBBound
2、FOcclusionQueryBatcher::BatchPrimitive (一個演算法)
3、排序BasePass,實現HiZ剔除
如果我們不使用深度僅通過排序靜態繪製列表桶大致從前到後,以最大化HiZ剔除。不會干擾狀態排序,且每個列表都是單獨排序的
(客官,待續)
4、提交視野的自定義資料
5、RHI資源(構建)
檢驗: