Unity URP 管線主要類之間的關(guān)系梳理

簡(jiǎn)介: 最近有一個(gè)功能要修改管線,引擎沒有人手,那就只能靠自己了,個(gè)人是很不喜歡改內(nèi)置的東西的,不過迫不得已也得干呀,既然要改,甭管該多少,先抽點(diǎn)時(shí)間梳理一下 URP(SRP) 的來龍去脈。
軟件: unity 2021.3.21f1c1
管線:com.unity.render-pipelines.universal@12.1.7
還額外獲得了一個(gè)看類的好工具-VS的類設(shè)計(jì)器,下面也會(huì)附上用法

類設(shè)計(jì)器的安裝與使用

打開安裝工具

單個(gè)組件,類設(shè)計(jì)器安裝

在一個(gè)類上右鍵 選擇查看類圖,便可以查看,可以同時(shí)多選多個(gè)類進(jìn)行查看,在類圖上右鍵也可以添加基類和派生類到視圖中,可以一鍵排布布局


查看類圖

類圖關(guān)系

結(jié)構(gòu)梳理

首先看一下幾個(gè)基類

render和data類

主要涉及四個(gè)類
RenderPipelineAsset、RenderPipeline、scriptableRendererData、ScriptableRenderer
從名字可以看出

  1. RenderPipelineAsset 和 RenderPipeline 應(yīng)該是一對(duì)兒,我們簡(jiǎn)稱為管線對(duì)兒
  2. ScriptableRendererData 和 ScriptableRenderer 是一對(duì)兒,我們簡(jiǎn)稱其為渲染對(duì)兒
    其中 RenderPipelineAsset 為管線對(duì)兒的數(shù)據(jù)文件,ScriptableRendererData 為渲染對(duì)兒的數(shù)據(jù)文件

分對(duì)兒看

管線對(duì)兒 RenderPipelineAsset 和 RenderPipeline

  1. 先看 RenderPipelineAsset ,啟用 URP 管線必要的配置文件,可簡(jiǎn)單理解為,URP 就從這里開始(在這之前可能還有其它方法來調(diào)用,但我們可以先找一個(gè)簡(jiǎn)單的頭) 。
    其中的 RenderPipelineAsset 就是我們使用 URP 管線時(shí)首先要?jiǎng)?chuàng)建的管線資源文件,所以他的主要功能就是用來存儲(chǔ)管線需要用到的數(shù)據(jù)和配置

    PipelineAsset文件

    設(shè)置管線Asset文件后,我們的 URP 管線就正式激活了

    RenderPipelineAsset
    是一個(gè)抽象類,主要有四個(gè)方法 CreatePipleline、OnDisable、OnValidate、RenderPipelineAsset(構(gòu)造函數(shù)),屬性就是一些類似配置的屬性。通過方法可以看出,RenderPipelineAsset 的主要目的就是使用其保存的數(shù)據(jù)和配置創(chuàng)建對(duì)應(yīng)的 RenderPipeline 管線。
    默認(rèn) URP 自帶一個(gè) RenderPipelineAsset 的派生類UniversalRenderPipelineAsset ,這個(gè)就是我們實(shí)際使用的管線Asset文件。我們要寫自己的管線,那么我們的Asset文件也需要派生自 RenderPipelineAsset

  2. UniversalRenderPipelineAsset
    默認(rèn) URP 的管線數(shù)據(jù)資源類,他有一個(gè)自己的 Editor界面繪制類 UniversalRenderPipelineAssetEditor。界面如下

    URP Asset

    主要包含渲染設(shè)置,質(zhì)量設(shè)置,燈光設(shè)置,陰影設(shè)置,后處理設(shè)置。
    可以看出,這個(gè)類就是用來配置我們渲染管線的相關(guān)設(shè)置的。

    • 提供了右鍵菜單創(chuàng)建 UniversalRenderPipelineAsset 文件的功能,在創(chuàng)建的過程中還會(huì)自動(dòng)創(chuàng)建一個(gè) ScriptableRendererData 對(duì)象并保存為Asset文件,這個(gè)文件就是用來后期生成 ScriptableRenderer 用的。
    • 包含一個(gè) UniversalRenderData 的對(duì)象列表,用來生成和設(shè)置相機(jī)的 ScriptableRenderer。
    • 以屬性的形式保存了管線需要的一些默認(rèn)材質(zhì)球
    • 提供通過索引來獲取 ScriptableRenderer 的方法 GetRenderer
  3. RenderPipeline
    RenderPipeline 這是個(gè)抽象基類,和 RenderPipelineAsset 是對(duì)應(yīng)的,主要提供了一些約定方法。

    RenderPipeline 抽象類

  4. UniversalRenderPipeline
    UniversalRenderPipeline 是 unity 默認(rèn)帶的一個(gè) URP 的 RenderPipeline 派生類,如果我們沒有自定義過其它 RenderPipeline 那應(yīng)該只有這一個(gè)具體實(shí)現(xiàn)類。它是通過 UniversalRenderPipelineAsset 的 (protected) CreatePipeline 方法來創(chuàng)建的。
    UniversalRenderPipeline 的構(gòu)造函數(shù)默認(rèn)強(qiáng)制傳入一個(gè) UniversalRenderPipelineAsset 對(duì)象,原因就是 UniversalRenderPipeline 需要使用 UniversalRenderPipelineAsset 里面的數(shù)據(jù)和配置生成正確的 Pipeline

    包含的方法

    • 這個(gè)類就具體的負(fù)責(zé)了渲染的流程,例如相機(jī)的設(shè)置,相機(jī)的排序,相機(jī)的堆棧渲染,燈光的處理,渲染的調(diào)用,等等
    • 這個(gè)類在 URP 的默認(rèn)源碼中的一處調(diào)用是 UniversalRenderPipelineAsset 的 scriptableRendererData 屬性,這個(gè)屬性用來獲取默認(rèn)材質(zhì)和獲取 ScriptableRendererData ,其 get 方法調(diào)用了 CreatePipeline();。
    • 另一處就是 UniversalRenderPipelineAsset 的基類 RenderPipelineAsset 約定的 (internal) InternalCreatePipeline 中調(diào)用了 抽象方法 CreatePipeline(),這個(gè)方法在 UniversalRenderPipelineAsset 進(jìn)行了實(shí)現(xiàn)。

