batching(合批) 和大量的描述一个3D物体的数据有关系,比如meshes,verices,edges,UV coordinates 以及其他不同类型的数据。在Unity中谈论batching,指的是用于合批mesh数据的两个东西:Dynamic Batching(动态合批) 和 Static Batching(静态合批)。渲染管线特别喜欢处理合在一起提交的mesh数据而不是单独的一个个的mesh数据。

Draw Calls

在讨论Dynamic Batching(动态合批) 和 Static Batching(静态合批)之前,先理解下Dynamic Batching(动态合批) 和 Static Batching(静态合批)要解决渲染管线的问题:降低用于绘制当前视图所有物体的Draw calls。

Draw call是从CPU发送到GPU的一个请求,用于物体的绘制。在Draw call请求之前,需要完成一系列的准备工作。

首先,mesh和textrue数据必须从CPU 的内存(RAM)推送到GPU内存(VRAM),对于已经存在于场景里的,这通常发生在场景初始化的时候。对于预先没有在场景内的,只能在它们被instantiate的时候进行该操作。其次,cpu必须为gpu准备渲染所需要的设置和数据。cpu和gpu之间的通信是通过不同平台的图形API来完成的,有可能是DirectX,OpenGL,Vulkan等等。

API通过驱动程序调用,大量繁杂的渲染管线渲染物体所需的设置信息通常被叫做Render State。在Render State改变之前,GPU都将会一直使用这个Render State来渲染物体。对Render State做改变是一个开销非常大的过程,比如我们设置Render State使用一张蓝色texture去渲染mesh,这会将整个mesh渲染成蓝色,我们可以再渲染9个完全不同的mesh,它们都会被渲染成蓝色,因为我们没有改变使用的texture。但是如果我们想渲染10个mesh哟个10张不同的贴图,就会十分耗时,因为需要渲染每个mesh时都去准备新的贴图信息发送draw call。越少更改Render State,图形api处理我们的请求就会越快。

能触发Render State同步的操作包括但不限于:添加实时的texture到GPU,修改Shader,修改灯光信息,修改阴影和透明度等等有关渲染的设置。

CPU和GPU之前通过Command Buffer保持通信,这个队列存储了CPU创建好的用于渲染的操作指令,GPU在每次完成渲染指令后再从这个队列中获取。

一个新的Draw Call并不意味着必须有一个新的Render State。合批能够提供渲染性能的原因是如果俩个物体使用同样的RenderState信息来渲染,GPU就可以立刻渲染下一个物体,这消除了Render State的同步时间,合批同样可以减少渲染的指令数量,减少CPU和GPU的负荷。

Materials and Shaders

Unity中通过Materials来把Render State暴露给我们。Materials是一个Shader的容器,shader本身并不感知实际的Render State,shader所需的diffuse textures,normal maps等实际就是隐式的Render State变量。

每一个shader都需要一个Material,一个Material也必须有一个Shader。因此如果我们想减少Render State的变化,我们可以通过减少场景中Materials的数量。CPU每帧会消耗更少的时间来生成和传输渲染指令,GPU也不需要频繁停下来重新同步Render State的变化。

做个实验,四个cube,四个sphere,各自不同的material,关掉shadow,关掉dynamic batching 和 static batching:

结果为9个batches(还有一个是背景,比如天空盒)

像之前介绍的那样,我们可以减少material数量来提高效率,如果都用同样的material会是什么效果:依然还是9个,这是因为我们没开启Dynamic Batching,渲染管线并不能够意识到需要重复使用Render State。

The Frame Debugger

Unity中调试渲染非常有用的工具,可以查看每一帧的渲染过程,对于跟踪场景中DrawCall来源,优化游戏非常有用。这一小节就不详细介绍了

Dynamic Batching

三个特性:

1. 运行中实时动态合批

2. 根据主摄像机视野中可见的物体,每一帧合批的内容都可以不同

3. 运动的物体也可以进行合批

上一小节的例子,开启动态合批后结果为:6个batches,这是因为4个Sphere因为不满足动态合批条件而没有进行合批。

动态合批的条件具体参考Unity的文档,这玩意随着Unity版本的变化不断在变化。

https://docs.unity3d.com/Manual/DrawCallBatching.html

动态合批需要满足的条件:

  • 使用相同的材质引用
  • 只有ParticleSystem和MeshRender可以合批,SkinnedMeshRender等其他Component无法合批.Currently, only Mesh Renderers, Trail Renderers, Line Renderers, Particle Systems and Sprite Renderers are batched. This means that skinned Meshes, Cloth, and other types of rendering components are not batched.
  • 每个mesh最多300个顶点索引。
  • 最多900个顶点属性 。
  • mesh的Scale要么都统一,要么都别统一(这句没看懂,令人费解)
  • 材质的shader不能使用多passes
  • mesh不能接收实时阴影
  • 合批后mesh总共的索引数不能超过各自平台的上限,一般是32k-64k个。

Vertex attributes

顶点属性是每个顶点的一系列信息,比如位置,法线,UV等。如果每个顶点3个属性,则如果想合批,可以最多支持的顶点数是900/3 = 300。如果每个顶点5个属性,则最多可以持的顶点数是900/5 = 180。要注意的是即使顶点属性少于3个,合批最多也只能支持300个顶点(另外一条规则)

Mesh scaling

奇数个负数Scale不能合批,比如(1,-1,1),偶数个可以(1,-1,-1)

Dynamic Batching summary

  • 适用于场景中含有大量简单的物体,比如大片有石头和树木的森林等。
  • 如果只是单纯的texture不同,可以考虑使用图集的方式,这样就可以合批。
  • 如果场景中有很多个比较简单的物体,但是只有少数可以合批的话,还不如不开启合批,因为遍历场景判断合批的操作可能更费。
  • 动态合批的条件非常苛刻,经常会出现打破了合批规则而自己不知道,所以要多注意,要经常不定期的去调试check来保持Draw call的合理值,当然,常常的状况是我们直到Draw Call真的成为性能瓶颈影响表现时,并不需要去考虑Draw call。
  • 最后一条建议,多尝试,看看哪些不能合批哪些能合批来保证Draw call

Static Batching

Unity 提供了第二种合批方式,那就是Static Batching。Static Batching的条件:

  • 物体必须被标记为Static
  • 需要额外的内存
  • 合批后mesh总共的索引数不能超过各自平台的上限,一般是32k-64k个。
  • mesh可以不同,但是必须使用相同的材质引用

The Static flag

要小心如果只是把物体标记为Batching Static,运行时可能会产生奇怪的现象:mesh由于Static Batching没有移动,但是Rigidbody什么的可能会动。

Memory requirements

额外的内存开销是Static Batching的一个缺点,Static Batching copy 需要合批的mesh的数据到一个单独的大mesh buffer中,并将其传入渲染管线中通过一个Draw Call进行渲染,完全忽略掉原始的mesh。如果需要合批的mesh都是不同的,那是否使用静态合批内存的开销是一样的。然而如果渲染的是相同的object,则内存开销会翻倍,平常渲染一个,10个或者100万个同样object的clone花费的内存开销是一样的,因为他们引用的是相同的mesh 数据,对于每个Object唯一不同的只是transform。然而Static Batching 需要copy mesh 数据到大的buffer中,这种引用关系就没有了,每个物体都会将原始的mesh数据copy到buffer中。因此使用Static Batching 渲染1000个tree的内存开销是不使用Static Batching的1000倍,所以在使用Static Batching时要慎重,要判断使用的是否合适。

Material references

有时候,Static Batching会需要处理多个Materials,在这种情况下,每个Material会被分组到各自的Static Bathc中,也就是说Static Batching可以用和Materials数量相等的Draw Call渲染所有的静态meshes。

Static Batching caveat & Edit Mode debugging of Static Batching & Instantiating static meshes at runtime

  • Static Batching 不能在编辑器中立刻查看效果,只能运行起来后看效果,调试起来非常麻烦
  • 运行时将物体动态标记成Static并不会被合批,但是可以通过 StaticBatchUtility.Combine() 强制合批,但是要非常谨慎使用,这个函数开销极大

Static Batching summary

Static Batching 是一个十分有用但是又十分危险的工具,如果使用的好会给渲染带来提升,如果使用的不好,内存的开销以及各种其它弊端都会很蛋疼。

Summary

Dynamic Batching 和 Static Batching summary都是有用但是又有风险的工具,要真正搞明白它们才能正确的使用它们。第六章会更多更深入的介绍Dynamic Graphics。

GPU Instancing

此处加一点书中这章没写的内容,GPU Instancing也会有效降低DrawCall,它的原理详见

https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/10%20Instancing/

GPU Instancing 非常高效,它的要求也更高,不仅要求Material引用一样,mesh也必须一样,因为mesh一样所以才不会存在Batching合并大mesh带来的内存开销。

