Unity中,有多种不同的渲染管线可以选择。简单的说,渲染管线负责从场景中选择物体并渲染到屏幕上,包括三个基本步骤:
不同的渲染管线有不同的功能和性能特性,分别适应于不同的游戏,应用和平台。
将项目从一个渲染管线切换到另一个很困难,因为不同渲染管线使用不同的shader进行渲染,而且拥有不同的特性。
Unity提供了下面的渲染管线:
- Built-in Render Pipeline 默认渲染管线,是一个通用渲染管线,相对固定,仅可以有限度的进行控制。
- Universal Render Pipeline (URP) 是可编程渲染管线,可以方便地进行自定义渲染,针对不同的平台进行优化。
- High Definition Render Pipeline (HDRP) 也是一种可编程渲染管线,可以在高端平台上创建技术领先的,高逼真度的图形渲染。
- Scriptable Render Pipeline (SRP) 可以基于可编程渲染管线API,创建自定义的渲染管线。你可以从头开始创建一个全新的渲染管线,也可以通过修改URP和HDRP来适应自己的项目。
默认渲染管线相对于可编程管线,自定义扩展性不高,仅可以通过选择不同的 rendering paths ,并通过command buffers 和callbacks 对其功能进行扩展。
默认管线定义了不同的渲染通路,一个渲染通路是一系列光照和阴影处理。不同的渲染通路的功能和性质特性都不一样,要根据项目特性和目标平台选择合适的渲染通路。
可以在ProjectSettings>Graphics>Tier Settings种设置不同渲染质量的渲染通路,该设置也可以在摄像机中被覆盖掉。
如果设置的渲染通路,在硬件设备上不支持,Unity会自动选择低一级的渲染通路。例如,对于不支持延迟着色的硬件,会使用前向渲染。
前向渲染,是默认管线中的默认通路。
在前向渲染中,实时光照效率非常低。可以通过指定每个像素可以接受的光源数量来调整负载。对场景中其它的光源则会使用逐顶点,或逐对象的高效率,低效果的方式。
如果你的场景中没有很多的实时光源,或者光照效果没有那么重要,那么选择前向渲染。
延迟着色可以实现更好的光照和阴影渲染效果。
延迟着色需要GPU的支持,并且有一些限制。不支持半透明物体(这类物体会使用前向渲染),正交投影(这类摄像机使用前向渲染),以及硬件抗锯齿(尽管可以通过后效来实现类似效果)。同时,延迟着色对culling mask不完全支持,而且对 Renderer.receiveShadows 标识按照true(设置无效)来处理。
如果你的场景有很多的实时光源,需要很高的渲染真实度,并且目标平台硬件支持,则使用延迟着色。
Legacy Deferred(light prepass)与Deferred Shading 类似,只是使用了不同的技术,不支持新的PBR standard shader。
Legacy Vertex Lit 实现低级效果并且不支持实时阴影,是前向渲染的一部分。基于顶点的光照。
Deferred | Forward | Legacy Deferred | Vertex Lit | |
---|---|---|---|---|
Features特性 | ||||
逐像素光照(normal maps, light cookies) | Yes | Yes | Yes | No |
实时阴影 | Yes | 会有警告?With caveats | Yes | No |
反射探针 | Yes | Yes | No | No |
深度/法线缓冲区 | Yes | 需要额外的渲染 | No | No |
软边粒子 | Yes | |||
半透明对象 | No | Yes | No | Yes |
抗锯齿 | No | Yes | No | Yes |
光照裁剪掩码 | 部分支持 | Yes | 部分支持 | |
光照渲染精度 | 逐像素 | 部分逐像素 | 逐像素 | 逐顶点 |
性能 | ||||
逐像素光照消耗 | 由照亮的像素数决定 | 照亮的像素数*照亮的对象数 | 由照亮的像素数决定 | 无 |
对象的平均渲染次数 | 1 | 每像素受光照数 | 2 | 1 |
相对简单场景的消耗 | 高 | 无 | 中等 | 无 |
平台支持 | ||||
PC(Windows/Mac) | Shader Model 3.0+ & MRT(MultiRenderTarget) | All | Shader Model 3.0+ | All |
Mobile (iOS/Android) | OpenGL ES 3.0 & MRT, Metal (on devices with A8 or later SoC) | All | OpenGL ES 2.0 | All |
Consoles | XB1, PS4 | All | XB1, PS4, 360 | All |
前向渲染根据照亮对象的光源的数量,对对象进行一次或多次渲染。光源本身根据其强度等设置,会被进行不同的处理。
前向渲染中,照亮物体,并且一定数量的亮度最高的光源,按照逐像素光照来进行渲染。最多由4个光源按照顶点光照进行渲染。其它的光源,按照球函数(一种特定算法,SH:Spherical Harmonics )计算光照,速度很快但仅仅是一种近似模拟。光源是否被逐像素处理,取决于:
- 光源的 RenderMode 被设置成 Not Important 的,会被处理成顶点光或球函数模拟光。
- 最亮的方向光,一定是逐像素光照。
- Render Mode = Important 的光源是逐像素的。
- 如果最终对象的逐像素光源数量小于QualitySetting.PixelLightCount设置的值,则会选择更多的光源为逐像素光照,来降低亮度。
对每个对象的渲染,会执行下面的步骤:
- Base Pass 来渲染一个逐像素的方向光和所有的逐顶点/SH的光照。
- 对每个逐像素的光照,额外进行一次渲染。
例如,对象被一些光源照亮,如下图的圆圈代表的对象,被A-H的8个光源照亮。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BVNLRbxQ-1581473824688)(https://docs.unity3d.com/uploads/Main/ForwardLightsExample.png)]
这里假定所有的光源,拥有想通过的设置,颜色,强度,默认的RenderMode,因此它们对该对象的影响按照A-H的顺序。最亮的光源按照逐像素渲染(A-D,假定设置为每个对象4个逐像素光源),最多4个光源为逐顶点光照(D-G),剩下的用SH渲染(G-H):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ASE271PA-1581473824689)(https://docs.unity3d.com/uploads/Main/ForwardLightsClassify.png)]
注意到光照组之间是重叠的,例如最后一个逐像素的光源同时被混合进了逐顶点光源中,以避免光源或对象的移动导致光照的跳变。
Base Pass 为每个对象渲染一个逐像素的方向光,所有的逐顶点光源和SH光源。该过程同时会在Shader中处理光照贴图(lightmaps),环境光,自发光。该过程中处理的方向光可以渲染阴影。注意,LightMaps对象不会再渲染SH光照。
注意,如果Shader中设置了 “Only Directional Light” pass 标识,则该Pass仅渲染主方向光,环境/光照探针和光照贴图(SH和逐顶点光照将不在该Pass中渲染)。
Additional Pass 负责渲染影响到对象的一盏光源的逐像素光照。这些pass不会渲染阴影(也就是说前向渲染,仅支持一个带阴影的方向光),除非添加了multi_compile_fwdadd_fullshadows 声明。
Spherical Harmonics光照拥有非常快的效率,CPU占用很小,GPU负载也非常低(base pass总是会计算SH;同时由于其工作原理,SH光源数量的增加,几乎不会增加性能损失)。(SH没有深入研究,所以先按照字面意思解释这部分吧)
SH光照的缺点:
- 它们是逐顶点计算的,所以不支持light cookies(简单理解为镂空的灯笼效果,应一张贴图部分遮挡光源)和lightmaps。
- SH光照将以一个比较低的频率执行。SH光照不会产生强烈的光照过度,它们只会影响漫反射(diffuse)光照(对高光来说频率太低了)。
- SH光照算法,在光源离表面很近时,渲染效果可能不太正常。
(译者)以前自研引擎也曾经实现过一种效率很高,但是效果不太好的点光源:
- 在CPU中计算光照位置,颜色,强度,衰减。这些可以根据参数实时变化,模拟摇曳的灯光等效果。
- 渲染一个物体时,将照亮该物体的该类光源的参数传给shader
- 在vertex shader中,按照顶尖距离这些光源的距离,和光源自身的参数,计算该顶点受这些光源的影响,并混合,叠加到顶点颜色中(或者其它的VertexOutput的字段)
- 在pixel shader中,处理diffuse时混合上面计算的颜色。
感觉跟SH有点像,基于球形的衰减照亮顶点。
延迟着色的技术原理,可以参考Wikipedia: deferred shading
使用延迟着色时,每个对象能够接收的点光源数量没有限制,所有的光源都将按照逐像素渲染,意味着都能跟光照贴图正确地配合,以及支持cookies和阴影。
延迟着色地优势是负载跟照亮一个像素的光源数量是成比例的。该负载只跟光源在场景中的体积(照亮范围)有关,而跟它照亮的对象数量无关。因此提升效率的方法之一,就是让光源的照亮范围小一些。延迟着色具有一致性,可以按照我们预想的进行渲染。每个光源都是逐像素的,因此再比较大的三角形上形成颜色块(基于顶点的光照因为只计算了顶点颜色,并再像素阶段进行插值而导致一些色阶)。
延迟着色的缺点是不支持抗锯齿和半透明物体(这些物体将在前向渲染中处理)。同时不支持对特定对象是否接受阴影的设置,并且culling mask也仅是有限度的支持:最多支持4个culling masks,也就是说culling layer mask 至少要包含所有layers减去4个layers,32-4=28个layers是设置的。
需要显卡支持Multi Render Target,Shader Mode 3.0+,Depth render texture。2006年以后的PC显卡,从GeForce8XXX以及RadeonX2400,IntelG45开始,都支持。
在移动端,需要OpenGL ES 3.0。
注意:延迟着色不支持正交投影,如果摄像机是用正交模式渲染,则会对其启用前向渲染通路。
延迟着色中光照负载,只跟照亮像素的光源数量有关,而跟场景复杂度无关。所以将点光源或聚光灯光源的范围降低可以降低负载。如果光源整体或部分被场景对象遮挡,则效率更高(照亮的范围更小)。
如果光源需要渲染阴影,则极大的增加负载。对于每个要投射阴影的对象,每个光源都要进行额外的渲染。同时,渲染阴影的光源,在shader代码效率上也远低于不渲染阴影的shader。
如果对象不支持延迟着色(比如半透明),则它们将在延迟渲染过程完成后,在前向渲染通路中完成。
G-Buffer(Geometry buffer)对RT0-RT4(render target)的使用如下,数据被渲染到每个render target 的不同通道中:
- RT0, ARGB32 : Diffuse color 漫反射颜色 (RGB), occlusion(A).
- RT1, ARGB32 : Specular color 高光颜色 (RGB), roughness 粗糙度(A).
- RT2, ARGB2101010 : World space normal 世界空间法线 (RGB), unused(A).
- RT3, ARGB2101010(non-HDR) 或 ARGBHalf(HDR) : Emission + lighting + lightmaps + reflection probes
- Depth + Stencil buffer 深度+模板缓冲区
因此,默认的人G-Buffer是每个像素160位(non-HDR)或192位(HDR)。
如果使用了 Shadowmask 或 Distance Shadowmask 进行混合渲染,则会用到RT4:
- RT4, ARGB32 : Light occlusion values(RGBA) 光照遮挡值.
这时,G-Buffer则是每个像素192位(non-HDR)或224位(HDR)。
如果硬件不支持5个并行的render target,则使用了shadow masks 的对象,将会由前向渲染管线来渲染。当摄像机未开启HDR时,Emission+lighting buffer (RT3)使用对数编码方式,来提供比普通的ARGB32贴图格式更大的动态范围。
注意,当摄像机使用HDR渲染时,并不会为Emission+lighting buffer (RT3)单独创建render target,而是将RT3创建为ARGBHalf,每个通道是16位,这样用同一个RT存储。
(Note that when the Camera is using HDR rendering, there’s no separate rendertarget being created for Emission+lighting buffer (RT3); instead the rendertarget that the Camera renders into (that is, the one that is passed to the image effects) is used as RT3.)
G-Buffer位每个对象渲染一次,将包括漫反射和高光颜色,表面平滑度,世界空间法线,以及emission+ambient+reflections+lightmaps渲染到G-Buffer中。G-Buffer被创建成一个全局的属性,这样后面的shader可以访问(命名为CameraGBufferTexture0 … CameraGBufferTexture3)。
lighting pass 基于G-Buffer和深度在屏幕空间计算光照,因此负载跟场景复杂度无关,光照被累加仅emission buffer。
与摄像机的近裁剪面不相交的点光源和聚光灯光源(完全在摄像机近裁剪面的前面),利用场景的Z-buffer测试,进行3D渲染。这样可以将被遮挡的光源过滤掉,提升性能,即对光源进行深度测试,失败了就不进行光照运算了。而对于与近平面相交的方向光,点光/聚光等光源,则渲染成四方形面片。
如果开启了阴影,则也在该阶段处理。但是这需要对投射阴影的对象额外渲染,并在该阶段使用更加复杂的shader。
在该渲染管线中,仅可以使用Standard光照模型。如果需要不同的光照模型,则修改lighting pass用的shader,通过将 Built-in shaders 里的Internal-DeferredShading.shader的文件,放到Assets/Resources目录下,并进行修改。然后,在ProjectSettings>Graphics,将Deferred下拉列表,改为Custom Shader,并指定我们改好的shader。
关于改着色技术理论,参考 this article 。
老版本的延迟着色,是为了兼容Unity5.0版本,主要是因为该版本不支持一些渲染特性(比如standard shader,reflection probes)。新项目不建议再使用该版本管线。
注意:延迟着色不支持正交投影,如果摄像机是正交视图的,则会使用前向通路渲染。
使用延迟着色时,每个对象能够接收的点光源数量没有限制,所有的光源都将按照逐像素渲染,意味着都能跟光照贴图正确地配合,以及支持cookies和阴影。
延迟着色地优势是负载跟照亮一个像素的光源数量是成比例的。该负载只跟光源在场景中的体积(照亮范围)有关,而跟它照亮的对象数量无关。因此提升效率的方法之一,就是让光源的照亮范围小一些。延迟着色具有一致性,可以按照我们预想的进行渲染。每个光源都是逐像素的,因此再比较大的三角形上形成颜色块(基于顶点的光照因为只计算了顶点颜色,并再像素阶段进行插值而导致一些色阶)。
延迟着色的缺点是不支持抗锯齿和半透明物体(这些物体将在前向渲染中处理)。同时不支持对特定对象是否接受阴影的设置,并且culling mask也仅是有限度的支持:最多支持4个culling masks,也就是说culling layer mask 至少要包含所有layers减去4个layers,32-4=28个layers是设置的。
需要显卡支持Shade Mode 3.0+,Depth render texture,双面stencil buffers。2004年以后的PC显卡,GeForce FX,Radeon X1300,以及Intel 965/GMA X3100 以后的显卡,都支持。
延迟着色中光照负载,只跟照亮像素的光源数量有关,而跟场景复杂度无关。所以将点光源或聚光灯光源的范围降低可以降低负载。如果光源整体或部分被场景对象遮挡,则效率更高(照亮的范围更小)。
如果光源需要渲染阴影,则极大的增加负载。对于每个要投射阴影的对象,每个光源都要进行额外的渲染。同时,渲染阴影的光源,在shader代码效率上也远低于不渲染阴影的shader。
base pass 对每个对象渲染一次,摄像机空间的法线和高光强度,被渲染到一张ARGB32的Render Texture
上(法线存储在RBG通道,高管强度存储在A通道)。如果平台或硬件支持将Z-buffer当贴图进行访问,则可以不用渲染深度,否则需要一个额外的渲染通路用shader replacement来渲染深度。
Base Pass主要是根据场景填充Z-buffer,以及存储像素的法线和高光强度的Render Texture。
lighting pass 基于深度,法线,高光强度来计算光照。因为计算是在屏幕空间的,所以效率跟场景复杂度没有关系。光照图是一张ARGB32(32位)的render texture,RGB通道用来存储漫反射颜色,A通道存储单色的高光强度。光照计算的值经过对数编码,以达到更大的动态范围。如果摄像机打开了HDR,则缓冲区改用ARGBHalf(64位),也不会执行对数编码了。
对于点光/聚光灯光源,与摄像机近平面不相交(完全在视锥体内)的,渲染成3D形状(考虑球形),同时进行深度测试,如果像素深度小于光源深度,则受该光源影响。对于与近平面相交的光源(可能光源的位置在摄像机近平面的后面),同样也会渲染3D形状,但是深度测试相反,大于光源深度的像素,受该光源影响。这样部分或全部被遮挡的光源,渲染效率就特别高了。如果一个光源同事与近平面和远平面相交,前面提到的优化就不会被执行了,不会执行深度测试,光照会被渲染成一个面片。
方向光不会执行上述优化,而是全屏计算。
如果光源开启了阴影,则也在该阶段处理。但是这需要对投射阴影的对象额外渲染,并在该阶段使用更加复杂的shader。
该通路下,只能使用Blinn-Phong光照模型,如果需要不同的光照模型,则修改lighting pass用的shader,通过将 Built-in shaders 里的Internal-PrePassLighting.shader的文件,放到Assets/Resources目录下,并进行修改。然后,在ProjectSettings>Graphics,将Lagacy Deferred下拉列表,改为Custom Shader,并指定我们改好的shader。
Final Pass 生成最终渲染图像,在这一步中,所有的对象需要再渲染一边,并利用光照图获取光照信息,合并贴图颜色,及其它自发光光照。LightMaps也是再这一步中进行应用。距离摄像机近的,渲染实时光照,并叠加烘焙的方向光光照。距离摄像机远的,过渡到完全的烘焙光照。
该通路对没个对象渲染一次,并在顶点阶段,对每个顶点执行所有的光源的光照运算。
该方式速度最快,同时绝大多数的显卡都支持。
因为所有的光照都是在顶点中完成的,该通路不支持很多逐像素渲染的特性,比如:阴影,法线贴图,light cookies,高细节的镜面高光都不支持。
Win/Mac/Linux | iOS/Android | Consoles | |
---|---|---|---|
Deferred lighting | SM3.0, GPU support | - | Yes |
Forward rendering | Yes | Yes | Yes |
Vertex Lit rendering | Yes | Yes | - |
Realtime Shadows | GPU support | GPU support | Yes |
Image Effects | Yes | Yes | Yes |
Programmable Shaders | Yes | Yes | Yes |
Fixed Function Shaders | Yes | Yes | - |
实时阴影在大多数的PC,手机,主机平台上都支持。在Windows系统上(Direct3D API),显卡都要支持阴影映射;多数2003年后的独立显卡,以及2007年以后的集成显卡都支持。技术上,支持Direct3D9的显卡,都要支持D16/D24X8 or DF16/DF24 贴图格式。在OpenGL上,还要支持GL_ARB_depth_texture。
移动端阴影(iOS/Android)需要OpenGL ES 2.0 以及 GL_OES_depth_texture格式扩展,或者支持OpenGL ES 3.0。因为贴图扩展格式在Tegra3,4上不支持,所以在这些硬件上,也不支持阴影。
Post-processing effects 后处理效果,需要render-to-texture功能(向一种特殊的贴图上渲染),目前显卡都是支持的。
可以编写可编程shader或固定功能shader(这里指的是Unity shader,固定管线没有shader)。在Shader Mode2.0(PC)以后和OpenGL ES 2.0(移动端)以后,都支持可编程shader。如果需要更多的功能,可以选择更高的shader models。固定功能渲染除了主机,所有平台都支持。
Universal Render Pipeline (URP),通用渲染管线是预建的一种可编程渲染管线,URP提供了一种易于美术使用的工作流,快速容易地创建优化地多平台地图形,从移动端,到高端主机,到PC。
更详细地URP,参考URP package documentation microsite。
HDRP让你可以位高端主机平台创建技术领先地,高逼真度地图形。
用HDRP创建AAA级地游戏,汽车演示,建筑应用,以及其它需要高逼真度地图形。HDRP使用基于物理地渲染和材质(PBR),支持前向和延迟着色。HDRP使用了compute shader 技术因此需要硬件支持。
参考:HDRP package documentation microsite
Scriptable Render Pipline允许在C#脚本中控制渲染,进行各种高级地定制。
Unity提供了2中于定义地SRC,分别是URP和HDRP,这两种都提供了大量定制选项。如果需要对渲染进行更多地控制,可以从头开始写一个全新的SRP。
可以从头开始创建全新的SRP,也可同通过修改URP和HDRP来满足需求。
更多信息参考SRP Core package documentation microsite.
SRP Batcher,是针对场景里,使用同一个shader的变体的许多materials的对象进行处理,以提升CPU渲染效率的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lY5ZLGFO-1581473824690)(https://docs.unity3d.com/uploads/Main/SRPBatcher.png)]
只有使用SRP的项目,才能开启SRP Batcher,包括:URP,HDRP,自定义SRP。
位URP,HDRP开启Batcher:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dPbMy3G5-1581473824690)(https://docs.unity3d.com/uploads/Main/SRPBatcher_Asset.png)]
也可以在代码中修改:
GraphicsSettings.useScriptableRenderPiplineBatching = true;
如果是XR项目:
XRSettings.stereoRenderingMode = XRSettings.StereoRenderingMode.SinglePassInstanced;
Platform | Minimum Unity version required |
---|---|
Windows DirectX 11 | 2018.2 |
PlayStation 4 | 2018.2 |
Vulkan | 2018.3 |
OSX Metal | 2018.3 |
iOS Metal | 2018.3 |
Nintendo Switch | 2018.3 |
Xbox One DirectX 11 | 2019.2 |
OpenGL 4.2 and higher | 2019.1 |
OpenGL ES 3.1 and higher | 2019.1 |
Xbox One DirectX 12 | 2019.1 |
Windows DirectX 12 | 2019.1 |
在Unity中,可以在任何时候修改任何材质的属性,但这回导致效率损失。例如,DrawCall在使用一个新的材质时,需要做做很多初始化工作。所以场景中的材质越多,CPU需要花费更多的时间位GPU准备数据。传统的方法时通多降低Draw Call调用次数,来降低这方面的CPU消耗。因为真正导致效率问题的,是位调用DrawCall做的准备工作,而DrawCall本身相对较少,主要是向GPU指令缓存提交数据。
SRP Batcher通过将一系列的Bind和Draw的指令合并到一起,降低设置GPU产生的负载,如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n6hhQ3QZ-1581473824691)(https://docs.unity3d.com/uploads/Main/SROShaderPass.png)]
如上图,左边是标准的一次DrawCall,需要做的准备工作,远高于右边的一次DrawCall。
(译者:在自研引擎时,对于GPU的指令也是有缓存的,通过在内存中缓存,每次设置GPU状态时,判断是否改变,如果没有改变,就不设置了,比如Driect3D.SetRenderState(…)。这种缓存是分层的,底层是GPU API级别,如SetRenderState,SetTexture,SetShader,等。上层是材质级别,材质级别需要对渲染对象进行材质排序。细节实际上很复杂,这里只是提一下概念原理。)
为了达到最大的渲染效率,合批越大越好。位了能将更多的渲染合到一个批次,要尽量使用相同的shader建立不同的material,减少shader变体的数量。
在内部的渲染循环中,当Unity发现一个新的材质,CPU会收集所有的需要设置到GPU的属性,调用GPU API 在GPU现存中建立常量缓冲区。GPU Buffer的数量,取决于Shader如何声明自己的CBUFFERs。
位了提升使用了较少的shader变体创建了很多材质使用的场景,SRP在CPU对GPU数据状态进行了缓存。
SRP Batcher 是一个底层的渲染循环,作用是减少对GPU 显存的修改次数。如果材质没有发生改变,则不会设置和更行GPU现存内容。SRP建立了专门的代码流程,来快速的在一个大的GPU Buffer中更新引擎各种属性,如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDzUqOTb-1581473824692)(https://docs.unity3d.com/uploads/Main/SRP_Batcher_loop.png)]
这里,CPU只处理Unity引擎定义的属性,上图中的Per Object large buffer。所有的材质,都在GPU中有固定的CBUFFER,随时可以使用。这对渲染提速在于:所有的材质内容都保留在了显存中,有专门的逻辑来为每个对象属性管理per-object GPU CBUFFER。
(译者:从该篇幅可以看出,主要还是一种缓存机制,但是能将缓存在内存和显存中进行更加有效的映射,同时所有的材质都在显存中缓存了,很多GPU API 调用都可以省掉了。具体原理,还是只能理解个大概)
SRP渲染的Object需要:
Shader 兼容性:
unity_ObjectToWorld
, or unity_SHAr
。可以在Shader Inspector 面板中查看兼容性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JaQJE6v4-1581473824692)(https://docs.unity3d.com/uploads/Main/SRP_batcher_shader_compatibility.png)]
Unity会自动识别兼容SRP Batcher的对象,在SRP Batcher 逻辑路径渲染,非兼容对象也会被Standard SRP 逻辑路径渲染。
Using the SRP Batcher code path | Not using the SRP Batcher code path |
---|---|
* 使用兼容SRP Batcher 的Sahder的Mesh | * 不是mesh的(包括skinned mesh) * Shader不兼容的 * 使用了 Material Property Block 进行渲染的 |
为了验证SRP Batcher 对渲染性能的提升,可以向场景中添加 SRPBatcherProfiler.cs
脚本(创建一个空对象,添加脚本),来查看。当该脚本运行时,使用F8键显示/隐藏剖析窗口,F9键开启/停止Batcher。
界面显示如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GJbXRf7K-1581473824692)(https://docs.unity3d.com/uploads/Main/SRP_Batcher_overlay.png)]
该系统统计了SRP渲染的CPU时间占用。
这里的时间累计了一帧的所有的RenderLoop.Draw
and Shadows.Draw
的时间,无论在哪个线程。例如SRP占用了1.31ms,可以是在主线程draw call占用了0.31ms,1ms是在graphic jobs执行占用的。
名字 | 描述 |
---|---|
(SRP batcher ON) / (SRP batcher OFF) | 当前Batcher是否工作。F9键开启/关闭 |
CPU Rendering time | SRP循环占用的总CPU时间,无论使用的哪种线程模型,例如single(单线程), client/worker(多线程) or graphics jobs(Job系统)。根据该参数可以看到Batcher的效果,通过F9开启/关闭Batcher来对比该CPU时间,来进行对比。上图例子中是2.11ms。(incl RT idle):表示渲染线程的空闲时间,这意味着是client/worker模式,而没有graphics jobs,渲染线程需要等待主线程的Graphics Commands。该例子中,渲染线程等待了0.36ms。 |
- SRP Batcher code path (flushes) | b标识了SRP Batcher 逻辑占用的CPU时间。该时间被分成了渲染所有对象(1.18ms),和渲染对象阴影(0.13ms)的时间。如果阴影数量比较多,尝试降低场景中投射阴影的光源的数量,或者将SRP Asset配置中的Cascades参数降低。该例中,是1.31ms。 flush(s)数量标识了根据shader变体,场景被flush了几次(渲染了多少批次),这里是89次。该值越低越好,越低标识该帧中用到的shader变体越少。 |
- Standard code path (flushes) | 标识了SRP非Batcher逻辑占用的CPU时间。例如骨骼动画模型和粒子。在该例子中,渲染了81个对象,消耗0.8ms,其中影子0.71ms,其它的0.09ms。 |
Global Main Loop: (FPS) | 主循环时间,等于FPS时间。注意:FPS并不是线性的,如果看到FPS提升了20,并不意味着效率提升了。按F9开启/关闭SRP Batcher,对比CPU Rendering time。 |
可以在Frame Debugger窗口中查看SRP Batcher的合批情况。
SRP Batch 细节显示了调用了多少次DrawCall,Shader附加的关键字,为什么没有于上个批次合到一起。在下面的例子中,原因是:Node use different shader keywords,即该批次使用了与上个批次不同的shader keywords,因为使用了不同的shader变体,合批被打断了。如果SRP的DrawCall次数较低,说明很可能用到了太多的shader变体。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-foI634iK-1581473824693)(https://docs.unity3d.com/uploads/Main/SRP_Batcher_batch_information.png)]
如果要实现自己的SRP,而不使用URP或HDRP,尝试写一个使用最少的shader keywords的通用的’uber’ shader (但是可以根据需要使用材质参数和属性,没有太大限制)。