心脏拨它就乱 发表于 2021-9-7 13:43:43

Unity 性能优化:资源篇

Unity性能优化

大的方面来说,通过Unity对于项目的性能优化大概可以分为下面几个部分:


[*]资源
[*]渲染
[*]程序
[*]项目配置
而在这个部分中,资源的性能优化属于最底子、最有效的优化手段,也是游戏开辟者一样平常开辟最需要注意的一部分,所以本篇文章就简单的先容一下对资源举行操作时需要关注哪些点
一、纹理(简单来说就是图片)

纹理的资源优化主要集中于下面的几点:


[*]纹理大小
[*]压缩格式
[*]导入设置
通常,在游戏运行时,大部分内存都是用在了纹理上,因此你的导入设置非常关键,我们可以在Inspector面板看到图片资源的信息,类似于下面这张图:

从性能优化的角度看,纹理导入需要遵循如下的原则:


[*]低落最大分辨率
[*]接纳二次幂压缩格式:
[*]制作纹理图集
[*]取消勾选Read/Write Enabled
[*]禁用多余的Mip Map:Mip Map贴图在2D精灵和UI图形这类大小始终一直的纹理上并无用处
1、低落最大分辨率
很好理解,纹理分辨率越大,在游戏运行时,占用的内存资源越大,并且占用的内存量是与其分辨率的平方成正比的。也就是说,分辨率变为原来的二倍,那么内存量就需要斲丧四倍。因此需要从资源优化的角度来讲,需要对其举行一定的限制,简单的来说,一个Button的纹理通常低于128X128,如果使用1024X024规格的大小就造成了性能的浪费
如下面的图,我们可以在图片资源的Inspector面板中最下面的属性中看到它:Max Size,同时可以看到可以根据不同平台来选择不同的最大分辨率:
第一张图片:Max Size调整为1024,纹理资源大小为4.9MB

第二张图片:Max Size调整为512,图片资源大小为1.3MB

2、对于纹理的压缩
在你主动选择压缩格式之前,Unity本身会对图片做一些处理,无论你放入的是PNG、JPG、PSD或者TGA,Unity都会手动资助我们调整为Texture 2D,这是一种简单的调理策略:

那么既然Unity本身都已经智能转换好了,为什么还要给予开辟者选择压缩格式的选择呢,直接对Texture 2D封装好压缩方法不就可以了吗?
其实Unity相对于其他开辟引擎有一个很显着的优势,就是多适配性,那么为了实现这种多适配性,对于单一平台的针对性就会相对减弱,而不同平台的性能表现又不尽相同,就需要开辟者来根据平台特点来选择针对游戏平台的压缩格式。
同样,即使在同一平台,也会根据不同的情况有着不同的压缩需求,好比有一些关键的主页面图片,玩家感知强的地方,就对图片的质量要求高些,一些边角的辅助图片,可能要求就低一些,如果都使用高质量压缩,性能方面就造成了浪费,但若都是用低质量压缩,质量又跟不上。所以,同样需要根据实际需求选择不同的压缩格式。
在说到Unity图片压缩时,常常会看到这样一张图,来先容不同压缩格式的特点与适用场景,我也是百度图片直接爬取的这张图片,大家可以参考着来看(如果有侵权,请告知我,我会立即删除)

