Unity URP 管线主要类之间的关系梳理

简介: 最近有一个功能要修改管线,引擎没有人手,那就只能靠自己了,个人是很不喜欢改内置的东西的,不过迫不得已也得干呀,既然要改,甭管该多少,先抽点时间梳理一下 URP(SRP) 的来龙去脉。
软件: unity 2021.3.21f1c1
管线:com.unity.render-pipelines.universal@12.1.7
还额外获得了一个看类的好工具-VS的类设计器,下面也会附上用法

类设计器的安装与使用

打开安装工具

单个组件,类设计器安装

在一个类上右键 选择查看类图,便可以查看,可以同时多选多个类进行查看,在类图上右键也可以添加基类和派生类到视图中,可以一键排布布局


查看类图

类图关系

结构梳理

首先看一下几个基类

render和data类

主要涉及四个类
RenderPipelineAsset、RenderPipeline、scriptableRendererData、ScriptableRenderer
从名字可以看出

  1. RenderPipelineAsset 和 RenderPipeline 应该是一对儿,我们简称为管线对儿
  2. ScriptableRendererData 和 ScriptableRenderer 是一对儿,我们简称其为渲染对儿
    其中 RenderPipelineAsset 为管线对儿的数据文件,ScriptableRendererData 为渲染对儿的数据文件

分对儿看

管线对儿 RenderPipelineAsset 和 RenderPipeline

  1. 先看 RenderPipelineAsset ,启用 URP 管线必要的配置文件,可简单理解为,URP 就从这里开始(在这之前可能还有其它方法来调用,但我们可以先找一个简单的头) 。
    其中的 RenderPipelineAsset 就是我们使用 URP 管线时首先要创建的管线资源文件,所以他的主要功能就是用来存储管线需要用到的数据和配置

    PipelineAsset文件

    设置管线Asset文件后,我们的 URP 管线就正式激活了

    RenderPipelineAsset
    是一个抽象类,主要有四个方法 CreatePipleline、OnDisable、OnValidate、RenderPipelineAsset(构造函数),属性就是一些类似配置的属性。通过方法可以看出,RenderPipelineAsset 的主要目的就是使用其保存的数据和配置创建对应的 RenderPipeline 管线。
    默认 URP 自带一个 RenderPipelineAsset 的派生类UniversalRenderPipelineAsset ,这个就是我们实际使用的管线Asset文件。我们要写自己的管线,那么我们的Asset文件也需要派生自 RenderPipelineAsset

  2. UniversalRenderPipelineAsset
    默认 URP 的管线数据资源类,他有一个自己的 Editor界面绘制类 UniversalRenderPipelineAssetEditor。界面如下

    URP Asset

    主要包含渲染设置,质量设置,灯光设置,阴影设置,后处理设置。
    可以看出,这个类就是用来配置我们渲染管线的相关设置的。

    • 提供了右键菜单创建 UniversalRenderPipelineAsset 文件的功能,在创建的过程中还会自动创建一个 ScriptableRendererData 对象并保存为Asset文件,这个文件就是用来后期生成 ScriptableRenderer 用的。
    • 包含一个 UniversalRenderData 的对象列表,用来生成和设置相机的 ScriptableRenderer。
    • 以属性的形式保存了管线需要的一些默认材质球
    • 提供通过索引来获取 ScriptableRenderer 的方法 GetRenderer
  3. RenderPipeline
    RenderPipeline 这是个抽象基类,和 RenderPipelineAsset 是对应的,主要提供了一些约定方法。

    RenderPipeline 抽象类

  4. UniversalRenderPipeline
    UniversalRenderPipeline 是 unity 默认带的一个 URP 的 RenderPipeline 派生类,如果我们没有自定义过其它 RenderPipeline 那应该只有这一个具体实现类。它是通过 UniversalRenderPipelineAsset 的 (protected) CreatePipeline 方法来创建的。
    UniversalRenderPipeline 的构造函数默认强制传入一个 UniversalRenderPipelineAsset 对象,原因就是 UniversalRenderPipeline 需要使用 UniversalRenderPipelineAsset 里面的数据和配置生成正确的 Pipeline

    包含的方法

    • 这个类就具体的负责了渲染的流程,例如相机的设置,相机的排序,相机的堆栈渲染,灯光的处理,渲染的调用,等等
    • 这个类在 URP 的默认源码中的一处调用是 UniversalRenderPipelineAsset 的 scriptableRendererData 属性,这个属性用来获取默认材质和获取 ScriptableRendererData ,其 get 方法调用了 CreatePipeline();。
    • 另一处就是 UniversalRenderPipelineAsset 的基类 RenderPipelineAsset 约定的 (internal) InternalCreatePipeline 中调用了 抽象方法 CreatePipeline(),这个方法在 UniversalRenderPipelineAsset 进行了实现。

渲染对儿 ScriptableRendererData 和 ScriptableRenderer

与 RenderPipelineAsset和 RenderPipeline 关系类似,ScriptableRendererData 是一个数据配置存储文件,用来生成 ScriptableRenderer 对象。UniversalRenderPipelineAsset 对象内部用一个 ScriptableRendererData[] 数组来保存不同的 ScriptableRendererData 对象

  1. 先看 ScriptableRendererData
    一个可以序列化保存的对象,主要包含一个 RenderFeatures 列表,公用方法就一个 SetDirty() ,还一个保护类型的 Create 抽象方法,用来创建 ScriptableRenderer 。
    结构很简单,大体意思应该就是约定,renderdata 内需要保存 RenderFeatures ,然后派生类需要实现 Create()方法用来创建对应的 ScriptableRenderer 对象
    ScriptableRendererData
  2. UniversalRendererData
    引擎默认派生了三个 data 类 Renderer2DData、ForwardRendererData、UniversalRendererData,其中的 ForwardRenderer 是一个被舍弃的 Renderer,被UniversalRendererData代替。
    每一个data派生类,内部都有一个 ShaderResources 类,用来保存当前管线需要的一些 shader 路径。
