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 1808095112 小时前
从零构建一个多目标多传感器融合跟踪器
unity
平行云12 小时前
实时云渲染支持在网页上运行UE5开发的3A大作Lyra项目
unity·云原生·ue5·webgl·虚拟现实·实时云渲染·像素流送
鹏飞于天12 小时前
Shader compiler initialization error: Failed to read D3DCompiler DLL file
unity
wonder1357914 小时前
UGUI重建流程和优化
unity·游戏开发·ugui
那个村的李富贵18 小时前
Unity打包Webgl后 本地运行测试
unity·webgl
nnsix19 小时前
Unity OpenXR开发HTC Vive Cosmos
unity·游戏引擎
nnsix19 小时前
Unity OpenXR,扳机键交互UI时,必须按下扳机才触发
unity·游戏引擎
nnsix20 小时前
Unity XR 编辑器VR设备模拟功能
unity·编辑器·xr
老朱佩琪!20 小时前
Unity访问者模式
unity·游戏引擎·访问者模式
不定时总结的那啥20 小时前
Unity实现点击Console消息自动选中预制体的方法
unity·游戏引擎