图片格式一般指我们从美术工具中导出的文件格式,用于在磁盘中存储的格式;如jpg,png,tga等;
文件格式是图像为了存储信息而使用的编码方式,但是他不能被CPU所识别,GPU的特性是做向量运算;因此这些文件被游戏读入时还需要CPU解压成R8G8B8等像素格式,再传送到GPU端使用;而在运行时做解压无疑是非常耗的,所以一般在图片源文件导入时就会为其生成纹理格式的文件。
纹理格式是可以被GPU所识别的像素格式,可以被快速寻址采样。
但是直接使用这种纹理格式会导致资源的加载时间长、内存占用大的问题,尤其在移动平台上更加明显,因此,为了解决这个问题,就出现了压缩纹理格式;
Unity支持许多图片格式的源文件,但是3D图形的实时渲染中不会用这些格式,3D图形硬件要求纹理以专门格式进行压缩,这些格式对快速纹理采样进行了优化,DXT,ETC等压缩纹理格式可以在游戏运行中无需CPU解压就被GPU直接采样。每个不同的平台和设备都有自己的专有格式,因此在选择压缩方式时需要考虑兼容性。
Unity文档中给出了所有支持的纹理压缩格式(https://docs.unity3d.com/cn/2018.4/Manual/class-TextureImporterOverride.html):
这里简单归纳一下,不做一一阐述:
分别对应着RGB和RGBA纹理,适用于android平台;
主要是PowerVR平台下的硬件使用,适用于IOS平台;
近年来使用频率越来越高的一种方式,安卓和iOS都开始支持ASTC,它具有多种压缩比例,而且使用于pot和npot,从4x4每个像素占用8bit到12x12每个像素仅占用0.89个;ASTC压缩的不同设置决定了压缩的大小,和纹理是否带有alpha通道没有关系;
无Alpha通道的贴图建议压缩格式为ASTC 8x8。如果贴图为法线贴图,建议压缩格式为ASTC 5x5。有更高要求的贴图(比如面部、场景地面),可以设置压缩格式为ASTC 6x6,法线贴图为ASTC 4x4。
有Alpha通道的贴图建议压缩格式为ASTC 5x5。有更高要求的贴图(比如特效、UI),可以设置压缩格式为ASTC 4x4。
真实色彩的压缩格式,其中RGBA16位是低质量的真实色彩;
在Unity文档中还给出了每个平台下的默认格式,如下所示,它给出了不同平台、不同颜色模型(有无Alpha通道)下的压缩格式,包括了高质量、正常质量(默认设置)、低质量;
其中高质量一般是8位/像素,基本无压缩;正常质量一般在4-8位/像素;低质量一般在4位/像素以下;
注意兼容性:使用目标平台不支持的纹理压缩格式时,纹理将解压缩RGBA32(因为RGBA32是真彩色,并有alpha通道,它是最高质量的压缩格式,并使用于所有平台)并与压缩纹理一起存储在内存中,解压缩纹理以及存储两次浪费了时间和内存,因此需要针对不同的平台选择兼容的格式。
纹理过大会导致资源的加载、卸载耗时以及内存的占用增加(纹理资源的加载和内存占用一般是正相关的),纹理过大也会导致渲染时的带宽问题;而质量越高、文件越大,因此这是在品质和性能找到一个平衡;
mipmap属性也会导致内存增加,也需要注意,一般UI资源都不需要勾选这两项的;
读写属性会导致内存加倍,而且一般不会用到;
NPOT和POT:主要和mipmap,纹理的存储优化,以及纹理采样的地址计算等有关。如果是p2的话,做起上边这些就很简单了,基本上就是移位移位再移位,硬件做起来很简单,P2对硬件更加友好;这里一般要求美术资源在制作时就是满足pot的,如果美术资源不是,那么使用pot则会出现效果问题;
如果美术资源已经有alpha通道,也可以在导入设置中设置Alpha Source为None;
没有什么比直接减少分辨率更直接有效的工作,就像我们都知道的道理:80%的优化来源于20%的工作,那剩下20%的优化才是真正耗费时间的。
要去限制美术出图的大小,他们不关心性能只关心效果,可能每一张图都想要2048x2048甚至更高,所以有的时候必须要在效果可以接受的基础上来降低分辨率,降低一个级别就是四倍的优化。
我们的思路是让需要展示出高品质的纹理占用更多的资源,让那些没必要展示高品质的纹理占用更少的资源;
尽量避免RGBA32和ARGB32纹理的使用,因为这种格式一般属于高清晰的,但也比较耗;
RGBA16格式的加载效率也很高,接近于ETC1/PVRTC,设备越好,差距越小,因此在ETC1/PVRTC的效果不够好时,可以尝试用RGBA16;
UI贴图要注意Mipmap和read&write属性的设置;
粒子贴图大小一般要在256x256一下;
对于模型、场景贴图,我们需要根据不同用途的贴图做不同的压缩处理,如果使用ASTC格式,可以参考NVIDIA官网给出的测试数据来选择;
在支持OpenGLES3.0的安卓设备上,ETC2是一个很好的处理带透明度的纹理格式,但是游戏需要在OpenGLES2.0设备上,则不要使用ETC2,因为该版本不支持ETC2,这样就会导致ETC2会被转成RGBA32导致双倍的内存占用;
纹理资源一般可以做分档处理,最简单的可分为高中低三档,也可以根据需要加入不同的档次,依据档次来选择压缩格式;
在执行上,一般需要hook和check工具,在导入时对纹理进行一些hook判断和处理,同时check工具要能够获取到项目中所有纹理的大小、压缩格式等信息统计。
其它策略:
1.在玩家焦点区域的纹理可以选择高清,其它区域设置为低清晰,通过动态的LOD来做优化;
Unity Manual:特定于平台的覆盖的压缩纹理格式;https://docs.unity3d.com/cn/2018.4/Manual/class-TextureImporterOverride.html
Unity Connect:说说Unity纹理压缩技术与策略;https://connect.unity.com/p/shuo-shuo-unitywen-li-ya-suo-ji-zhu-yu-you-hua-yi
各种移动GPU压缩纹理的使用方法,介绍了一些纹理格式、图片格式、压缩格式的联系:https://huailiang.github.io/blog/2019/texture/
UWA:Unity加载模块深度解析(纹理篇):https://blog.uwa4d.com/archives/LoadingPerformance_Texture.html
NVIDIA官网:ASTC压缩纹理格式详细分析数据:https://developer.nvidia.com/astc-texture-compression-for-game-assets
来源知乎专栏:游戏编程