几种合批

SRP Batcher

a) 优化原理

  通过ConstantBuffer将对象的基本信息存储在GPU上,减少CPU和GPU频繁的数据交互带来的性能损失。

b) 限制

  • 需要使用可编程渲染管线,不支持内置渲染管线。
  • 需要shader兼容。

c) 写法参考

复制代码
Shader "Xxxx" {
    Properties {
        _BaseMap("Texture", 2D) = "white" {} //主贴图
        _BaseColor("Tint Color", Color) = (1, 1, 1, 1) //混合颜色

        _Specular("Specular", Color) = (1, 1, 1, 1) //高光反射颜色
    }

    SubShader {
        //.....

        HLSLINCLUDE

        #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"

        CBUFFER_START(UnityPerMaterial)
            float4 _BaseMap_ST;
            float4 _BaseColor;
            float4 _Specular;
        CBUFFER_END

        ENDHLSL

        //.....

        Pass {
            //.....
        }
    }
}
复制代码

 

Dynamic Batcher

a) 优化原理

  将不同物体上的Mesh合并成一个大的Mesh,由CPU作为一个批次提交给GPU,即由原来多个drawcall变成了一个drawcall。

b) 限制

  • 参与合批的物体需要使用相同的材质(同一个材质的clone对象也不行)
  • 单个Mesh不能超过225个顶点
  • shader不能有多个pass
  • 参与合批的对象只能受一个光照影响
  • 收集合批时会有一定的cpu消耗

c) 建议

  如果场景中的物体共享材质的情况比较少,建议关闭动态合批,这样可以减少cpu每帧检查哪些物体可以动态合批的消耗。

 

GPU Instance

 a) 优化原理

  不同物体的Mesh相同时,可以由CPU作为一个批次提交给GPU,由原来多个drawcall变成了一个drawcall,减少CPU和GPU之间的通信开销。

  不同的物体变换矩阵,颜色,纹理等可以不同。

b) 限制

  • 物体的Mesh要相同,且使用相同的材质
  • shader要支持GPU Instancing

c) 写法参考

复制代码
Shader "My/URP_GPUInst" {
    SubShader {
        Tags {
            "RenderPipeline" = "UniversalPipeline"
            "Queue" = "Geometry" //URP中不再决定渲染顺序
            "RenderType" = "Opaque"
        }

        HLSLINCLUDE
        #pragma multi_compile_instancing //编译指令: 添加GPU实例化开关

        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"

        #define UNITY_MATRIX_M unity_ObjectToWorld //GPU实例化: 不同物体的变换矩阵, 使用索引访问

        UNITY_INSTANCING_BUFFER_START(PerInstance) //GPU实例化: 不同物体的颜色, 使用索引访问
        UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
        UNITY_INSTANCING_BUFFER_END(PerInstance)
        ENDHLSL

        Pass {
            Tags { "LightMode" = "UniversalForward" } //渲染pass

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct Attributes { //程序传入顶点着色器的数据
                float4 positionOS : POSITION; //用模型空间顶点坐标填充该变量
                UNITY_VERTEX_INPUT_INSTANCE_ID //每个物体都会分配一个索引
            };

            struct Varings { //顶点着色器传入片元着色器的数据
                float4 positionCS : SV_POSITION; //该变量存放了裁剪空间的顶点坐标
                UNITY_VERTEX_INPUT_INSTANCE_ID //GPU实例化会用到的索引
            };

            Varings vert(Attributes IN) { //顶点着色器
                Varings OUT;
                UNITY_SETUP_INSTANCE_ID(IN); //GPU实例化分配索引
                UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
                VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz); //顶点坐标从模型空间转其他空间
                OUT.positionCS = positionInputs.positionCS;
                return OUT;
            }

            float4 frag(Varings IN) : SV_Target { //片元着色器(逐像素)
                UNITY_SETUP_INSTANCE_ID(IN);
                float4 c = UNITY_ACCESS_INSTANCED_PROP(PerInstance, _Color);
                return c;
            }
            ENDHLSL
        }
    }
}
复制代码

 

复制代码
public class InstancedColor : MonoBehaviour {
    static int colorID = Shader.PropertyToID("_Color");
    static MaterialPropertyBlock propertyBlock;

    [SerializeField]
    private Color color = Color.white;

    void Awake() {
        OnValidate();
    }

    void OnValidate() {
        if (propertyBlock == null)
            propertyBlock = new MaterialPropertyBlock();

        propertyBlock.SetColor(colorID, color);
        GetComponent<MeshRenderer>().SetPropertyBlock(propertyBlock);
    }
}
复制代码

 

优先级

  SRP Batcher > GPU Instancing > Dynamic Batching

 

参考

【Unity Shader】在URP里写Shader(一):介绍-从Built-In到URP - 知乎

关于Unity四种合批技术详解_unity 合批-CSDN博客

Unity可编程渲染管线(SRP)教程:二、自定义着色器 - 知乎

 

posted @   yanghui01  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
历史上的今天:
2023-12-19 cpp环境搭建 - vs2017编译CMakeLists项目(Box2dLite)
点击右上角即可分享
微信分享提示