(整)Unreal渲染模塊 框總覽


@author: 黑袍小道

隨緣查看

   

說明

由於搬山的渲染這部分擔心自己理解錯誤,故而搬移官方下,后面整個完成再反過來更新

(這當且僅當做Unreal的幫助文檔)

   

圖形編程

模塊

渲染器代碼存在於其自身的模塊中。此模塊將編譯為非單塊版本的一個 dll 文件。這可以使迭代更快,因為在渲染代碼變更時無需重新鏈接整個應用程序。渲染器模塊取決於引擎,因為其擁有許多向引擎的回調。然而當引擎需要調用渲染器中的某些代碼時,這會通過某個接口來完成,通常為 IRendererModule FSceneInterface

場景代表

UE4 中,渲染器所見的場景由基本組件和 FScene 中存儲的多種其他結構的列表定義。將維護一個基元的八叉樹,用於加速空間查詢。

主要場景類

UE4 中擁有和游戲線程並行運行的渲染線程。

主要的類為:

描述

UWorld

包含多個可交互的 Actor 和組件的世界場景。關卡可以流送進入和退出世界場景,且程序中可以同時有多個世界場景處於激活狀態。

ULevel

一同加載/卸載並保存在同一地圖文件中的 Actor 和組件合集。

USceneComponent

需要添加到 FScene 中的任意對象的基礎類,如光照、網格體、霧等。

UPrimitiveComponent

可渲染或進行物理交互的任意資源的基礎類。也可以作為可視性剔除的粒度和渲染屬性規范(投射陰影等)。與所有 UObjects 一樣,游戲線程擁有所有變量和狀態,渲染線程不應直接對其進行訪問。

ULightComponent

代表光源。渲染器負責計算和添加其對場景的貢獻。

FScene

UWorld 的渲染器版本。對象僅在其被添加到 FScene(注冊組件時調用)后才會存在於渲染器中。渲染線程擁有 FScene 中的所有狀態,游戲線程無法直接對其進行修改。

FPrimitiveSceneProxy

UPrimitiveComponent 的渲染器版本,為渲染線程映射 UPrimitiveComponent 狀態。存在於引擎模塊中,用於划分為子類以支持不同類型的基元(骨架、剛體、BSP 等)。實現某些非常重要的函數,如 GetViewRelevanceDrawDynamicElements 等。

FPrimitiveSceneInfo

內部渲染器狀態(FRendererModule 實現專有),對應於 UPrimitiveComponent FPrimitiveSceneProxy。存在於渲染器模塊中,因此引擎看不到它。

FSceneView

單個視圖到一個 FScene 的引擎代表。視圖可以通過對 FSceneRenderer::Render 的不同調用的不同視圖來渲染(多編輯器視口)或通過對 FSceneRenderer::Render 的同一調用中的多個視圖來渲染(分屏游戲)。為每個幀構建新視圖。

FViewInfo

視圖的內部渲染器代表,存在於渲染器模塊中。

FSceneViewState

ViewState 存儲有關在多個幀中需要的某個視圖的私有渲染器信息。在游戲中,每個 ULocalPlayer 只有一個視圖狀態。

FSceneRenderer

為每個幀創建的類,用於封裝跨幀的臨時對象。

下面按其所在的模塊列出了各種主類。

引擎模塊

渲染器模塊

UWorld

FScene

UPrimitiveComponent / FPrimitiveSceneProxy

FPrimitiveSceneInfo

FSceneView

FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent / FLightSceneProxy

FLightSceneInfo

以及相同類(按哪個線程對其狀態擁有所有權進行排列)。

游戲線程

渲染線程

UWorld

FScene

UPrimitiveComponent

FPrimitiveSceneProxy / FPrimitiveSceneInfo

  

FSceneView / FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent

FLightSceneProxy / FLightSceneInfo

   

材質類

描述

FMaterial

連接用於渲染的材質的接口。可用於訪問材質屬性(如混合模式)。包含被渲染器用於檢索個體着色器的着色器地圖。

