天天看点

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

接下来我们要来学习下自定义渲染管线中的合批,这一节主要学习SRP Batcher

每一次的Draw Call都需要CPU和GPU之间的通信,如果有大量的数据需要从CPU发送到GPU中,那GPU就可能因为等待数据而浪费时间,而CPU会因为忙于发送数据导致无法做其他的事情,所以这两个问题都会导致帧率的降低。在目前我们的做法有点粗暴,一个物体一个Draw Call,这是非常浪费时间的,只是目前我们发送的整体数据量较少,所以还感受不出问题。

我们可以用示例数字来说明这个问题。

整三十个球,同样颜色,按以前的Unity肯定是能合批的,可是现在需要31个Draw Call,通过合批减少的DrawCall数量(Saved by batching)为0,其实就是天空盒一个,剩下的就是30个球的了。

(为什么Clear的DrawCall没了?哈哈,这就是我们之前做ClearRenderTarget的小优化,对于Skybox的Flag不用进行清理也是可以的,具体可以查看《自定义渲染管线基础学习》-”相机的ClearFlags“这一小节)

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

自定义渲染管线的合批

合批是合并Draw Call的过程,减少CPU和GPU之间的通信量。

在自定义管线中最简单的实现方法就是直接开启SRP Batcher,SRP Batcher实际上并不是直接减少Draw Call的数量,而是简化了流程,它将材质属性存储在GPU,所以不用每一次Draw Call都发送数据,这样子既能减少CPU和GPU之间的通信,也能减少CPU每一次Draw Call所要做的数据准备工作。这样也相当于减少了Draw Call的数量。

但是想要SRP Batcher生效,我们的Shader编写必须按照规范的统一结构来。

我们查看Shader的面板可以查看SRP Batcher的使用情况,发现有无法使用的提示,”属性没有定义在叫【UnityPerDraw】的cbuffer中“。cbuffer(constant buffer)。

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

想要SRP Batcher生效,我们Shader中的所有材质属性不能像之前那样直接定义,必须放在固定的内存缓存中。

之前SRP Batcher不生效的写法

我们查看Unlit的Shader,在上面可以看到提示SRP合批不适用的原因

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

标准写法

(但是在一些平台上无法支持cbuffer,比如OpenGL ES 2.0)

//使用cbuffer UnityPerMaterial 包起来才能使SRP Batcher生效
//但是在一些平台上无法支持cbuffer,比如OpenGL ES 2.0
cbuffer UnityPerMaterial  
{
    float4 _BaseColor;  //用于Shader中定义颜色属性,名称需相同
};

           

由于一些平台无法直接支持cbuffer

Core RP Library中通过CBUFFER_START和CBUFFER_END对此做了处理,因此我们可以使用这个来解决问题

使用需要include Common.hlsl

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批
Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

最终写法

//CBUFFER_START和CBUFFER_END是CORE RP Library中对cbuffer做的处理,解决部分平台无法支持的问题
CBUFFER_START(UnityPerMaterial)
    float4 _BaseColor;
CBUFFER_END

           

但仍然还有问题

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

我们还需要把别的变量也加到这里

CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;  //每一次绘制GPU设置这个值,然后在一次绘制中的顶点片元函数使用期间值不变
float4x4 unity_WorldToObject;
float4 unity_LODFade;
real4 unity_WorldTransformParams;
CBUFFER_END

           

然后CustomRenderPipeline.cs中开启SRP合批

public CustomRenderPipeline()
    {
        GraphicsSettings.useScriptableRenderPipelineBatching = true;  //开启SRP合批
    }

           

终于适用了

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

但不知道为什么我的面板还是没有变化

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

但是FrameDebuger里面已经可以看到效果了

我们可以看到SRP Batch

但我们可以看到上面显示着,Draw Calls 30,所以实际上SRP Batch并不是真正的合批,仍然会有30次Draw Calls,是减少了发送到GPU的数据量

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

到了这里我自己有点懵了

没用SRP之前的有合批么?

除了要勾静态的静态合批外,原来的动态合批是怎么回事?

动态合批需要在PlayerSetting中勾选Dynamic Batch功能,然后也有许多限制

但是它的合批是真的合批

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

多种颜色的合批

我们增加不同颜色的材质赋予这些球,但是我们发现实际上SRP的Batch并不会增加,因为数据缓存在了GPU上,每一次DrawCall只需要包含内存位置的偏移数据就好了。

对于SRP的使用有一个限制是每个材质的memory layout(内存布局?)必须是一样的,因此在这里所有的球我们都使用了同一个Shader,而这些材质都只包含了一个颜色属性。Unity不会去详细的比较的材质的memory layout,而是简单的根据相同的Shader变体去合并Draw Calls。

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

在上面的例子中,为了有5种颜色,我们创建了5个材质球,但如果要十几种颜色或者更多,我们总不能去创建那么多的材质球。如果我们能直接设置每个对象的颜色,那就会方便很多。

我们通过MaterialPropertyBlock实现这个功能。

using UnityEngine;
[DisallowMultipleComponent]
public class PerObjectMaterialProperties : MonoBehaviour
{
    static int baseColorId = Shader.PropertyToID("_BaseColor"); //使用Id的方式去设置属性会更高效
    static MaterialPropertyBlock block;
    [SerializeField]
    Color baseColor = Color.white;
    void Awake()
    {
        OnValidate();  //OnValidate只在编辑器下会被调用,打包后我们得自己调用
    }
    //OnValidate在编辑器下,在组件加载和组件修改时会被调用
    void OnValidate()
    {
        if (block == null)
        {
            block = new MaterialPropertyBlock();
        }
        block.SetColor(baseColorId, baseColor);
        GetComponent<Renderer>().SetPropertyBlock(block);
    }
}

           

我们可以看到虽然我们对这些球只使用了一个材质球,但是颜色却是不一样的,是通过组件修改单个对象的颜色

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

但是,我们看到SRP Batcher不生效了,这样子虽然方便了,但是性能不行了

Unity SRP自定义渲染管线学习2.2: 合批(Batching) SRP Batcher自定义渲染管线的合批多种颜色的合批

继续阅读