渲染對(duì)兒 ScriptableRendererData 和 ScriptableRenderer

與 RenderPipelineAsset和 RenderPipeline 關(guān)系類似,ScriptableRendererData 是一個(gè)數(shù)據(jù)配置存儲(chǔ)文件,用來生成 ScriptableRenderer 對(duì)象。UniversalRenderPipelineAsset 對(duì)象內(nèi)部用一個(gè) ScriptableRendererData[] 數(shù)組來保存不同的 ScriptableRendererData 對(duì)象

  1. 先看 ScriptableRendererData
    一個(gè)可以序列化保存的對(duì)象,主要包含一個(gè) RenderFeatures 列表,公用方法就一個(gè) SetDirty() ,還一個(gè)保護(hù)類型的 Create 抽象方法,用來創(chuàng)建 ScriptableRenderer 。
    結(jié)構(gòu)很簡(jiǎn)單,大體意思應(yīng)該就是約定,renderdata 內(nèi)需要保存 RenderFeatures ,然后派生類需要實(shí)現(xiàn) Create()方法用來創(chuàng)建對(duì)應(yīng)的 ScriptableRenderer 對(duì)象
    ScriptableRendererData
  2. UniversalRendererData
    引擎默認(rèn)派生了三個(gè) data 類 Renderer2DData、ForwardRendererData、UniversalRendererData,其中的 ForwardRenderer 是一個(gè)被舍棄的 Renderer,被UniversalRendererData代替。
    每一個(gè)data派生類,內(nèi)部都有一個(gè) ShaderResources 類,用來保存當(dāng)前管線需要的一些 shader 路徑。
三個(gè)data派生類

UniversalRendererData 有一個(gè)專門的 UniversalRendererDataEditor 類來繪制其 Inspector 界面


UniversalRendererData 界面

可以看到,基本包含了一些具體的渲染設(shè)置,還有基類約定的 Feature 對(duì)象。
* 實(shí)現(xiàn)了基類的 Create() 方法,用來創(chuàng)建對(duì)應(yīng)的 ScriptableRenderer
* 包含渲染排序,渲染路徑的設(shè)置,后處理等渲染選項(xiàng)的設(shè)置,和 UniversalRenderPipelineAsset 不同的是,UniversalRenderPipelineAsset 的設(shè)置大部分是關(guān)于,整套管線的流程類型的,UniversalRendererData 則側(cè)重于具體的渲染開關(guān),和 pass 設(shè)置。 也就是 UniversalRendererData 負(fù)責(zé)的是 UniversalRenderPipelineAsset 負(fù)責(zé)的整個(gè)管線中渲染的一小部分。所以 UniversalRenderPipelineAsset 里面是有一個(gè) UniversalRendererData 列表的。

  1. ScriptableRenderer
    一個(gè)抽象類,使用 ScriptableRendererData 的配置數(shù)據(jù),通過ScriptableRendererData 的 Create 方法進(jìn)行創(chuàng)建其派生類。
    • 包含大量的渲染開關(guān)和屬性,用來做具體渲染時(shí)的控制
    • 構(gòu)造函數(shù)必須包含 ScriptableRendererData 對(duì)象,確保生成的 renderer 的正確性
    • 主要針對(duì)相機(jī)的渲染操作,例如,設(shè)置渲染target,設(shè)置 culling 參數(shù),設(shè)置燈光,設(shè)置渲染前的pass 等
  2. UniversalRenderer
    ScriptableRenderer 的派生數(shù)量與 ScriptableRendererData 的數(shù)量 一 一 對(duì)應(yīng)。
    三個(gè)renderer派生類
    • UniversalRenderer 的方法與基類方法基本一致,大部分都是覆寫。
    • 主要用來處理渲染時(shí),渲染對(duì)象,渲染狀態(tài)等的控制
    • 內(nèi)部持有大量的 ScriptableRenderPass(抽象類)的派生類,用來處理渲染效果。
    • 持有大量的渲染材質(zhì),用來處理渲染效果。
    • 持有大量的RTHandle ,用來處理渲染輸出。
    • 所以 UniversalRenderer 是我們應(yīng)用到的最多的渲染類。


      內(nèi)部持有的大量渲染用對(duì)象