Unity Batching优先级:静态合批 > GPU Instancing  > 动态合批

Unity 2017 Game Optimization 读书笔记 The Benefits of Batching相关推荐

  1. Unity 2017 Game Optimization 读书笔记(1)Scripting Strategies Part 1

    1.Obtain Components using the fastest method Unity有多种Getcomponet的方法: GetComponent(string), GetCompon ...

  2. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (6)

    1. Use less texture data 这条优化技巧非常直接,减少texture的数据量,减少分辨率或者降低位数,虽然可能会降低渲染质量.但是通常使用16-bit textures并不会明显 ...

  3. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (5) Shader优化

    Shader optimization Fill Rate和 Memory Bandwidth开销最大的地方就是Fragment Shader.开销多大取决于Fragment Shader的复杂程度: ...

  4. Unity 2017 Game Optimization 读书笔记 Scripting Strategies Part 5

    一. Disable unused scripts and objects 场景中激活的物体或者脚本越多,开销越大.对于很多并没有产生作用的脚本和物体,可以隐藏掉从而提升性能,比如FPS游戏中视野外的 ...

  5. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (4)

    Optimizing Unity UI 本章讲探讨一些能够提升UGUI性能的优化方法. 1.Use more Canvases 一个Canvas的主要任务就是管理它层级下的所有UI元素,并且通过Dra ...

  6. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics (3)

    Rendering performance enhancements Enable/Disable GPU Skinning 开启GPU Skinning可以减轻CPU或GPU中Front End部分 ...

  7. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(2)

    Lighting and Shadowing 现代的游戏中,基本没有物体能在一步就完成渲染,这是因为有光照和阴影的关系.光照和阴影的渲染在Fragment Shader中需要额外的pass. 首先要设 ...

  8. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(1)

    The Rendering Pipeline 渲染表现差有可能取决于CPU端(CPU Bound)也有可能取决于GPU(GPU Bound).调查CPU-bound的问题相对简单,因为CPU端的工作就 ...

  9. Unity 2017 Game Optimization 读书笔记(4)Scripting Strategies Part 4

    1.Avoid Find() and SendMessage() at runtime SendMessage() 方法和 GameObject.Find() 相关的一系列方法都是开销非常大的.Sen ...

最新文章

  1. C#4.0和VS2010新特性(三)
  2. python中change的用法_vue中select的使用、默认选择、onchange/change事件等操作实例
  3. html除左侧浮动,html清除浮动的6种方法示例
  4. 使用Canal实现redis和mysql的同步
  5. 【架构师】【数据库基础】【笔记 01】快速了解数据库系统的重要概念02
  6. mysql数据库事务隔离级别
  7. Java 多线程的创建
  8. 高考计算机专业最低分数线是多少,2021最低多少分可以稳上二本 高考二本分数线是多少...
  9. 彻底搞懂Html5本地存储技术(一)
  10. mergesort java_排序--归并排序MergeSort(Java实现)
  11. 怎么去掉win7开始菜单中的睡眠和休眠选项
  12. APP下载链接在微信被屏蔽了 无法打开的解决方案
  13. 一次搞懂数据大屏适配方案 (vw vh、rem、scale)
  14. 计算机硬件资源可,计算机硬件资源,Computer hardware resource,音标,读音,翻译,英文例句,英语词典...
  15. 什么是增值税的进项税和销项税?
  16. windows: 如何显示文件的全称
  17. 防火墙添加ip白名单_如何给防火墙加白名单 防火墙添加ip白名单
  18. C#连接SQL Server并查询数据
  19. 堡垒机前戏:paramiko模块
  20. Pikachu靶场练习

热门文章

  1. 两表左连接count某一字段_表连接解决多日留存率问题|SQL
  2. 两个摄像头合成一路_三星推出全新摄像头光电传感器ISOCELL GN1,性能直奔HM1
  3. Pytorch(一) --线性模型
  4. array(2019CCPC网络预选赛 hdu6703主席树+set)主席树求大于等于k的最小值
  5. android studio启动停止命令,那些停止Android Studio任务的方法(不断整理中)
  6. 安安猜价格聪明机器人_5 项降噪优化,石头扫地机器人 T6 安静也有大吸力
  7. c语言在dos下执行bat文件,应用dos批处理文件经常用到的DOS常用命令
  8. php中的getdate+函数,PHP中的getdate()函数
  9. 计算机网络部分简答题
  10. 【IT笔试面试题整理】给定二叉树,给每层生成一个链表