srp batch

参考网址:

Unity MaterialPropertyBlock 正确用法(解决无法合批等问题)_unity_define_instanced_prop的变量无法srp合批-CSDN博客

URP | 基础CG和HLSL区别 - 哔哩哔哩 (bilibili.com)

【直播回放】Unity 批处理/GPU Instancing/SRP Batcher_哔哩哔哩_bilibili

合批分为四种:

静态合批

动态合批

gpu instance

srp batch

四个优先级排序:

按照出现的历史时间,可以大致这么排序:静态合批和动态合批较早;之后才有了gpu instance,srp batch

按照程序参与度来说:静态合批、动态合批、srp batch只需要勾选一下即可,而gpu instance则需要按照指定的约束编写shader,开启材质gpu instance功能。

从效率来说:静态合批是在build的时候,内存占用大,效率高;动态合批是在运行时的合批,消耗cpu;gpu instance是针对大量同mesh的物体的场景;而srp batch则是针对同shader的不同变体进行合批。

从优先级来说:srp batch》gpu instance

1)静态合批

静批条件:材质球相同+mesh可以不同

相同材质球、相同shader、勾选static、是在build的时候就合并为大的mesh。

mesh可以不同,在build成exe或者移动的可执行的文件的时候,就被合并成了一个大的mesh,在frame debugger中看不到合并结果,只有build之后,才能看到合并结果,通过render doc截帧才能看到。

在player settings的设置中,勾选静态合批。

2)动态合批

动批条件:材质球相同+mesh可以不同(但是必须顶点数小于300)

动态合批,在unity较早的版本,是可以在player settings中找到,并勾选,但是在新版本的unity中,urp的管线中,找不到这个勾选项了。而要在,管线配置中,勾选才行,默认是不勾选的。

默认是不勾选的原因是,dynamic batch是动态合批的,也就是在运行的时候,进行合并mesh操作。这个可能会对cpu有一定的损耗,故要权衡。

如上图所示,圆柱体和立方体,相同的材质球,相同的shader,不同的mesh可以动态合批。

但是动态合批有个特点是,当顶点数量超过300的时候,动批失败,比如将圆柱体改为胶囊体之后,动批失败。

3)gpu instance

instance条件:材质球相同+mesh相同

如下图所示,cube1和cube2是相同的mesh,相同的材质球才能被instance。

如果将cube2缓存是胶囊体,则和cube1不能被instance。

cube1和cube3无法instance,是因为他们使用的材质球不同,虽然shader相同。

shader更改为如下内容:

cs 复制代码
Shader "Unlit/xxxx"
{
Properties
{
    //_MainTex ("Texture", 2D) = "white" {}
    [PerRendererData] _BaseColor("Color", Color) = (1,1,1,1)
}
SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
        CGPROGRAM
        #pragma multi_compile_instancing
        #pragma enable_d3d11_debug_symbols
        #pragma vertex vert
        #pragma fragment frag
        // make fog work
        #pragma multi_compile_fog

        #include "UnityCG.cginc"
        //float4 _BaseColor;
        
        // 如果既要srp batch又要兼顾instance就得这么写
        // UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
        //     UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
        // UNITY_INSTANCING_BUFFER_END(Props)
        
        struct appdata
        {
            float4 vertex : POSITION;
            //float2 uv : TEXCOORD0;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        struct v2f
        {
            //float2 uv : TEXCOORD0;
            UNITY_FOG_COORDS(1)
            float4 vertex : SV_POSITION;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        //如果只支持instance,可以这么写
        UNITY_INSTANCING_BUFFER_START(Props)
            UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
        UNITY_INSTANCING_BUFFER_END(Props)

        // sampler2D _MainTex;
        // float4 _MainTex_ST;

        v2f vert (appdata v)
        {
           v2f o;

            //setup instance id
            UNITY_SETUP_INSTANCE_ID(v);
            UNITY_TRANSFER_INSTANCE_ID(v, o);

            //calculate the position in clip space to render the object
            o.vertex = UnityObjectToClipPos(v.vertex);
            return o;
        }

        float4 frag (v2f i) : SV_Target
        {
          //setup instance id
            UNITY_SETUP_INSTANCE_ID(i);
        //get _Color Property from buffer
        fixed4 color = UNITY_ACCESS_INSTANCED_PROP(Props, _BaseColor);
        //Return the color the Object is rendered in
            return color;
        }
        ENDCG
    }
}

}

UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)

UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)

UNITY_INSTANCING_BUFFER_END(Props)

这个必须是UnityPerMaterial的常量buffer,否则不能同时支持srp batch功能。

加上:multi_compile_instancing

在顶点和片段中加上instance的宏处理才行。

从图上可以看出Cube1和Cube1_1被instance了,而另外两个cube因为深度的原因被instance的两个cube打断了。这里Cube1和Cube1_1使用的是相同的材质球,但是属性不一样。同时开启材质球的instace开关:

测试2使用的是:材质属性块