在理解上面这张图之前做一个简单的计算,一张1024乘1024的RGBA32格式图片的占用存储空间为:
由于RGBA32一个像素每一个颜色值是由两个16进制的数组成,也就是8位,那个一个像素就是8位乘以4个颜色值R、G、B、A得到的是4个字节,即4B,然后乘上1024*1024个像素,最终得到的大小为4MB,也就是4兆。很显着这是很恐怖的一个数字,要知道如今移动端手机的运行内存大概6G,除去系统的占用内存,真正给游戏用的最多也就4G`,再分配给GPU|的显存就更少了,而若这些内存被用来大量加载贴图很显着是不能被接受的。同时,这样数据量的图片加载也会给内存
基于上面原生纹理带来的包体与内存问题,就需要根据不同的情况采取一些压缩策略,由于本人基本没有美术功底,所以对与各种压缩格式的美术呈现效果不是很了解,主要是从功能性与性能的角度来分析各种压缩格式的适用场景:


[*] 高风致压缩格式:RGBA32作为一种高保真的压缩格式,可以大概极大的包管图片质量
[*] 中风致压缩格式:RGBA16 + Dithering一听就是RGBA32的阉割版,简单来说,相比于RGBA32其色彩细分程度大,可以显着的看出门路感,视觉表现相对于RGB32不敷平滑
[*] 低风致压缩格式: ETC1+Alpha/PVRTC4这些压缩格式每每是移动段最常用的压缩格式,其相对于其他压缩格式有着无可比拟的性能优势
注意:


[*]除了由于压缩逻辑不同带来的加载带宽减少之外,同时还需要了解像ETC1、PVRTC4等这类在内存中不需要举行解压,而是可以直接被GPU支持,所以相比其他压缩格式通常会有最好的性能表现
3、取消勾选Read/Write Enabled
该功能是为了使得游戏开辟者可以通过C#脚本调用对与图片的读取与写入的控制,很显着,这是由CPU来控制实现的,所以为了可以使得CPU获取数据,需要在内存中备份一份让CPU访问。同时为了图形渲染与表现,又会将其加载到显存中为GPU提供数据。
简单来说,该选项会在游戏运行时,分别在CPU内存与GPU内存中备份出一张贴图,如果你并不需要对于纹理举行读写操作,可以实验关闭该选项,这样就可以避免游戏运行时占用多余的内存
4、禁用多余的Mip Map
Mip Map类似于模型的LOD,同样是一种基于渲染距离改变渲染贴图精度的技术。其优势是在物体距离渲染距离比较远时,可以节省性能。但是使用Mip Map时会增大内存占用量。
Mip map的技术原理是根据原始图举行2的幂次方的递减来天生一组不同精度的图片。当游戏运行时,会将这组图片加载到内存中,然后根据渲染的距离不同,来使用不同精度的图片。
Mip map会增大多大的内存占用量呢


[*]在我们使用Mip map时,假设大小为256X256,并且会天生8张不同精度的图片。根据2的幂次方举行递减计算每张贴图大小并累加。这样最终得到的图片组的体积大概比原来的单张贴图大33%
通过一个实例来验证,假设原始图片大小为8M,天生的第一张低精度图片的大小为2M(分辨率减少一半,大小就会变为原来的四分之一,很好理解)这样大概递减8次,然后累加,就会获取最终的图片组大小,通过一个简单的递归方法来计算一下:
    public void Awake()
    {
      Debug.Log(GetMipmapSize(8, 8)/8);
    }
    // index:处理总层级数 imageSize:初始大小 返回增大的内存量
    float GetMipmapSize(int index,float imageSize)
    {
      float lastSize = 0;
      if (index == 1)
      {
            lastSize = imageSize*0.25f;
      }
      if (index > 1)
      {
            lastSize = imageSize * 0.25f + GetMipmapSize(index - 1, imageSize * 0.25f);
      }
      return lastSize;

    } 执行程序,得到的结果为:

可以看到,求到的结果是接近于33%,固然如果Mip Map对一张纹理的处理不是八次,计算的结果会有偏差但是实际上,从三次往上,内存占用量的增加比例已经非常少了,基本都维持在33%左右,将上面的代码稍微修改,做个小验证:
        public void Awake()
    {
      for (int i = 3; i < 15; i++)
      {
            Debug.Log(string.Format("处理 {0} 次内存占用量为: {1}",i,GetMipmapSize(i, 8) / 8));
      }      
    }
    float GetMipmapSize(int index,float imageSize)
    {
      float lastSize = 0;
      if (index == 1)
      {
            lastSize = imageSize*0.25f;
      }
      if (index > 1)
      {
            lastSize = imageSize * 0.25f + GetMipmapSize(index - 1, imageSize * 0.25f);
      }
      return lastSize;
    } 得到的日志为:

可以发现,从三层开始,基本就维持在33%的内存占用量,并且在层数逐渐增大的时候,内存占用量增加量就非常非常少了。
而Unity所支持的纹理最小为32X32,也就是最小的纹理也会额外的产生三层低精度纹理:16X16、4X4、1X1,这就是为什么许多文章先容到使用Map mip会说其约莫会增加33%的内存占用量
固然Mip map本身是一种性能优化的技术,但是在2D精灵或者UI元素这些不会改变渲染精度的纹理上,只会占用多余的内存,所以在2D精灵或者UI元素上使用纹理时记得不要勾选Mip map。
5、打包图集
图集的打包主要是优化UI图形渲染过程中Draw call的数量,其基本原理也是通过UI元素合批来减少Draw Call,进入提升CPU的性能表现,关于其详细细节,可以检察我之前的文章:
图集打包文章:


[*]Unity 将Sprite打包进图集
二、模型

相比与纹理,模型的性能表现更多的取决于美术规范,程序来讲没有更多可以优化的地方,但是在Unity中也有一些选项影响模型加载、渲染等方面的性能表现,我们可以在导入时看到:

1、禁用掉Reader/Write Enables:
点击模型,可以在Inspector面板看到这些设置选项,类似于纹理,如果在游戏中,你不需要对模型举行修改,可以禁用掉Reader/Write Enables来避免数据的备份而占用多余的内存,我们可以在Unity官方文档中找到相关先容:

翻译过来就是:


[*] 启用此选项后,Unity 会将 Mesh数据上传到 GPU可寻址内存,但也会将其保存在 CPU 可寻址内存中。这意味着Unity可以在运行时访问 Mesh数据,可以从脚本中访问它。
[*] 而禁用此选项后,Unity 会将 Mesh 数据上传到 GPU可寻址内存,然后将其从 CPU 可寻址内存中删除
[*] 默认情况下,此选项处于禁用状态。在大多数情况下,要节省运行时内存使用量,请禁用此选项
而对于模型本身来说,尽量避免模型留有多余的面数。尤其是移动端。因为高精度模型除了本身所带来的压力外,在其他方面也有诸多的性能挑衅
2、尽量不要勾选不需要的功能选项
在Unity中,某些功能即使你未使用到,也会 斲丧一定的资源去维护其状态。类似上面的Reader/Write Enables选项,所以用不到的功能我们可以思量尽量的去禁用掉
3、设置一些关于质量与性能的选项
Unity提供了一些对模型举行优化的选项,可以查阅Unity官方文档来阅读了解他们,这里也简要的列出:

通过上面一张图片可以看出,影响模型表现与游戏性能的选项有下面几个:


[*]Mesh Compression:通过使用网格边界和每个组件较低的位深度来压缩网格数据,增加压缩率会低落网格的精度。最好在 Mesh 看起来与未压缩版本没有太大区别的情况下将其调得尽可能高。这对于优化游戏大小很有用
[*]Optimize Mesh:确定三角形在网格中列出的顺序以获得更好的 GPU 性能,默认都会勾选
[*]Normals:如果网格模型既不是法线贴图也不受及韶光照影响,就选用None,这样也可以大概很好的提升性能表现
其实,Unity设置了一些通过程序控制模型质量来改变性能表现的选项,但是不建议使用,预期通过这些选项来调整性能表现,还不如直接让美术直接处理模型。毕竟他们更加专业,可以更好的包管模型的表现效果与性能表现的平衡。
4、使用LOD
关于LOD,其实应该在渲染这一段来讲,但是这个技术又与模型网格有很大的关系,所以提前先容一下
LOD即Levels of Detail,翻译过来就是多层次细节,类似与纹理渲染的Mip map技术,同样是一种根据渲染距离设置渲染精度的一种技术。其实现方式是在游戏开辟时,美术根据不同的渲染距离制作一组不同精度的模型,导入到Unity通过LOD组件毗连其这一组模型,并设置相关参数。这样在游戏运行时,就会在不同的距离有不同的渲染精度:

这是Unity官方文档的一个案例,可以看出,随着渲染距离的增加,渲染精度逐渐下降,直到最终被剔除,这样做的优势是包管游戏画面表现的同时,可以最大程度低落渲染压力。简单的理解,如果不接纳LOD,随着距离增加,物体占用的屏幕像素就会越少,那么单位像素的三角面数就会越多。单位的渲染压力就会增大。画面表现需求不高的地方渲染压力反而更高,这显然是不公道的。所以就需要通过LOD来解决这样的问题。
固然这种技术本身也是有相当大的缺陷的,起首就是会增大包体的体积,同时也会增加美术的工作量。所以在实际开放中,一般只会对一些重要的对象使用该技术
总结

上面所先容的关于资源影响游戏性能的一些常用的点,都是游戏开辟者一样平常接触最多的,更深入,更底层的就需要根据项目的特点举行专门的适配与调整。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Unity 性能优化:资源篇