FMaterialResource

UMaterial FMaterial 接口實現。

FMaterialRenderProxy

材質在渲染線程上的代表。可用於訪問 FMaterial 接口和各個標量、向量和紋理參數。

UMaterialInterface

[abstract] 用於材質功能的游戲線程接口。用於檢索用於渲染的 FMaterialRenderProxy 和用作來源的 UMaterial

UMaterial

材質資源。授權為節點圖形。計算用於着色、設置混合模式等的材質屬性。

UMaterialInstance

[abstract] UMaterial 的實例。使用 UMaterial 中的節點圖形,但提供不同參數(標量、向量、紋理、靜態切換)。每個實例都有一個父項 UMaterialInterface。因此,材質實例的父項可能是 UMaterial 或另一個 UMaterialInstance。這會形成一個鏈,最終通往 UMaterial

UMaterialInstanceConstant

只能在編輯器中修改的 UMaterialInstance。可以提供標量、向量、紋理和靜態開關參數。

UMaterialInstanceDynamic

可以在運行時修改的 UMaterialInstance。可提供標量、向量和紋理參數。無法提供靜態開關參數,且無法成為另一 UMaterialInstance 的父項。

   

基元組件和代理

基元(就是Prim)組件是可視性和相關性確定的基本單位。例如,遮蔽和視錐剔除都是按基元進行的。因此在設計系統時,考慮組件的大小十分重要。每個組件都有一個邊界,用於多種操作,如剔除、陰影投射和光照影響確定。

組件只有在注冊之后才會對場景(以及渲染器)可見。

更改組件屬性的游戲線程代碼必須調用組件上的 MarkRenderStateDirty(),將更改傳播到渲染線程。

FPrimitiveSceneProxy FPrimitiveSceneInfo

FPrimitiveSceneProxy UPrimitiveComponent 的渲染線程版本,用於根據組件類型划分子類。

它存在於引擎模塊中,並在渲染通道中調用函數。

FPrimitiveSceneInfo 是基元組件狀態,為渲染器模塊私有。

重要的 FPrimitiveSceneProxy 方法

函數

描述

GetViewRelevance

在幀的開始從 InitViews 調用,並返回填充的 FPrimitiveViewRelevance

DrawDynamicElements

調用,以便在某代理相關的任何通道中繪制該代理。僅在代理表示自己擁有動態相關性時調用。

DrawStaticElements

調用以在基元與游戲線程相連時提交代理的 StaticMesh 元素。僅在代理表示自己擁有靜態相關性時調用。

   

場景渲染順序

渲染器按照其希望將數據整合給渲染目標的順序處理場景。例如,僅 Depth 的通道會比 Base 通道先渲染,先填充 Heirarchical Z (HiZ),從而降低基礎通道中的着色消耗。此順序是按通道函數在 C++ 中調用的順序靜態決定的。

相關性

FPrimitiveViewRelevance 是說明通道與基元相關的信息。基元可能有存在不同相關性的多個元素,因此 FPrimitiveViewRelevance 相當於一個所有元素的相關性的邏輯 OR。這表示基元可以同時存在不透明和透明相關性,或動態和靜態相關性;它們並非相互排斥。

FPrimitiveViewRelevance 還會顯示基元是否需要使用動態 (bDynamicRelevance) /或靜態 (bStaticRelevance) 渲染路徑。

繪制規則

繪制規則包括通過通道特定的着色器渲染網格體的邏輯。它們使用 FVertexFactory 接口來抽取網格體類型,並使用 FMaterial 接口來抽取材質詳情。在最底層,一條繪制規則會負責一組網格體材質着色器以及一個頂點工廠,將頂點工廠的緩沖區與渲染硬件接口 (RHI) 綁定,將網格體材質着色器與 RHI 綁定,設置適當的着色器參數,然后執行 RHI 繪制調用。

繪制規則方法

函數

描述