擴(kuò)散

上述幾個(gè)類的相互關(guān)系

  • RenderPipelineAsset 生成 RenderPipeline,RenderPipeline 用來控制管線的渲染流程
  • RenderPipelineAsset 包含 ScriptableRendererData 列表
  • ScriptableRendererData 生成 ScriptableRenderer , ScriptableRenderer 用來控制渲染指令和狀態(tài)

UniversalAdditionalCameraData

RednerPipeline 咋調(diào)用的 ScriptableRenderer 呢
在上面的代碼分析中,我們并沒有找到直接的調(diào)用關(guān)系

  • 引擎在切換到 URP 管線后,我們會(huì)注意到,相機(jī)上會(huì)新增一個(gè) UniversalAdditionalCameraData 組件,這個(gè)組件內(nèi)部的一個(gè)共有屬性 scriptableRenderer 它通過相機(jī)上設(shè)置的 renderer 的索引,使用 UniversalRenderPipeline.asset.GetRenderer(defaultIndex); 來獲取當(dāng)前相機(jī)的 ScriptableRenderer 。

  • 在 UniversalRenderPipeline 的 InitializeAdditionalCameraData 方法執(zhí)行時(shí),將 ScriptableRenderer 包裝進(jìn)了 CameraData,所以在 pipeline 的執(zhí)行過程中,大部分情況下可以通過 CameraData 來獲取 ScriptableRenderer ,對(duì)應(yīng)的屬性名為 renderer
    cameraData.renderer = asset.scriptableRenderer;

  • 所以之前也說 ScriptableRenderer 是針對(duì)與相機(jī)渲染的

ScriptableRenderPass

  1. 主要用于實(shí)際的渲染操作,大部分存在于 RenderFeature 和 ScriptableRenderer 中。
  2. ScriptableRenderer 中包含了 m_ActiveRenderPassQueue 隊(duì)列,F(xiàn)eature 內(nèi)的 pass 也通過遍歷的形式被添加進(jìn) m_ActiveRenderPassQueue
  3. 渲染操作遍歷 m_ActiveRenderPassQueue 進(jìn)行渲染狀態(tài)的操作與渲染
  4. 所以 ScriptableRendererFeature 可以實(shí)現(xiàn)類似舊管線中的多 pass 渲染

ScriptableRendererFeature

  1. ScriptableRendererData 內(nèi)包含 ScriptableRendererFeature 列表
  2. 在生成 ScriptableRenderer 的時(shí)候會(huì)將 ScriptableRendererData 內(nèi)的 ScriptableRendererFeature 傳遞到 ScriptableRenderer 的 m_RendererFeatures 內(nèi)。
  3. 在 ScriptableRenderer 抽象類內(nèi),需要調(diào)用的地方以遍歷的形式進(jìn)行調(diào)用,例如 AddRenderPasses、OnPreCullRenderPasses、Dispose 等
  4. ScriptableRendererFeature 的派生類內(nèi)基本都會(huì)包含一個(gè) renderObjectsPass,通過前幾步的調(diào)用關(guān)系,便可以將當(dāng)前的feature的pass 傳遞到 Renderer 的渲染過程中。
  5. ScriptableRendererFeature 內(nèi)可以包含各種設(shè)置屬性,用來設(shè)置其內(nèi)部將要參與渲染的 ScriptableRenderPass

結(jié)束

基本結(jié)構(gòu)和相互關(guān)系,大致如此,主要的就是先了解四個(gè)基類的關(guān)系,然后是其派生類


四個(gè)大類

然后就是四大類中主要用到的幾個(gè)類


相關(guān)類

至于具體的派生類,有時(shí)間慢慢了解即可
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容