SRP Batcher,Draw Call优化,Shader SRP Batcher compatible

当我们使用SRP(Scriptable Render Pipeline)之后,例如HDRP,URP或者LWRP,在SPR的asset文件中有一个选项叫做SRP Batcher(如图)。

这篇文章就让我们来了解了解这个好东西。

 

作用

简单的说,如果当你的场景中有很多的物体分别使用到了不同的Material,但是这些Material使用的Shader却都是同一个时,SRP Batcher可以大大为我们降低DrawCall,从而加快渲染速度。

官方介绍:https://blogs.unity3d.com/2019/02/28/srp-batcher-speed-up-your-rendering/

https://docs.unity3d.com/Manual/SRPBatcher.html

中文文档:https://connect.unity.com/p/srp-batcher-jia-su-xuan-ran

接下来我们可以通过一个简单的示例来验证这个效果。

 

示例

首先我们先通过Create->Shader->Unlit Shader创建一个简单的无光照Shader命名为SampleUnlit。接着我们创建三个Material,分别命名为SampleMaterial1,SampleMaterial2,SampleMaterial3。这三个Material都使用我们刚刚创建好的SampleShader,并分别引用不同的Texture。

接着我们在场景中创建15个Cube,分别引用上面的这些Material,效果如图

SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第1张图片   SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第2张图片

此时打开Game视图的Statistics面板,可以看见15个Cube一共产生了15个DrawCall(由于SkyBox会产生一个DrawCall所以显示的有16个),而Saved By Batching为0。

我们通过Window->Analysis->Frame Debugger打开Frame Debug窗口,点击Enable按钮,可以观察到当前帧的绘制信息

SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第3张图片

按往常我们可能会通过动态批处理或者静态批处理来进行优化。

动态批处理:我们可以勾选SRP asset文件的Dynamic Batching,勾选后可以发现,DrawCall数量变为12,Saved By Batching变为4。同意通过Frame Debug可以发现有些方块的绘制被合并到了一起,从而减少了DrawCall。

    SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第4张图片

静态批处理:我们可以将这些小方块全部变为静态物体(勾选其Static属性),运行后发现DrawCall同样变少了(未运行状态下不变),以及对应的Frame Debug视图如下:

         SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第5张图片

 

但是使用SRP后,这种情况我们就可以使用SRP Batcher来处理了,而且效果会更好。

 

SRP Batcher

首先我们勾选SRP asset的SRP Batcher选项,嗯哼,怎么没有任何变化,说好的会减少DrawCall呢?

通过官方的文档,我们可以找到问题的所在,那就是Shader了。我们点击前面创建的SampleUnlit,会发现其有个SRP Batcher的属性,显示着not compatible,哇擦,不兼容。同时下面还有个看不懂的提示。

SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第6张图片

官方文档有如下一句话:

For a Shader to be compatible with SRP:

  • All built-in engine properties must be declared in a single CBUFFER named “UnityPerDraw”. For example, unity_ObjectToWorld, or unity_SHAr.
  • All Material properties must be declared in a single CBUFFER named “UnityPerMaterial”.

翻译成白话来说,Shader中所有的内置属性例如unity_ObjectToWorld,unity_SHAr等,都要在一个名为UnityPerDraw的CBUFFER中声明,而所有的Material属性都要在一个名为UnityPerMaterial的CBUFFER中声明。

官方文档后面也给到了一个代码示例

Properties
 
{
 
_Color1 ("Color 1", Color) = (1,1,1,1)
 
_Color2 ("Color 2", Color) = (1,1,1,1)
 
}

//原本的写法
//float4 _Color1;
 
//float4 _Color2;


//兼容SRP Batcher的写法

CBUFFER_START(UnityPerMaterial)
 
float4 _Color1;
 
float4 _Color2;
 
CBUFFER_END

可以看出Material属性,也就是Properties中的参数在声明时,都被包含在了一个下面这样的语法快中