Constructor

從給定的頂點工廠和材質着色器地圖,並存儲這些引用。

CreateBoundShaderState

為繪制規則創建 RHI 邊界着色器狀態。

Matches/Compare

提供排列繪制規則與靜態繪制列表中的其他項目的方法。Matches 必須比較 DrawShared 依賴的所有因素。

DrawShared

設置在從 Matches 返回 True 的繪制規則之間一致的 RHI 狀態。例如,大多數繪制規則會為材質和頂點工廠排序,因此着色器參數只依賴可以設置的材質,並且可以綁定特定於該頂點工廠的頂點緩沖區。應盡可能在此處設置狀態,而非在 SetMeshRenderState 設置,因為 DrawShared 在靜態渲染路徑中調用較少。

SetMeshRenderState

設置特定於此網格體的 RHI 狀態,或 DrawShared 中未設置的任何項目。這比 DrawShared 調用的次數多得多,因此此處性能非常重要。

DrawMesh

實際發出 RHI 繪制調用。

   

渲染路徑

UE4 擁有動態路徑(能夠提供更多的控制,但轉換較慢)和靜態渲染路徑(緩存盡可能靠近 RHI 級別的場景轉換)。差異基本上是整體上的,因為它們都在最底層使用繪制規則。應確保各個渲染通道(繪制規則)在需要時能夠同時處理兩個渲染路徑。

動態渲染路徑

動態渲染路徑使用 TDynamicPrimitiveDrawer 並對每個要渲染的基元場景代理調用 DrawDynamicElements。需要使用動態路徑來渲染的一組基元通過 FViewInfo::VisibleDynamicPrimitives 來跟蹤。每個渲染通道都需要在此陣列上迭代,並調用各個基元上的 DrawDynamicElements。隨后,代理的 DrawDynamicElements 需按需要組合出多個 FMeshElements,並將其隨 DrawRichMesh TDynamicPrimitiveDrawer::DrawMesh 提交。這樣最終會創建一個新的臨時繪制規則,調用 CreateBoundShaderStateDrawSharedSetMeshRenderState 以及 DrawMesh

靜態渲染路徑

靜態渲染路徑通過靜態繪制列表實現。網格體在連接到場景時會插入到繪制列表中。在插入過程中,將調用代理上的 DrawStaticElements,以收取 FStaticMeshElements。隨后將隨 CreateBoundShaderState 的結果創建並存儲一個繪制規則實例。新的繪制示例將根據其 Compare Matches 函數排序,並插入到繪制列表中的適當位置(參見 TStaticMeshDrawList::AddMesh)。在 InitViews 中,包含靜態繪制列表中的可見性數據的 bitarray 會初始化並傳遞到 TStaticMeshDrawList::DrawVisible(實際繪制繪制列表的地方)。DrawShared 只會對所有相互匹配的繪制規則調用一次,而 SetMeshRenderState DrawMesh 會對每個 FStaticMeshElement(參見 TStaticMeshDrawList::DrawElement)調用。

靜態渲染路徑會將許多工作移動連接時間,這會大大加快渲染時的場景轉換。在渲染線程上針對靜態網格體時,靜態繪制列表的渲染會快 3 倍,從而允許場景中出現多得多的靜態網格體。由於靜態繪制列表會在連接時間緩存數據,因此它們僅能緩存與視圖無關的狀態。很少重新連接但經常需要渲染的基元非常適合靜態繪制列表。

靜態渲染路徑可能會暴露出 bug,因為它每個狀態桶只調用 DrawShared 一次。這些 bug 可能會很難發現,因為它們取決於場景中網格體的渲染順序和連接順序。特別的視圖模式(如僅光照、無光照等)會強制所有基元使用動態路徑,因此如果在強制動態渲染路徑時 bug 消失,則其很可能是由於某繪制規則的 DrawShared / Matches 函數的錯誤實現而出現的。

總體渲染順序

