簡(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í)多選多個(gè)類進(jìn)行查看,在類圖上右鍵也可以添加基類和派生類到視圖中,可以一鍵排布布局


結(jié)構(gòu)梳理
首先看一下幾個(gè)基類

主要涉及四個(gè)類
RenderPipelineAsset、RenderPipeline、scriptableRendererData、ScriptableRenderer
從名字可以看出
- RenderPipelineAsset 和 RenderPipeline 應(yīng)該是一對(duì)兒,我們簡(jiǎn)稱為管線對(duì)兒
- ScriptableRendererData 和 ScriptableRenderer 是一對(duì)兒,我們簡(jiǎn)稱其為渲染對(duì)兒
其中 RenderPipelineAsset 為管線對(duì)兒的數(shù)據(jù)文件,ScriptableRendererData 為渲染對(duì)兒的數(shù)據(jù)文件
分對(duì)兒看
管線對(duì)兒 RenderPipelineAsset 和 RenderPipeline
-
先看 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 -
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
-
RenderPipeline
RenderPipeline 這是個(gè)抽象基類,和 RenderPipelineAsset 是對(duì)應(yīng)的,主要提供了一些約定方法。
RenderPipeline 抽象類 -
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ì)象
- 先看 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 -
UniversalRendererData
引擎默認(rèn)派生了三個(gè) data 類 Renderer2DData、ForwardRendererData、UniversalRendererData,其中的 ForwardRenderer 是一個(gè)被舍棄的 Renderer,被UniversalRendererData代替。
每一個(gè)data派生類,內(nèi)部都有一個(gè) ShaderResources 類,用來保存當(dāng)前管線需要的一些 shader 路徑。

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

可以看到,基本包含了一些具體的渲染設(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 列表的。
-
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 等
-
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
- 主要用于實(shí)際的渲染操作,大部分存在于 RenderFeature 和 ScriptableRenderer 中。
- ScriptableRenderer 中包含了 m_ActiveRenderPassQueue 隊(duì)列,F(xiàn)eature 內(nèi)的 pass 也通過遍歷的形式被添加進(jìn) m_ActiveRenderPassQueue
- 渲染操作遍歷 m_ActiveRenderPassQueue 進(jìn)行渲染狀態(tài)的操作與渲染
- 所以 ScriptableRendererFeature 可以實(shí)現(xiàn)類似舊管線中的多 pass 渲染
ScriptableRendererFeature
- ScriptableRendererData 內(nèi)包含 ScriptableRendererFeature 列表
- 在生成 ScriptableRenderer 的時(shí)候會(huì)將 ScriptableRendererData 內(nèi)的 ScriptableRendererFeature 傳遞到 ScriptableRenderer 的 m_RendererFeatures 內(nèi)。
- 在 ScriptableRenderer 抽象類內(nèi),需要調(diào)用的地方以遍歷的形式進(jìn)行調(diào)用,例如 AddRenderPasses、OnPreCullRenderPasses、Dispose 等
- ScriptableRendererFeature 的派生類內(nèi)基本都會(huì)包含一個(gè) renderObjectsPass,通過前幾步的調(diào)用關(guān)系,便可以將當(dāng)前的feature的pass 傳遞到 Renderer 的渲染過程中。
- ScriptableRendererFeature 內(nèi)可以包含各種設(shè)置屬性,用來設(shè)置其內(nèi)部將要參與渲染的 ScriptableRenderPass
結(jié)束
基本結(jié)構(gòu)和相互關(guān)系,大致如此,主要的就是先了解四個(gè)基類的關(guān)系,然后是其派生類

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

至于具體的派生類,有時(shí)間慢慢了解即可







