目录
SRP/URP/HDRP之间的关系
SRP是什么?
URP是什么?
HDRP是什么?
2. 为什么诞生SRP?
3. URP 和 内置渲染管线 性能对比
1. 首先来说说光照处理部分
2. 接下来看看SRP Batcher(重点)
SRP Batcher 是什么?
SRP Batcher是怎么优化的?
内置渲染管线和URP的CPU原理图对比:
SRP Batcher 兼容性
3. URP的增加功能
1.渲染管线扩展/自定义渲染器(待补充)
1. 第一人称对象
2. 卡通描边
3. 对象遮挡
4. 模糊清晰混合
2. 摄像机堆叠(待更新)
URP源码解析(待更新)
参考文章:
额外内容
下图是各个管线的关系图
根据上图所示,URP是Unity可编程渲染管线(SRP)的一种,所以了解URP之前需要先了解SRP是什么。(在文章最下面,额外内容里附了张渲染管线流程图)
SRP全称为Scriptable Render Pipeline(可编程渲染管线/脚本化渲染管线),是Unity提供的新渲染系统,可以在Unity通过C#脚本调用一系列API配置和执行渲染命令的方式来实现渲染流程,SRP将这些命令传递给Unity底层图形体系结构,然后再将指令发送给图形API。
说白了就是我们可以用SRP的API来创建自定义的渲染管线,可用来调整渲染流程或修改或增加功能。
它主要把渲染管线拆分成二层:
一层是比较底层的渲染API层,像OpenGL,D3D等相关的都封装起来。
另一层是渲染管线上层,上层代码使用C#来编写。在C#这层不需要关注底层在不同平台上渲染API的差别,也不需要关注具体如何做一个Draw Call
它的全称为Universal Render Pipeline(通用渲染管线), 它是Unity官方基于SRP提供的模板,它的前身是LWRP(Lightweight RP即轻量级渲染管线), 在2019.3开始改名为URP,它涵盖了范围广泛的不同平台,是针对跨平台开发而构建的,性能比内置管线要好,另外可以进行自定义,实现不同风格的渲染,通用渲染管线未来将成为在Unity中进行渲染的基础 。
平台范围:可以在Unity当前支持的任何平台上使用
它的全称为High Definition Render Pipeline(高清晰度渲染管线),它也是Unity官方基于SRP提供的模板,它更多是针对高端设备,如游戏主机和高端台式机,它更关注于真实感图形和渲染,该管线仅于以下平台兼容:
在此文章对HDRP不过多描述。
内置渲染管线的缺陷
目的:
在看URP 和 内置渲染管线 性能对比之前最好先了解DrawCall,Batches,SetPassCalls分别是什么值。
DrawCall,Batches,SetPass calls文章:https://blog.csdn.net/qq_30259857/article/details/110062397
主要提速的有两个方面
1. 光照处理(包括阴影)
2. SRP Bacher (SRP 批处理)(重点)
其他可以看看官网图,下面是官网的对比表链接和图。
https://docs.unity3d.com/Packages/[email protected]/manual/universalrp-builtin-feature-comparison.html
如上图所示,老的渲染管线使用Multi-Pass的Forward Rendering,就是多Pass的正向渲染。最大的问题是如果要在场景里要加很多动态光的话,每一个动态光都有可能会增加一个Pass,这个动态光所影响的物体要多画一遍。
这就导致如果游戏里想要有多个动态光的话,可能这个场景会被画很多遍,性能会很差。它带来的问题是所有的游戏几乎都不会用多个动态光,因为实在太费性能了。
在过去制作移动的游戏的过程中,大家的标准做法都是烘焙Lightmap。
现在URP就解决了这个问题。实现了一个单PASS的正向渲染。可以支持多盏动态光,但是全部动态灯光都会放在一个Pass里渲染,这样带来的问题是要限制灯光的数量,因为每次Draw Call去画的时候,传给GPU的参数是有限的。
如果灯光数量特别多,参数太多,那就会无法在一次Draw Call里完成很多个灯光。所以我们有一些限制,在轻量级渲染管线LWRP里,目前是支持1盏平行光,每个对象可能只能接受4个动态光。每个摄像机也有一些限制,这是为了我们可以把所有的计算放在一个Pass里面。
接下来看看内置渲染管线和URP各种情况下的光照处理实验对比
以下是分别在四种情况下对比所得出的结论
URP光照处理最终结论:
1. 性能上阴影处理方面比内置渲染管线好很多。
2. URP平行光基础上添加动态光没有带来额外的Batches和SetPass calls性能开销。
下面有图有真相
1. 无光源情况下的对比
内置渲染管线:
URP:
结论:Batches,SetPass Calls 基本是一样的,没区别。
2. 一个平行光,无阴影下的对比
内置渲染管线:
URP:
结论:Batches,SetPass Calls 基本是一样的,没区别。
3. 一个平行光,一个点光源,无阴影下的对比
内置渲染管线:
URP:
结论:可以发现内置渲染管线的Batches将近增加了一倍,而URP的Batches和SetPass calls跟一个平行光时一样,一点都没有增加。
4. 一个平行光,有阴影下的对比
内置渲染管线:
URP:
结论:内置渲染管线处理阴影面数增加了45k,Batches增加了759,URP面数增加了11K,Batches增加了188。处理阴影性能上URP好很多。
官网解释:SRP Batcher 是一个底层渲染循环,可通过许多使用同一着色器变体的材质来加快场景中的 CPU 渲染速度。
个人解释:就算是不同的材质球,只要是用一个着色器变体的物体都可以批处理到一块。(在2019.3.4版本 渲染顺序也会打断批处理,这点上官网没有说明,也许后续版本已经处理了),它的主要目的是减少渲染状态设置的开销,还有就是把物体属性用专用代码快速更新。
上面解释都提到了变体,那么变体怎么理解呢?
multi_compile和shader_feature这两个关键字就是实现着色器变体的指令。
下面是自定义的multi_compile 关键字。
上图中定义了两个multi_complie,white和black两个关键字,此时Unity会生成两个变体,一个是走white逻辑的变体,另外一个是走black逻辑的变体。然后在脚本中通过Material.EnableKeyWord和Shader.EnableKeyword来开启某功能,通过Material.DisableKeyword和Shader.DisableKeyword来关闭某功能。为什么这么做呢?主要是为了避免分支语句(if )导致的性能下降。
。
shader_feature关键字跟multi_compile不一样的是未被选择的变体会在打包的时候被舍弃(multi_complie不会),shader_feature主要是在材质球选项上控制开关,比如这个选项。
URP的Lit Shader里有很多实现变体指令,所以这些Shader生成的变体也有很多。如图:
主要参考来自以下文章:
多版本shader的编写-multi_compile和shader_feature:https://zhuanlan.zhihu.com/p/190233160?utm_source=wechat_session
https://docs.unity.cn/cn/2019.3/Manual/SRPBatcher.html
https://connect.unity.com/p/srp-batcher-jia-su-xuan-ran
过去,Unity 中,可以在一帧内的任何时间修改任何材质的属性。但是,这种做法有一些缺点。当Draw Calls使用新材质时,需要进行很多处理。场景内的材质越多,设置GPU数据所需的CPU资源就越多。解决此问题的传统方法是减少 DrawCall 的数量以优化 CPU 渲染成本,因为 Unity 在发出 DrawCall 之前必须进行很多设置。实际的 CPU 成本来自该设置,而不是来自 GPU DrawCall 本身(DrawCall 只是 Unity 需要推送到 GPU 命令缓冲区的少量字节)。
这是官网说的提速效果:
Unity 2018引入了可编程渲染管线SRP,其中包含新的底层渲染循环SRP Batcher批处理器,它可以大幅提高CPU在渲染时的处理速度,根据场景内容的不同,提升效果为原来的1.2~4倍不等。
SRP Batcher使材质数据持久保留在 GPU 内存中。如果材质内容不变,SRP Batcher 不需要设置缓冲区并将缓冲区上传到 GPU。还有 SRP Batcher 会使用专用的代码路径来快速更新大型 GPU 缓冲区中的 Unity 引擎属性,如下图。
上面的功能能解决什么问题呢?也就是CPU不需要再设置渲染状态和一大堆渲染数据设置,只需要物体跟缓冲区的数据绑定就可以了。
SRP Batcher 正是通过批处理一系列
Bind
和Draw
GPU 命令来减少 DrawCall 之间的 GPU 设置。
内置渲染管线:(红框部分就是SRP Batcher优化的性能部分)
URP:
在把材质数据和物体数据上传好后的流程图:(GPU没有详细画,主要看CPU)
上面流程图中绑定的意思是大家都知道Shader里有很多变量,如纹理贴图,Property定义的变量以及内置变量等,个人理解是把缓冲区里存的渲染数据设置给了Shader变量。
再看看OpenGL API调用情况
URP
可以发现内置渲染管线有 glUniform4fv API,这是设置一大堆着色器数据的函数,也是耗时的部分,而在URP取而代之的是Bind接口,省去了设置着色器数据的开销。
根据上面内容我们可以知道SRP Batcher并没有减少DrawCall,而是优化了DrawCall之前的设置开销。
SRP Batch值我们可以在Frame Debug窗口可以看得到。
Statistics窗口上的SetPass calls值,其实就是SRP Batch数量 加上 未能批处理的DrawCall数量。
在下图中可以看到SRP Batch批处理了 189个 DrawCalls.
为了使 SRP Batcher 代码路径能够渲染对象:
为了使着色器与 SRP Batcher 兼容:
unity_ObjectToWorld
或 unity_SHAr
。UnityPerMaterial
的 CBUFFER 中声明所有材质属性。Property定义的属性也是属于PerMaterial.
可以在 Inspector 面板中查看着色器的兼容性状态。
可以在 Inspector 面板中检查特定着色器的兼容性。
在看看时间对比
内置渲染管线(未开启任何合批)
内置渲染管线(开启静态批处理)
URP未开启SRP Batcfh
URP环境下(开启SRP Batcher)
主要有以下功能
1. 渲染管线扩展/自定义渲染器
2. 摄像机堆叠 (待更新)
3. Shader Graphic(Shader图形编程)(待更新)
官网案例Github地址:https://github.com/Unity-Technologies/UniversalRenderingExamples
以下是官网案例效果(最后一个是自己实现)
此Demo主要演示的是摄像机堆叠功能,摄像机堆叠功能下面会单独专门讲。
展示一种创建卡通样式轮廓效果的设置,示例中有两种方法,一种是后处理方法,另一种是船体网格方法。一个示例使用自定义RendererFeature,并且都使用自定义着色器
此Demo有两个渲染器
我们来看看第二个渲染器
主要的卡通描边效果就是在上图中的 Sobel Outlines (Blit)实现,
当一个对象被另一个对象遮挡时,可以创建效果。
如下图所示,一个角色被建筑挡住时用指定的材质效果来显示角色被遮挡的部分。
以下是自己实现的扩展功能
此效果是在模糊的基础上把某层的物体清晰显示的效果。
详解属性:
渲染器列表
HDR(High Dynamic Range Imaging):高动态范围成像,
Anti Aliasing(MSAA):抗锯齿
Unity轻量级渲染管线LWRP源码及案例解析 - 上:https://connect.unity.com/p/unityqing-liang-ji-xuan-ran-guan-xian-lwrpyuan-ma-ji-an-li-jie-xi-shang
Unity轻量级渲染管线LWRP源码及案例解析 - 下:https://connect.unity.com/p/unityqing-liang-ji-xuan-ran-guan-xian-lwrpyuan-ma-ji-an-li-jie-xi-xia
SRP Batcher:加速渲染:https://connect.unity.com/p/srp-batcher-jia-su-xuan-ran
URP扩展案例 Github地址: https://github.com/Unity-Technologies/UniversalRenderingExamples
Unite Now - (中文字幕)使用URP提升游戏画面效果:https://www.bilibili.com/video/BV1fK4y1a78s
关于静态批处理/动态批处理/GPU Instancing /SRP Batcher的详细剖析:https://zhuanlan.zhihu.com/p/165574008
关于静态批处理/动态批处理/GPU Instancing /SRP Batcher的详细剖析:https://zhuanlan.zhihu.com/p/98642798
Batch, Draw Call, Setpass Call:https://zhuanlan.zhihu.com/p/76562300
Unity3D优化技巧系列(一):Draw Call优化:https://gameinstitute.qq.com/community/detail/113025
Unity ConstantBuffer的一些解析和注意:https://zhuanlan.zhihu.com/p/137455866
渲染流水线图: