这里要讲讲很多人分不清楚的“图片格式”和“纹理格式”的区别和联系。
图片格式是图片文件的存储格式,用于图片文件的存储和传输,通常在磁盘文件,内存及网络传输中使用。
纹理格式是显卡能够直接进行采样的纹理数据的格式,是向显卡中加载纹理时使用的数据格式。
图片格式与纹理格式之间的关系是,没啥关系。计算机中的所有图片文件,如果需要用作纹理,那么必须被转换成显卡能识别的纹理格式,然后才能提交给显卡。
常用的图片格式很多,有位图也有矢量图,有带压缩的也有不带压缩的,有无损压缩的也有有损压缩的。比如 bmp 就是一种无压缩的位图格式,png 是使用了lz77压缩算法对位图进行了无损压缩的格式。而 jpg 是一种有损压缩的格式,并且 jpg 是不带 alpha 通道的。
纹理格式则要看显卡以及图形API的支持情况,比较基本的32位纹理 A8R8G8B8,或者不带Alpha通道的 R8G8B8 ,或者16位纹理 R5G6B5 等等在目前的显卡级图形API中得以被广泛支持。而有些特殊的纹理格式,只有支持特定图形API的图形设备才能支持,比如DirectX特有的 DXTx 系列,Android上广泛使用的ETC系列,iOS最新的ASTC系列纹理格式,都只能在特定的设备上支持。
把图片加载成为纹理的时候,需要将图片格式按照对应的规范解码,一般是解码为原始位图,然后再重新编码成你需要的纹理格式。这个过程游戏引擎,比如Unity或者虚幻,通常已经帮我们做好了,不用开发者自己关注其中的细节。
但是这种加载方式有一个问题,解压缩,解码,重新编码压缩等都是比较消耗CPU的操作,也就是说会比较耗时,因此会导致从磁盘加载一个图片一直到提交到显存中成为纹理的过程比较缓慢,会导致明显的加载时卡顿掉帧。
为了加快这个时间,Unity采用了一种机制,在资源打包的时候,不管是AssetBundle 还是安装包,都把图片预先转换成对应平台的纹理格式。因为保存在包里的已经是最终纹理格式,加载时就省掉了图片解码解压,再做纹理编码这个过程,能够加快加载速度。这也是为什么Unity的AssetBundle包不能跨平台通用的原因之一,因为纹理格式是与平台相关的。
这就是为什么jpg文件很小,但是产生的纹理却比较大。jpg是有损压缩的图片文件格式,通常有损压缩能够获得比无损压缩更小的文件尺寸,而且jpg是不带Alpha通道的。而这个jpg文件对应的纹理格式,可能是原始位图格式,那当然会比jpg大很多。
谨慎的选择纹理格式是很重要的,针对不同的目标平台,不同的显示效果要求,选择你使用的纹理格式,以及纹理尺寸,对于图形优化来说是非常重要的。
如果目标平台是PC,同时不要求极限的高清画质,那么DXTx当然是你的最佳选择,而且可以使用Crunched 压缩,进一步减小纹理尺寸,通常不带透明通道的选择DXT1,带透明通道的选择DXT5。DXT纹理格式也是一种有损压缩编码的纹理,其原理类似JPG,但是采样快的大小固定为4x4 所以不像JPG一样可以选择质量,其纹理大小比原始32位RGBA的纹理分表小8倍(DXT1)和4倍(DXT5)。
如果目标平台是移动端,在Android设备上目前主要还是ETC格式,只有极少的Android设备支持DXT格式。iOS的高端设备支持一种新的格式ASTC,具体如何使用可以查看文档。
如果一定要使用JPG图片来加载,那么只能把JPG图片文件不当做文件,而是当做一个二进制资源来使用,运行时实时加载进内存,然后再转换成纹理,这样做节省了空间,但是增加了时间开销。
来源:知乎