• Unity中的静态合批、动态合批、GPU Instance 以及SRP Batching


    Unity中的静态合批、动态合批、GPU Instance 以及SRP Batching

    四种合批简介

    GPU instancing

    GPU instancing: 对同一网格,同时渲染多个副本时使用,底层调用的是多实例渲染接口,例如OpenGL的glDrawArraysInstanced接口。GPU实例对于绘制场景中多次出现的几何图形(例如,灌木丛)非常有用。首先使用GPU Instance,需要材质着色器支持 GPU 实例化,接着就可以在 Project 窗口中选择材质,最后在 Inspector 中勾选 Enable Instancing 复选框。
    在这里插入图片描述

    特点:

    • 使用 GPU 实例化可使用少量绘制调用一次绘制(或渲染)同一网格的多个副本。
    • GPU 实例化在每次绘制调用时仅渲染相同的网格,但每个实例可以具有不同的参数(例如,颜色或比例)以增加变化并减少外观上的重复。
    • GPU 实例化可以降低每个场景使用的绘制调用数量。可以显著提高项目的渲染性能。

    使用GPU Instance的限制条件:

    • Unity 自动选取要实例化的网格渲染器组件和 Graphics.DrawMesh 调用。请注意,不支持 SkinnedMeshRenderer(骨骼蒙皮渲染)。

    • Unity 仅在单个 GPU实例化绘制调用中,批量处理那些共享相同网格和相同材质的游戏对象。使用少量网格和材质可以提高实例化效率。要创建变体,请修改着色器脚本为每个实例添加数据,下述shaderlab代码为官方示例代码。

    • 还可以使用 Graphics.DrawMeshInstanced 和 Graphics.DrawMeshInstancedIndirect 调用来通过脚本执行 GPU 实例化。

    使用实例化渲染实例代码

    Shader "Custom/InstancedColorSurfaceShader" {
        Properties {
            _Color ("Color", Color) = (1,1,1,1)
            _MainTex ("Albedo (RGB)", 2D) = "white" {}
            _Glossiness ("Smoothness", Range(0,1)) = 0.5
            _Metallic ("Metallic", Range(0,1)) = 0.0
        }
    
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 200
            CGPROGRAM
            // 基于物理的标准光照模型,并对所有光照类型启用阴影
            #pragma surface surf Standard fullforwardshadows
            // 使用 Shader Model 3.0 目标
            #pragma target 3.0
            sampler2D _MainTex;
            struct Input {
                float2 uv_MainTex;
            };
            half _Glossiness;
            half _Metallic;
            UNITY_INSTANCING_BUFFER_START(Props)
               UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
            UNITY_INSTANCING_BUFFER_END(Props)
            void surf (Input IN, inout SurfaceOutputStandard o) {
                fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
                o.Albedo = c.rgb;
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = c.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    然后可以在C#脚本中给对应的对象设置Color属性

    MaterialPropertyBlock props = new MaterialPropertyBlock();
    MeshRenderer renderer;
    
    foreach (GameObject obj in objects)
    {
       float r = Random.Range(0.0f, 1.0f);
       float g = Random.Range(0.0f, 1.0f);
       float b = Random.Range(0.0f, 1.0f);
       props.SetColor("_Color", new Color(r, g, b));
       
       renderer = obj.GetComponent<MeshRenderer>();
       renderer.SetPropertyBlock(props);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    更多关于Unity GPU Instance的内容,请点击这里查看官方文档

    static Batching

    • static Batching:静态合批,一般合批的对象是场景中不能动的物体,静态物体,并且在inspector界面勾选上static选项;Unity预先组合静态GameObjects的网格,然后将组合的数据发送到GPU,但单独渲染组合中的每个网格,静态合批不会减小drawcall,只是减少了渲染状态的改变次数。Unity仍然可以单独筛选网格,但每次绘制调用都不会占用大量资源,因为数据的状态永远不会改变。在Unity开启Static Batching,依次点击 Edit > Project Settings > Playe->Other Settings->enable Static Batching。对于Unity使用静态合批的具体要求可以参照官方文档
    • 支持静态合批的Unity渲染管线:默认渲染管线、URP(通用渲染管线)、HDRP、SRP。
    • 在运行时,通过脚本使用静态合批:Unity提供了运行时,通过脚本使用静态合批口:StaticBatchingUtility.Combine,这是一个静态方法,通过这种方式调用静态合批,就不需要在编辑器的inspector界面勾选上Static选项。
    • static Batching缺点与限制使用静态合批会增加内存!,因为使用静态合批,需要在内存中存储合成的几何体数据;如果多个GameObject使用了相同的网格数据,Unity会为每一个GameObject创建一个网格副本,这就意味着相同的几个数据有可能会出现多次!所以如果内存过大,就尽量避免使用静态合批。对于每一次静态合批,顶点数的限制时64000,如果超过这个值,Unity就会再次创建另外一个批次(Batch)。

    Dynamic batching

    • Dynamic batching :动态合批,一般处理的是动态物体;在CPU上变换网格顶点,对共享相同配置的顶点进行分组,并在一次绘制调用中渲染它们。如果顶点存储相同数量和类型的属性,则它们共享相同的配置。例如,位置和法线。 在Unity开启动态合批,依次点击Edit > Project Settings > Player->Other Settings->enable Dynamic Batching。对于Unity使用动态合批的具体要求可以参照官方文档
    • 特点:由于动态合批是通过将多个符合要求的GameObject的顶点一起转换到世界空间,提升性能;相当于是作用在CPU,所以只有在顶点的转换过程比一个绘制调用(Draw Call)过程消耗更低,这种策略才是一个合理的选择。
    • 支持是动态合批的Unity渲染管线:默认渲染管线、URP、SRP。
    • Dynamic batching的限制:动态合批对于顶点属性的数量有限制,不能超过900个顶点属性,例如,材质的shader使用了位置法线UV坐标,那么顶点数就是900 / 3 = 300,如果使用了vertex position, vertex normal, UV0, UV1, 和 vertex tangent,那么顶点数量的限制就是 900 / 5 = 180;

    SRP Batcher

    • **SRP Batcher:**如果项目使用脚本化渲染管道(SRP),使用SRP批处理,可以减少渲染状态的切换,这样会同样可以提升渲染新能,因为满足srp管线的材质,在显存中都有一个CBuffer,只要材质的参数没变,就不用每一帧都提交和设置材质的渲染状态 ,按照官网上上面的文档描述,使用SRP Batcher,其中一个要求是:材质可以不同,但是材质使用的Shader变体必须一致,这个和上面的三种合批方式很不一样

    在SRP Batcher中,GameObject的内置引擎属性(transform等)是有专门的提交路径(下图实线箭头所示),和材质的提交是分开的(下图虚线所示),这样做的好处是,我们每帧都更新一些必要的属性,例如位置,大小等信息,而材质就可以以增量改变的方式提交给GPU,而恰好材质的提交(渲染状态的改变)是非常印象效率的,在SRP Batcher管线中,每一种材质在GPU内存中都有一个CBuffer存放对应的参数,只要材质的参数没有发生变化,那么在每一帧中就不必从CPU提交材质到GPU。从而减少CPU的消耗,提升渲染效率,官网上的示意图如下:
    在这里插入图片描述

    图集的作用

    在上述的合批中,多数都是要求使用相同的材质(meterail),而贴图也是属于材质的一种属性,如果两个材质仅仅贴图不一样,这也会导致材质不一样,就不印象合批,所以把多张贴图打包为图集,这样就可以是的材质引用同一份贴图,使得合批得以进行。

    不同合批的优先级

    1. SRP Batcher and static batching
    2. GPU instancing
    3. Dynamic batching

    SRP Batcher和static batching可以共存,如果一个GameObject使用了static batching,Unity就会禁用GPU instancing ,即使GameObject使用的是GPU instancing Shader; 如果一个GameObject使用了GPU instancing , Unity就会禁用Dynamic batching;

    合批的优先级官网文档参考链接

    UGUI中的mask组件,会增加draw call分析:

    Stencil 状态
    Stencil 状态即模板测试,通过模板缓冲来实现特定的效果,在 Unity 中,Mask 组件就是通过该功能实现,一个 Mask 组件及其控制的渲染节点,需要至少三次 Draw call。第一次开启模板测试并调用一次 Draw call,刷新模板缓冲。第二次绘制对需要通过模板测试的区域进行设置。第三次再进行实际的子节点内容绘制,绘制结束再关闭模板测试。因此使用 Mask 组件就无法与其他相邻节点进行批次处理,但是 Mask 组件内部的连续节点在满足合并规则的情况下还是会进行合批。

    Stencil 使用的最佳实践
    如果界面内使用大量 Mask 组件会带来 Draw call 的剧增,因此应该尽量减少 Mask 组件的使用。如有使用 Mask 组件的节点,应该尽量不要穿插在连续并且可以进行批次合并的节点层级内,这样也可以尽量规避 Mask 打断本可以合并批次的一系列连续节点。

  • 相关阅读:
    LeetCode二叉树OJ
    小知识·认识CMake
    java高校多媒体设备运维管理系统服务端计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
    【git 学习】--- ubuntu18.04 搭建本地git服务器
    多线程中守护线程的使用
    【云原生】Kubernetes----Rancher助力Kubernetes监控
    Linux 共享内存
    vue3在父组件的jsx代码中使用具名插槽
    传奇GOM引擎时装功能如何添加
    Vue入门
  • 原文地址:https://blog.csdn.net/qq_41841073/article/details/127988451