cs 复制代码
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject m_cube1;
    public Color m_color;

    private Material m_material1;
    private MaterialPropertyBlock propertyBlock;

    void Start()
    {
        if (propertyBlock == null)
            propertyBlock = new MaterialPropertyBlock();
        propertyBlock.SetColor("_BaseColor", m_color);
        MeshRenderer meshRenderer = m_cube1.GetComponent<MeshRenderer>();
        meshRenderer.SetPropertyBlock(propertyBlock);
    }
}

这个脚本就是将黄色和蓝色的cube在Start中改变为黄色、蓝色,使用的是MaterialPropertyBlock这个方式。为啥要使用MaterialPropertyBlock呢?假如我们改为:

Instancing and Material Property Blocks | Ronja's tutorials (ronja-tutorials.com)

cs 复制代码
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject m_cube1;
    public Color m_color;

    private Material m_material1;
    private MaterialPropertyBlock propertyBlock;

    void Start()
    {
        if (propertyBlock == null)
            propertyBlock = new MaterialPropertyBlock();
        propertyBlock.SetColor("_BaseColor", m_color);
        MeshRenderer meshRenderer = m_cube1.GetComponent<MeshRenderer>();
        //meshRenderer.SetPropertyBlock(propertyBlock);
        meshRenderer.material.SetColor("_BaseColor", m_color);
    }
}

则会看到Cube1和Cube1_1的这两个材质球是新创建的两个材质球,但是有个优点是四个cube都能srp batch了。

同一个材质球+不同属性+shader书写要求+开启gpu instance=》才能instance。

instance的功能不受srp batch开关的影响。

Unity三种合批方式和GPU Instance - 知乎 (zhihu.com)

Unity URP中的Static Batching、GPU Instancing、SRPBatcher简单介绍_gpu instancing 和 srp batcher区别-CSDN博客

gpu instancing开启的条件:

1、首先shader必须符合gpu instancing的书写规则,如上面的例子。

2、材质需要勾选enable gpu intancing。

3、srp batcher的优先级高于gpu instaning,对于game objects,如果srp batcher能被使用(shader兼容srp batcher,节点本身也兼容),则就会使用srp batcher,即便材质开启了enable gpu instancing也没用。

4、如果srp batcher的条件被破坏,例如使用了MaterialPropertyBlock,且开启了Enable GPU Instancing,则GPU Instancing则会启用。

4)srp batch

你太逗了吧

srp batch条件:材质球不同(shader须相同)+ mesh可以不同

条件:

shader要满足srp batch的条件,将属性包在常量buffer里面。

如下图:

cube1和capusle是同材质球;cube3和cube1是不同的材质球,但是shader相同。但他们都被srp batch了。

cs 复制代码
Shader "Unlit/xxxx"
{
    Properties
    {
        //_MainTex ("Texture", 2D) = "white" {}
        _BaseColor("Color", Color) = (1,1,1,1)
    }


    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma enable_d3d11_debug_symbols
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"
            //float4 _BaseColor; //_BaseColor作为单独变量声明,没有放置cb中
            
            
            CBUFFER_START(UnityPerMaterial)
            float4 _BaseColor;
            CBUFFER_END
            
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                //o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                // sample the texture
                //fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return _BaseColor;
            }
            ENDCG
        }
    }
}

1)srp batch原理

参考网址:

https://zhuanlan.zhihu.com/p/353687806

https://zhuanlan.zhihu.com/p/433222943

srp batcher使材质数据保留在gpu内存中。如果材质内容不变,srp batcher不需要设置缓冲区并将缓冲区上传到gpu。

2)兼容性

不是所有平台都支持常量缓冲区,所以unity用宏来定义区分什么时候使用。CBUFFER_START宏用来替代开始,CBUFFER_END 用来替代cbuffer的结束。

3)cbuffer

比如:unity_ObjectToWorld或者unity_SHAr。必须在一个名为UnityPerMaterial的cbuffer中声明所有材质属性。只要有一个不走常量buffer中,则合批失败。

相关推荐
qq_4313313524 分钟前
Unity ML-Agents + VScode 环境搭建 Windows
windows·vscode·unity·强化学习
林枫依依1 小时前
Unity 创建、读取、改写Excel表格数据
unity·excel
EQ-雪梨蛋花汤1 小时前
【Unity笔记】Unity 编辑器扩展:一键查找场景中组件引用关系(含完整源码)(组件引用查找工具实现笔记)
笔记·unity·编辑器
枫景Maple3 小时前
Unity常用内置变换矩阵
unity·游戏引擎
太妃糖耶4 小时前
URP-UGUI交互功能实现
unity·游戏引擎·shader
萌萌的提莫队长6 小时前
Unity 跳转资源商店,并打开特定应用
unity·游戏引擎
画中影1 天前
PICO4 Ultra MR开发 空间网格扫描 模型导出及预览
unity·教程·mr·模型保存·pico4ultra·空间网格
EQ-雪梨蛋花汤1 天前
【Unity笔记】Unity + OpenXR项目无法启动SteamVR的排查与解决全指南
笔记·unity·游戏引擎
雨月琉琉1 天前
Unity使用Rider的常用快捷键
unity