天天看點

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自定義渲染管線的合批多種顔色的合批

繼續閱讀