下面將說明從 FDeferredShadingSceneRenderer::Render 開始渲染一個幀時的控制流程:

操作

描述

GSceneRenderTargets.Allocate

按需要重新分配全局場景渲染目標,使其對當前視圖足夠大。

InitViews

通過多種剔除方法為視圖初始化基元可見性,設立此幀可見的動態陰影、按需要交叉陰影視錐與世界場景(對整個場景的陰影或預陰影)。

PrePass / Depth only pass

RenderPrePass / FDepthDrawingPolicy。渲染遮擋物,對景深緩沖區僅輸出景深。該通道可以在多種模式下工作:禁用、僅遮蔽,或完全景深,具體取決於活動狀態的功能的需要。該通道通常的用途是初始化 Hierarchical Z 以降低 Base 通道的着色消耗(Base 通道的像素着色器消耗非常大)。

Base pass

RenderBasePass / TBasePassDrawingPolicy。渲染不透明和遮蓋的材質,向 GBuffer 輸出材質屬性。光照圖貢獻和天空光照也會在此計算並加入場景顏色。

Issue Occlusion Queries / BeginOcclusionTests

提出將用於下一幀的 InitViews 的延遲遮蔽查詢。這會通過渲染所查詢物體周圍的相鄰的框、有時還會將相鄰的框組合在一起以減少繪制調用來完成。

Lighting

陰影圖將對各個光照渲染,光照貢獻會累加到場景顏色,並使用標准延遲和平鋪延遲着色。光照也會在透明光照體積中累加。

Fog

霧和大氣在延遲通道中對不透明表面進行逐個像素計算。

Translucency

透明度累加到屏外渲染目標,在其中它應用了逐個頂點的霧化,因而可以整合到場景中。光照透明度在一個通道中計算最終光照以正確融合。

Post Processing

多種后期處理效果均通過 GBuffers 應用。透明度將合成到場景中。

以上是相當簡單概略的介紹。如需了解詳情,請通讀相關代碼或輸出的"profilegpu"日志。

渲染硬件接口 (RHI)

RHI 是平台特定的圖形 API 之上的一個薄層。UE4 中的 RHI 抽象層盡可能低,這樣大多數功能都能以與平台無關的代碼寫成,從而能夠在支持所需功能層級的任何平台上運行。

功能集將量化到 ERHIFeatureLevel 中,降低復雜程度。如果平台無法支持某個功能層級所需的全部功能,則其必須降低層級,直至能夠全部支持。

功能層級

描述

SM5

通常對應於 D3D11 Shader Model 5,但由於 OpenGL 4.3 限制,僅有 16 種紋理可以使用。支持曲面細分、計算着色器和立方體貼圖陣列。支持延遲着色路徑。

SM4

對應 D3D11 Shader Model 4,這與 SM5 基本相同,但沒有曲面細分、計算着色器和立方體貼圖陣列。支持延遲着色路徑。不支持眼適應,因為其使用計算着色器。

ES2

對應大多數 OpenGL ES2 移動設備支持的功能。使用削減向前着色路徑。

渲染狀態分組

渲染狀態根據其影響的流程部分而分組。例如,RHISetDepthState 可設置所有與景深緩沖相關的狀態。

渲染狀態默認值

由於渲染狀態數量眾多,要在每次繪制之前對它們全部設置一遍是不現實的。為此,UE4 具有隱性設置的一組狀態,它們被認為是設置為了默認值(因此在變更后必須恢復為默認值),另外還有一組少得多的狀態需要顯性設置。沒有隱性默認值的狀態有:

  • RHISetRenderTargets
  • RHISetBoundShaderState
  • RHISetDepthState
  • RHISetBlendState
  • RHISetRasterizerState
  • RHISetBoundShaderState 設置的着色器的任何依賴性

    其他所有狀態均視為已設置為其默認值(即相關 TStaticState 的定義,如默認的蠟紙模板狀態由 RHISetStencilState(TStaticStencilState<>::GetRHI()) 設置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM