每日一句:别听世俗耳语,看自己的风景就好
目录
SA的原理:
SA的优点:
SA的缺点:
DrawCall是什么?
批处理是什么?
我们先了解一下UGUI系统的运行原理吧!
提到图集优化,我想先引出一个经典的游戏优化案例:
《超级马里奥》的Tile压缩方法:
由于红白机的性能相比现在的家用主机来说极为有限,无论是储存器性能还是处理器性能,所以当时的开发者采用“Tile瓦片”(每个瓦片8X8像素大小)作为基本的图片存储单元,然后再把这些瓦片拼接在一起。
如此以来画面分辨率256X240的红白机用8X8瓦片来填满只需要32 * 30 = 960张瓦片,给每个瓦片一个0至255的编号,那么最多只需要960B来表示一个屏幕里的所有图片,并且瓦片的内容是重复的并且个数是有限的,所要求的存储性能以及内存性能都因此大大降低。
当然为了极致的性能压缩性能,那个时代的开发者也应用了不少的技巧:
1.一个角色的行走动画,用一张图片进行左右交替翻转就能实现,减少了存储压力。
2.天上的云地上的草叠加放置,表现大小规模不同。
3.角色的图片只存储一半,用的时候再翻转拼接,又进一步压缩了存储。
这些前人的智慧也对主流的游戏引擎有着深远影响:Sprite Atlas(精灵图集,以下统称SA)
不仅仅局限于以上描述的方面,SA甚至可以应用于2D 和 3D 项目中的 UI、粒子系统、贴图等等。
现在我们对SA进行一个详细的归纳总结:
SA的原理:
是一种将多张小图汇总,打包成为一个大图的技术。在游戏运行时只需要载入一张大图到内存便可以实现多个素材的载入,是一种优化性能的手段,减少多次DrawCall对性能的占用。
SA的优点:
将多个图片合并到一张大图中,减少多次DrawCall对性能的占用。
SA的缺点:
当不经常使用的素材被放到图集中时,即使改素材不被使用也会被载入内存,浪费了内存资源;并且图集的大小固定为长边的二次幂,如果图集内素材的大小差距过大,会直接造成储存的浪费。
前期要求:
首先我们先找到PackageManager,在Unity Registry中下载2D包。不然无法在项目中创建SA内容。
点击“install”,下载这个包
然后找到Project Setting选项>Editor>Sprite Atlas>Mode
Mode默认是Disabled,更改为Always Enabled,V1和V2两个版本目前没有很大的区别,选V1就行
其他两个选项的意思是:Enabled For Builds——在项目导出后应用图集,所以在编辑器里面看到的图集仍然是原来的那些图片。
为了保证项目能接近玩家原生感受选择Always Enabled。
SA的创建:
项目内右键Project>2D>Sprite Atlas创建SA。
这里如果没有前期准备的内容,就无法创建SA。
配置SA:
点击我们新创建的SA
解释一下该面板的几个重要内容的意义:
- Include in Build:是否在游戏发布后构建到游戏中
- Allow Rotation:是否允许旋转图片,如果勾选,在构建图集时可能会旋转对应的图片,建议禁用
- Tight Packing:选中可根据图片的轮廓而非默认矩形轮廓来打包精灵,让图片排列更紧密,建议禁用,否则UI元素在显示时可能会重叠显示其他的图片,因为在获取对应Sprite时是按矩形轮廓来获取的
- Padding:不同UI元素之间的间隔,单位为像素,避免图片之间过近导致显示出问题
- Objects for Packing:需要打包的UI元素,可以放文件夹或者单个图片,放文件夹可以将文件夹所有的图片打包进这个图集中,图片的格式需要设置为Sprite(2D and UI),一个图集最大的尺寸是2048*2048
以上为SA的使用方法以及原理,当然还有其他的图集系统类似于Texture Atlas的内容,不过原理上也大同小异,下面我们深入的了解一下图集优化的内容。
前文提到了DrawCall,这里解释一下DrawCall的相关概念:
DrawCall是什么?
当我们在渲染一个物体时,需要通知GPU执行渲染的指令,这一过程叫做“DrawCall”。而调用DrawCall的次数越多,对GPU和CPU的性能开销就越大,本身电脑的性能就有限,因此我们便要减少DrawCall的次数,减轻对GPU的性能负担。所以开发者们就想到了上述类似Sprite Atlas的方法,以减少性能开销。
批处理是什么?
上面我们了解了Sprite Atlas的运行原理,而批处理便是该原理的名称;由于每一次DrawCall就可以大致理解为一个渲染批次(batch)。Draw call属于资源密集型的指令,图形API要为每个Draw call做大量的工作。造成CPU性能消耗的主要是渲染状态的切换导致的,例如切换到不同的材质,这会导致在图形驱动中产生密集的资源验证和切换。为了减少draw call的调用,Unity引入了两种优化技巧:
- 动态批处理:对于足够小的mesh,动态批处理通过将他们的顶点整合到一个批次中进行绘制。
- 静态批处理:通过将不会移动的静态物体合并到更大的mesh中,以提升渲染速度。
材质方面的要求
只有使用了相同材质的物体才能够实现批处理。如果两个不同的物体,使用的两个材质,只是纹理上的差别,那就把他们的纹理合并到一起,这样就可以使用同一个材质。脚本中使用Render.material属性时,会重新生成一个原来材质的拷贝,所以用Render.sharedMaterial可以保持材质的一致性(但是使用同一个材质的物体,都会被改变)。关于阴影,只要材质中使用的是相同的Shadow Pass,就可以实现批处理,即便他们不是同一个材质。
我们先了解一下UGUI系统的运行原理吧!
UGUI是在3D网格下建立起来的UI系统,它的每个元素都是通过3D模型网格的形式构建起来的。当UI系统被实例化时,首先要做的就是构建网格。【也就是说,Unity在制作一个图元,或者一个按钮,或者一个背景时,都会先构建一个方形网格,再将图片放入网格中。可以理解为构建了一个3D模型,用一个网格绑定一个材质球,材质球里存放要显示的图片。】
那么这里有一个问题界面上成千上万个元素就会拥有成千上万个材质球、图片。如果GPU对每个材质球和网格都进行渲染,将会导致GPU的负担重大,怎么办呢?
UGUI对这种情况进行了优化,它
- 将一部分相同类型的图片集合起来合成一张图,
- 然后将拥有相同图片、相同着色器的材质球指向同一个材质球,
- 并且把分散开的模型网格合并起来,
- 这样就生成几个大网格和几个不同图集的材质球,
以及少许整张的图集节省了很多材质球、图片、网格的渲染,UI系统的效率提升了很多,游戏在进行时也顺畅了许多。
这就是图集概念,它把很多张图片放置在一张图集上,使得大量的图片和材质球不需要重复绘制,只要改变模型顶点上的UV和颜色即可。
我们设想一下,如果每时每刻都在移动一个元素,那么UGUI系统就会不停地拆分合并网格,也就会不停地消耗CPU来使得画面保持应有的样子。这些合并和拆分的操作会消耗很多CPU,我们要尽一切可能节省CPU内存尽量把多余的CPU让给核心逻辑。UGUI系统在制作完成后,性能优劣差距很多时候都会出现在这里。
我们要如何想方设法合并更多的元素,减少重构网格的次数,以达到更少的性能开销目的呢?(UI优化)请阅读这篇文章啦
Unity—UI-CSDN博客https://blog.csdn.net/m0_63330263/article/details/136473724?spm=1001.2014.3001.5501本文成果由CSDN博主“Lyrissss_”与我共同创作