作者:枸杞忧天

(本文首发于公众号“偶尔学学Unity”,文章仅为作者观点,不代表GWB立场)

最近在准备公司的技术分享,主题是入门批量渲染,想着反正也总结了,不如充几篇博客吧,也算显得没有那么半途而废,一举两得了。

所以,这次将分四篇介绍一下与批量渲染有关的知识:

第一篇的主题是静态合批;

第二篇的主题是动态合批;

第三篇的主题是实例化渲染;

第四篇的主题是优化骨骼蒙皮动画,以及两种常用的批量渲染方式:烘焙顶点动画与烘焙骨骼矩阵动画。

那就开始吧。

批量渲染

批量渲染其实是个老生常谈的话题,它的另一个名字叫做“合批”。在日常开发中,通常说到优化、提高帧率时,总是会提到它。

可以简单的理解为:批量渲染是通过减少CPU向GPU发送渲染命令(DrawCall)的次数,以及减少GPU切换渲染状态的次数,尽量让GPU一次多做一些事情,来提升逻辑线和渲染线的整体效率。但这是建立在GPU相对空闲,而CPU把更多的时间都耗费在渲染命令的提交上时,才有意义。

如果瓶颈在GPU,比如GPU性能偏差,或片段着色器过于复杂等,那么没准适当减少批处理,反而能达到优化的效果。

所以要做性能优化,还是应该先定位瓶颈到底在哪儿,然后再考虑优化方案,而不是一股脑的就啪啪啪合批。

当然,通常情况下,确实是以CPU出现瓶颈更为常见,所以适当的了解些批量渲染的技法,是有那么一丢丢必要的。

静态合批

静态合批是一种听起来很常用,但在大多数手游项目里又没那么常用的合批技术。

这里,我简单的将静态合批分为预处理阶段的合并,和运行阶段的批处理。

合并阶段

合并时,引擎将符合合批条件的渲染器身上的网格取出,对网格上的顶点进行空间变换,变换到合并根节点的坐标系下后,再合并成一个新的网格;这里需要注意的是,新网格是以若干个子网格的形式组合而成的,因为需要记录每一个合并前网格的索引数量和起始索引(相对于合并后的新网格)。

空间变换的目的,是为了“固化”顶点缓冲区和索引缓冲区内的数据,使其顶点位置等信息都在相同的坐标系下。这样运行时如果需要对合并后的对象进行空间变换(手动静态合批对象的根节点可被空间变换),则无需修改缓冲区内的顶点属性,只提供根节点的变换矩阵即可。

尽管网格不同、材质不同,Unity也会将它们的网格进行合并

在Unity中,可以通过勾选静态批处理标记,让引擎在打包时自动合并;当然,也可以在运行时调用合并函数,手动合并。

通过勾选开关标记单位参与静态合批

打包时的自动合并会膨胀场景文件,会在一定程度上影响场景的加载时间。

包含静态合批的场景体积大了一丢丢

此外,不同平台对于合并是有顶点和索引数量限制的,超过此限制则会合并成多个新网格。

批处理阶段

运行时是否可以合批(Batch)成功,还取决于渲染器材质的设置。

使用不同的材质,会分为不同的批次

当然,如果手动替换过场景中所有Material,也会打断批次。

运行时手动替换所有渲染器的材质球

不再有合批发生

如果偷偷修改了渲染器使用的网格(不再使用合批后的大网格),也会打断批处理。

替换网格后,也不会再被批处理

除上述之外,还有一些不常用,且不太有用的知识点。

运行时动态加载?

动态加载并实例化一个带静态标记的GameObject到场景中,是不会被当做静态合批处理的。换言之,静态标记只被作为是打包时的考虑参数,并不会在运行时被引擎处理。如果在场景加载后,希望对手动实例化的单位进行静态合批,可以使用手动静态合批。

合并根节点的空间变换

自动静态合批的根节点在场景上,因此无法对其进行空间变换;而手动静态合批,因为根节点不是场景而是一个游戏对象,所以可以通过修改根节点的空间属性(位置、大小及缩放值),达到诸如移动整个合批单位的目的。

当然,即使修改了合批后对象的空间属性,顶点和索引缓冲区里的数据也不会被修改,引擎会在渲染前,通过ConstBuffer(UniformBuffer)传入根节点的变换矩阵,达到了整体变换的目的。