CBUFFER_START(UnityPerMaterial)
//Properties
CBUFFER_END

再回过头来看前面我们Shader的提示:Material property is found in another cbuffer than "UnityPerMaterial"(_MainText_ST)。

也就是说我们Shader中的_MainText_ST属性没有声明在名为UnityPerMaterial的CBUFFER中,我们将其改为如下代码

sampler2D _MainTex;
CBUFFER_START(UnityPerMaterial)
    float4 _MainTex_ST;
CBUFFER_END

注:何为_MainText_ST?当Shader中使用到Texture属性(如例子中的_MainText),Unity会自动为我们添加一个类型为float4后缀为_ST的属性(float4 _MainText_ST),用来表示Texture的Tiling和Offset。

再次查看我们的Shader会发现已经兼容了SRP Batcher了,同时Statistics面板中的Save By batching变为了-15。

          SRP Batcher,Draw Call优化,Shader SRP Batcher compatible_第7张图片

此时查看Frame Debug,发现由原来的RenderLoop.Draw变为了RenderLoopNewBatcher.Draw,同时底下只有一个SRP Batch。不过这不代表只使用了一个DrawCall来显示了这些内容,而是对它们进行了序列上的优化。

此时我们已经实现了SRP Batcher的功能了,不过前文还提到了一个用来处理内置属性名为UnityPerDraw的CBUFFER却没有用到,按照UnityPerMaterial的样式,我们可以在Shader中添加一下测试代码:

CBUFFER_START(UnityPerDraw)
    float4x4 unity_ObjectToWorld;
CBUFFER_END

注:有关内置Shader属性的说明可以参照:https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

结果会报错:Shader error in 'Unlit/SampleUnlit': redefinition of 'unity_ObjectToWorld',重复定义了unity_ObjectToWorld。而我们的Shader代码中,怎么也找不到又在哪定义了这个unity_ObjectToWorld。那么只可能是在通过#include引入的其他文件当中了。

如果是CG语言(CGPROGRAM),我们会引用UnityCG.cginc,在Unity安装目录的Editor/Data/CGIncludes文件夹中我们可以找到它,打开查看内容可以发现其又引用了UnityShaderVariables.cginc,相同目录下找到并查看内容,我们就会发现有如下一些定义,替我们定义好了这些内置属性

......
CBUFFER_START(UnityPerDraw)
    float4x4 unity_ObjectToWorld;
    float4x4 unity_WorldToObject;
    float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
    float4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms
    float4 unity_RenderingLayer;
CBUFFER_END
......

如果用的是HLSL语言(HLSLPROGRAM),在我们项目工程的Library/PackageCache/com.unity.render-pipelines.universal/ShaderLibrary目录下有个Core.hlsl文件,在里面又引用了Input.hlsl,在其中又引用了UnityInput.hlsl,打开UnityInput.hlsl同样可以看见这些定义

// Block Layout should be respected due to SRP Batcher
CBUFFER_START(UnityPerDraw)
// Space block Feature
float4x4 unity_ObjectToWorld;
float4x4 unity_WorldToObject;
float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
real4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms

// Light Indices block feature
// These are set internally by the engine upon request by RendererConfiguration.
real4 unity_LightData;
real4 unity_LightIndices[2];

float4 unity_ProbesOcclusion;

// Reflection Probe 0 block feature
// HDR environment map decode instructions
real4 unity_SpecCube0_HDR;

// Lightmap block feature
float4 unity_LightmapST;
float4 unity_DynamicLightmapST;

// SH block feature
real4 unity_SHAr;
real4 unity_SHAg;
real4 unity_SHAb;
real4 unity_SHBr;
real4 unity_SHBg;
real4 unity_SHBb;
real4 unity_SHC;
CBUFFER_END

 

 

 

 

你可能感兴趣的:(Unity,SRP,Batcher,Unity,Draw,Call)