三个data派生类

UniversalRendererData 有一个专门的 UniversalRendererDataEditor 类来绘制其 Inspector 界面


UniversalRendererData 界面

可以看到,基本包含了一些具体的渲染设置,还有基类约定的 Feature 对象。
* 实现了基类的 Create() 方法,用来创建对应的 ScriptableRenderer
* 包含渲染排序,渲染路径的设置,后处理等渲染选项的设置,和 UniversalRenderPipelineAsset 不同的是,UniversalRenderPipelineAsset 的设置大部分是关于,整套管线的流程类型的,UniversalRendererData 则侧重于具体的渲染开关,和 pass 设置。 也就是 UniversalRendererData 负责的是 UniversalRenderPipelineAsset 负责的整个管线中渲染的一小部分。所以 UniversalRenderPipelineAsset 里面是有一个 UniversalRendererData 列表的。

  1. ScriptableRenderer
    一个抽象类,使用 ScriptableRendererData 的配置数据,通过ScriptableRendererData 的 Create 方法进行创建其派生类。
    • 包含大量的渲染开关和属性,用来做具体渲染时的控制
    • 构造函数必须包含 ScriptableRendererData 对象,确保生成的 renderer 的正确性
    • 主要针对相机的渲染操作,例如,设置渲染target,设置 culling 参数,设置灯光,设置渲染前的pass 等
  2. UniversalRenderer
    ScriptableRenderer 的派生数量与 ScriptableRendererData 的数量 一 一 对应。
    三个renderer派生类
    • UniversalRenderer 的方法与基类方法基本一致,大部分都是覆写。
    • 主要用来处理渲染时,渲染对象,渲染状态等的控制
    • 内部持有大量的 ScriptableRenderPass(抽象类)的派生类,用来处理渲染效果。
    • 持有大量的渲染材质,用来处理渲染效果。
    • 持有大量的RTHandle ,用来处理渲染输出。
    • 所以 UniversalRenderer 是我们应用到的最多的渲染类。


      内部持有的大量渲染用对象

扩散

上述几个类的相互关系

  • RenderPipelineAsset 生成 RenderPipeline,RenderPipeline 用来控制管线的渲染流程
  • RenderPipelineAsset 包含 ScriptableRendererData 列表
  • ScriptableRendererData 生成 ScriptableRenderer , ScriptableRenderer 用来控制渲染指令和状态

UniversalAdditionalCameraData

RednerPipeline 咋调用的 ScriptableRenderer 呢
在上面的代码分析中,我们并没有找到直接的调用关系

  • 引擎在切换到 URP 管线后,我们会注意到,相机上会新增一个 UniversalAdditionalCameraData 组件,这个组件内部的一个共有属性 scriptableRenderer 它通过相机上设置的 renderer 的索引,使用 UniversalRenderPipeline.asset.GetRenderer(defaultIndex); 来获取当前相机的 ScriptableRenderer 。

  • 在 UniversalRenderPipeline 的 InitializeAdditionalCameraData 方法执行时,将 ScriptableRenderer 包装进了 CameraData,所以在 pipeline 的执行过程中,大部分情况下可以通过 CameraData 来获取 ScriptableRenderer ,对应的属性名为 renderer
    cameraData.renderer = asset.scriptableRenderer;

  • 所以之前也说 ScriptableRenderer 是针对与相机渲染的

ScriptableRenderPass

  1. 主要用于实际的渲染操作,大部分存在于 RenderFeature 和 ScriptableRenderer 中。
  2. ScriptableRenderer 中包含了 m_ActiveRenderPassQueue 队列,Feature 内的 pass 也通过遍历的形式被添加进 m_ActiveRenderPassQueue
  3. 渲染操作遍历 m_ActiveRenderPassQueue 进行渲染状态的操作与渲染
  4. 所以 ScriptableRendererFeature 可以实现类似旧管线中的多 pass 渲染

ScriptableRendererFeature

  1. ScriptableRendererData 内包含 ScriptableRendererFeature 列表
  2. 在生成 ScriptableRenderer 的时候会将 ScriptableRendererData 内的 ScriptableRendererFeature 传递到 ScriptableRenderer 的 m_RendererFeatures 内。
  3. 在 ScriptableRenderer 抽象类内,需要调用的地方以遍历的形式进行调用,例如 AddRenderPasses、OnPreCullRenderPasses、Dispose 等
  4. ScriptableRendererFeature 的派生类内基本都会包含一个 renderObjectsPass,通过前几步的调用关系,便可以将当前的feature的pass 传递到 Renderer 的渲染过程中。
  5. ScriptableRendererFeature 内可以包含各种设置属性,用来设置其内部将要参与渲染的 ScriptableRenderPass

结束

基本结构和相互关系,大致如此,主要的就是先了解四个基类的关系,然后是其派生类


四个大类

然后就是四大类中主要用到的几个类


相关类

至于具体的派生类,有时间慢慢了解即可
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,527评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,687评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,640评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,957评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,682评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,011评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,009评论 3 449
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,183评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,714评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,435评论 3 359
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,665评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,148评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,838评论 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,251评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,588评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,379评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,627评论 2 380

推荐阅读更多精彩内容