Batch ≠ DrawCall

一次静态合批,并不表示一定只有一次DrawCall命令的调用。

合并发生后,每个参与合批的网格信息(顶点、索引等)就会被最终确定,不再被修改。当一个参与合并的单位不显示时,如被设置为隐藏或被视椎体剔除,引擎并不会修改顶点缓冲区和索引缓冲区的内容,而会拆分若干个小的DrawCall来分次渲染。通过调整每个DrawCall的索引(起始索引、索引个数)来跳过不应该被显示的单位。

通过两次DrawCall来跳过隐藏的三角形

由于,这些DrallCall之间几乎没有渲染状态的切换,效率较高,所以引擎也将其统计为一次合批(尽管包含若干个DrawCall)。

隐藏掉部分立方体后,形成了两次DrawCall

引擎的Statistics窗口、FrameDebugger和Profiler(Renderer)会体现出这种差异

静态合批包含了多个材质时,引擎在材质分组后的处理方式也是相同的,只是不同材质在渲染时,都使用了相同的顶点、索引缓冲区。

与直接使用大网格的不同

静态合批与直接使用大网格(是指直接制作而成,非静态合并产生的网格)的不同,主要体现在两方面。

其一,静态合批可以主动隐藏部分对象。静态合批在运行时,由于每个参与合并的对象可以通过起始索引等彼此区分,因此可以通过上述多次DrawCall的策略,实现隐藏指定的对象;而直接使用大网格,则无法做到这一点。

其二,静态合批可以有效参与CPU的视锥剔除。当有剔除发生时,被送进渲染管线的顶点数量就会减少(通过参数控制),也就意味着被顶点着色器处理的顶点会减少,提升了GPU的效率;而使用大网格渲染时,由于整个网格都会被送进渲染管线,因此每一个顶点都需要被顶点着色器处理,如果摄像机只能照到一点点,那么绝大多数参与计算的顶点最后都会被裁减掉,有一些浪费。

大网格不会被视锥体剔除,全部顶点都会被送进渲染管线

静态合批会被视锥体剔除,只有部分顶点被送进渲染管线

静态合批下合并后的网格

静态合批下,顶点着色器只处理了部分顶点

当然,这并不意味着静态合批一定就比使用大网格要更好。如果子网格数量非常多,视锥剔除时CPU的压力也会增加,所以具体情况具体分析吧~

静态合批的利弊

静态合批采用了以空间换时间的策略来提升渲染效率。

其优势在于:网格通常在预处理阶段(打包)时合并,运行时顶点、索引信息也不会发生变化,所以无需CPU消耗算力维护;若采用相同的材质,则以一次渲染命令,便可以同时渲染出多个本来相对独立的物体,减少了DrawCall的次数。

在渲染前,可以先进行视锥体剔除,减少了顶点着色器对不可见顶点的处理次数,提高了GPU的效率。

其弊端在于:合批后的网格会常驻内存,在有些场景下可能并不适用。比如森林中的每一棵树的网格都相同,如果对它采用静态合批策略,合批后的网格基本等同于:单颗树网格 x 树的数量,这对内存的消耗可能就十分巨大了。

极端情况下可能导致内存占用过高

总而言之,静态合批在解决场景中材质基本相同、网格不同、且自始至终都保持静止的物体上时,很适用。

不出意外的话,下次更新的内容应该是动态合批。

下回见。

批量 材质 调整_游戏图形批量渲染及优化:Unity静态合批技术相关推荐

  1. 批量 材质 调整_寒霜引擎的PBR实践3.0(一)材质篇

    随着对游戏美术品质要求的提高,对整个开发从流程pipeline到从业人员的素质要求都开始增加.传统的美术工作流因为依赖个人的经验和感觉,所以在制作大体量项目的过程中很难达到理想效果.而这时,由项目组内 ...

  2. 批量 材质 调整_SMT打样小批量加工中的助焊剂是什么

    一般SMT打样小批量加工的焊接过程中也有很多值得注意的地方,比如说被焊接金属表面和焊盘表面都是需要仔细清理干净的,否则可能会影响到SMT贴片的焊接效果.助焊剂(flux):在焊接工艺中能帮助和促进焊接 ...

  3. python怎么批量下载年报_使用Python批量下载Wind数据库中的PDF报告

    原标题:使用Python批量下载Wind数据库中的PDF报告 背景 最近小编出于工作需要,准备在Wind金融数据终端批量下载上市公司2019年第一季度业绩预告.通过相关的条件检索,发现其相关数据有近百 ...

  4. mysql批量删除进程_小程序批量删除云数据库里的数据

    我们用云开发的云数据库存数据,难免会遇到数据过多,或者一些过时数据要删除的需求.之前云开发删除数据库只能一条条的删除.要想批量删除很麻烦,近期云开发推出了批量删除数据的方法.甚至可以稍微改造下实现数据 ...

  5. 如何使用python批量压缩图片_利用Python 批量压缩图片

    方法一 直接调整宽高 先放参考资料:如何用Python智能批量压缩图片? import math from glob import glob from PIL import Image import ...

  6. python数据库操作批量sql执行_使用Python批量修改数据库执行Sql文件

    由于上篇文章中批量修改了文件,有的时候数据库也需要批量修改一下,之前的做法是使用宝塔的phpMyAdmin导出一个已经修改好了的sql文件,然后依次去其他数据库里导入,效率不说极低,也算低了,且都是些 ...

  7. pdf批量添加图章_给PDF批量添加文本链接

    为了进一步补充说明文件中的一些重要内容,PDF文件的创建者会为一些文本创建链接,方便阅读者访问相关的网站,获取更多的信息. 我们可以通过使用pdfFactory文本链接功能来实现以上需求,另外,我们还 ...

  8. python批量生成图_利用Python批量生成任意尺寸的图片

    实现效果 通过源图片,在当前工作目录的/img目录下生成1000张,分别从1*1到1000*1000像素的图片. 效果如下: 目录结构 实现示例 # -*- coding: utf-8 -*- imp ...

  9. 2018批量打印开关_从阿迪达斯到国产品牌,感受3D打印技术掀起的运动鞋中底革命...

    3D打印运动鞋已成为走入大众视线的消费品.2018年3月Adidas正式发售10万双 Futurecraft 4D跑鞋,每双价格为2,600元,这双搭载着3D打印鞋中底的跑鞋受到了消费者的追捧. 在F ...

最新文章

  1. 手机扫一扫,现实物体隔空「复制粘贴」进电脑!北大校友的AI新研究,现在变成AR酷炫应用...
  2. 通过XML文件生成View
  3. 机器学习-Random Forest算法简介
  4. 07_设置坐标轴刻度、设置刻度标签(Setting Tick Labels)、调整刻度标签 (Adjusting the ticklabels)
  5. day23 01 类的命名空间
  6. 『操作系统』 进程的描述与控制 Part 1 前驱图与程序执行
  7. 获取设置套接字选项:getsockopt, setsockopt
  8. SpringCloud 应用在 Kubernetes 上的最佳实践(二):部署篇 (开发部署)
  9. Oracle 日期时间函数详解
  10. Android图片剪裁库:uCrop
  11. .net快速开发框架源码分享
  12. 去哪里学习行业知识?
  13. [总结]视频质量评价技术零基础学习方法
  14. c语言中 指针的研究,C语言中指针的研究与总结
  15. LCCUP 力扣杯2020秋季编程大赛题解
  16. Java虚拟机讲解 与 搞垮Java虚拟机
  17. 2018南京大学计算机夏令营机试
  18. 【蓝桥杯-单片机学习笔记(十四)】DS1302
  19. 2021年全球超导体收入大约735.7百万美元,预计2028年达到823.7百万美元
  20. iphone7plus计算机,iPhone 7 Plus人像模式有多强大?看看就知道了

热门文章

  1. linux(3):Linux MBR分区、挂载操作步骤,逻辑卷扩容操作
  2. 树莓派移植SX1278 LoRa通信--使用wiringPi 移植GPIO中断
  3. Linux tm time_t timeval timespec以及与时间相关函数用法
  4. db2存储结构换Oracle,DB2中实现Oracle的功能
  5. CSS Grid布局(2)
  6. 数学学习笔记--概率论
  7. 从像素坐标到相机坐标_【视觉知识】机器视觉几何坐标概论
  8. sql 链接到oracle数据库,通过MSSQL连接服务器连接至Oracle数据库
  9. springboot指定注解扫描范围
  10. 转一个无聊的爱情故事:如果有个女生为你哭