我的公众号 亮亮同学TT qq群:117871561 欢迎各位大佬加入。
cocosCreator版本:2.4.4
平台:android
测试工具:adb ,perfdog: https://perfdog.qq.com/
纹理压缩工具:cocoscreator 提供的etc1A slow模式
测试参数:一张 1280 * 720 的png格式的背景图片
这篇文章主要围绕 「cocoscreator提供的纹理压缩功能」 及 「纹理压缩相关的知识点」 来进行的,通过阅读本篇文章,你可以 更清晰的认识在你的项目中 如何权衡 是否用纹理压缩 来达到你想要的 优化效果。
纹理压缩相关知识点
1,计算机中计量存储容量计量单位:
「位(bit」 数据存储的最小单位。在计算机中的二进制数系统中,位,简记为b,也称为比特,每个0或1就是一个位(bit)。计算机中的CPU位数指的是CPU一次能处理的最大位数。
「字节(byte」 字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,也表示一些计算机编程语言中的数据类型和语言字符。Byte是从0-255的无符号类型,所以不能表示负数 。
KB: 千字节 是计算机信息技术用于计量存储容量的一种计量单位
MB:兆字节 是计算机信息技术用于计量存储容量的一种计量单位
GB:是计算机信息技术用于计量存储容量的一种计量单位
关系:
1GB = 1024MB
1MB = 1024KB
1KB = 1024Byte
1Byte = 8bit
1bit(位) 是数据存储最小单位
2,像素格式。
像素格式描述了像素数据存储所用的格式。定义了像素在内存中的编码方式。
「像素深度」 :像素深度是指存储每个像素所用的位数,也用它来度量图像的分辨率。像素深度决定彩色图像的每个像素可能有的颜色数,或者确定灰度图像的每个像素可能有的灰度级数。例如,一幅彩色图像的每个像素用R,G,B三个分量表示,若每个分量用8位,那么一个像素共用24位表示,就说像素的深度为24。一个像素的位数越多,它能表达的颜色数目就越多,而它的深度就越深。
「颜色通道」 :一般用RGBA来表示 颜色通道中R,G,B,A的意义是:R 红色成分,通常范围从0.0(没有红色)到1.0(全部的红色)。G 绿色成分,通常范围从0.0(没有绿色)到1.0(全部的绿色)。B 蓝色成分,通常范围从0.0(没有蓝色)到1.0(全部的蓝色)。A alpha(不透明度)成分,通常范围从0.0(完全透明)到1.0(不透明)。
「像素格式」 :每个像素所使用的颜色通道的组合模式
常见的像素格式有:
「RGBA4444」 :每个通道占4位(bit) 及用此种格式表示一个像素 占用的存储大小是 4*4 = 16 位 = 2Byte。
「RGBA8888」 :每个通道占8位(bit) 及用此种格式表示一个像素 占用的存储大小是 4*8 = 32 位 = 4Byte。
「RGB565」 :占用的存储大小 5+6+5 = 16 位 = 2Byte
「RGB888」 :每个通道占8位(bit) 及用此种格式表示一个像素 占用的存储大小是 3*8 = 24 位 = 3BYte。
等等其他格式。
每个像素的大小 取决于 像素深度 及每个颜色通道所占的位数 所有通道位数的累加。
2,一张图片在磁盘中的大小,一张图片加载到内存中的大小
「我们在 磁盘中看到的一张图片的大小 与 加载到内存中该图片所占用的大小 是不一样的 ,png格式是一种复杂的编码压缩格式,可以把图像信息 高比例压缩,便于传输,而加载到内存中 需要解压解码还原原始信息。所以 在内存中占用的大小要远远大于我们在磁盘中看到的大小」 后面会详细解释,这里先了解一下。
通常情况下 计算一张png图片加载到内存的占用大小公式是: 「图片分辨率*4 = 占用内存」 单位是字节
比如一张1280 * 720 的背景图 所占的内存(显存)是
1280 * 720 * 4 = 3686400 byte = 3686400 / 1024 = 3600 kb = 3600 / 1024 = 3.515 MB
因为一张图片加载到内存中的大小 是由他的像素格式决定的,也是就是 每个像素所用的 像素格式 一般情况下 是默认 「rgba8888」 格式也就是 一个像素32位 及4个字节。 如果 格式用 「rgba4444」 那就是 16位 及2个字节 那计算出来的 内存占用是:
「图片分辨率*2 = 占用内存」 单位是字节
细化后的 计算公式是 「分辨率宽*分辨率高 * 像素格式通道所占用的位数 / 8 = 内存占用」
如果是安卓手机 图片在不同目录下 系统会根据 所在目录的dpi(图像每英寸长度内的像素点数) 进行 计算。
另外 如果用压缩纹理格式的话 , 压缩后的纹理大小 跟纹理加载到gpu的大小 是一样的。比如 一张1280 * 720 的png图片 压缩纹理后大小 1441kb 传递给 gpu 使用时的大小就是 1441kb。
1,图片文件格式与纹理格式的区别
「图片文件格式是」 :将 「位图信息(图像的表述方式,二维数组)」 通过 特殊的编码 生成的存储格式,用于图像信息的存储和传输,一般在磁盘,内存及网络中存储与传输。我们经常看到的图片文件格式 有 png,jpg等格式, 「png(无损压缩)」 , 「jpg(有损压缩」 也会把这些图片称为纹理,但他们并不是纹理格式,不能被GPU直接读取并显示。这些文件格式当被游戏读入后,需要经过CPU解码成 「原始位图(位图的每个像素可以用RGB格式(像素/纹理格式)表述如:RGB565,RGBA4444,RGBA5555,RGB888, RGBA8888)」 ,再传送到GPU端进行使用。
「纹理格式」 :是能被GPU所识别的像素/纹理格式( 「RGB565,RGBA4444,RGBA5555,RGB888, RGBA8888等」 ),能被快速寻址并采样。是GPU能直接使用的数据格式。
2,什么是纹理压缩,常见的压缩纹理格式
「纹理压缩格式」 :
纹理压缩原理参考地址:https://www.khronos.org/registry/OpenGL/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
参考博客:https://www.cnblogs.com/fuckgiser/p/5497013.html
压缩纹理,是一种GPU能直接读取并显示的格式,使得图像无需解压即可进行渲染,可节约大量的内存。常见的纹理压缩格式ETC,PVRTC.
「ETC:」 是一种为感知质量设计的有损算法,其依据是人眼对亮度改变的反应要高于色度改变。是把4x4的像素块压缩成一个64或128位的数据块,,是有损压缩。压缩率6:1,ETC 分为两种, 「ETC1」 和 「ETC2」 ETC1适用于Opengl ES 2.0 支持几乎所有市面上的Android机,所有iPhone ETC2 适用于 Opengl ES 3.0 支持大部分高端Android机,iPhone 5S及以上机型。
「PVRTC:」 PVRTC格式与基于块的压缩格式,与ETC的不同之处是,它使用2张双线性放大的低分辨率图,根据精度和每个像素的权重,融合到一起来呈现纹理,并且2-bpp和4-bpp都支持ARGB数据。PVRTC格式压缩比较高,也是有损压缩。压缩比 2-bpp 16:1 4-bpp 8:1. 只支持长宽相等且为2的幂次方的纹理,支持部分Android机(GPU:PowerVR系列),iPhone全系列机型
「opengl与webgl版本对应关系」
OpenGL 2.0 ——> OpenGL ES 2.0 ——> WebGL 1.0
OpenGL 3.3 ——> OpenGL ES 3.0 ——> WebGL 2.0
纹理压缩对游戏项目的影响
1,包体
1)纹理压缩后的文件要比 png文件大很多(etc纹理压缩的文件名后缀是.pkm) 一张35kb左右的 1280 * 720 的png格式 的图片 纹理压缩后的 pkm文件是 1.4MB左右。
2)打成苹果包和安卓包 后 大小 压缩纹理的 包要比 png的包小 一些 项目中只有一张自己添加的1280 * 720的背景图
没有压缩纹理的包体是 9254kb
压缩纹理的包体是 9227kb
3)如果需要动态加载又想节省下载时间成本 可以考虑 纹理压缩后进行zip压缩 下载到本地后进行解压缩 这种方案。权衡利弊。
zip压缩后的大小:测试用的工具是 7-zip 仅用于测试。项目中可以考虑用gzip 命令gzip地址 http://gnuwin32.sourceforge.net/packages/gzip.htm
压缩前1441kb 压缩后9kb
2,内存
1)通过翻阅大量资料和实际测试 png格式的图片 加载到内存 到提供给gpu渲染。会保存两份 cpu解码后的位图数据 ,一份放在cpu 一份放在gpu. 压缩纹理的数据 则只在gpu保留一份。
2)测试数据 两种方式:一种将1280 * 720的图片直接拖到编辑器 第二种是 用cc.resources.load动态加载
「a」 :直接拖到编辑器 贴图大小 1280*720 加载之前 内存占用 约 121MB 加载纹理压缩后的 图片 内存占用122-123MB 未压缩纹理的加载占用内存是 125-126左右
「b」 :用cc.resources.load动态加载
未进行纹理压缩的图片:
未加载—加载后----加载瞬间内存占用
118MB 128MB 130MB
117MB 128MB 130MB
118MB 127MB 130MB
114MB 124MB 125MB
104MB 116MB 116MB
进行纹理压缩后的内存占用:
124MB 129MB 129MB
118MB 123MB 123MB
117MB 122MB 122MB
117MB 122MB 122MB
117MB 122MB 122MB
通过测试数据可以看出
1)计算 一张图片 加载到内存的 大小公式:分辨率 * 通道数 *单个通道占用内存的大小(bit) 与 实际测试的 数据 有些偏差。
2)通过直接将图片拖到编辑器上 与 动态加载图片 的内存占用 数据 偏差很大 ,前者占用较小 与 计算公式所得的结果 相近, 后者翻了2倍左右
3)压缩纹理后占用内存 大小 远远小于 未压缩纹理占用内存大小,约 2倍左右。
注意:webgl 只支持rgba8888格式
最后 会按照 32的倍数 占用内存
3,加载时间
理论上 压缩纹理的 加载时间 要远远小于 未压缩纹理的时间 。因为 压缩纹理 可以被gpu快速寻址采样,不需要cpu的解码 ,这个过程时间的消耗很大。而未压缩纹理的 需要经过特定的解码规则 进行解码,还原 成原始位图,传送给gpu 进行渲染。
4,cup负荷
因为未压缩纹理的图片 在加入到内存后 需要cpu进行解码 还原成位图,而压缩纹理格式不需要,所以 后者会减轻cpu的负荷。
总结一下压缩纹理的 优缺点:
「优点」 :包体较小,减小首包下载时间和流量。内存占用小,对cpu的压力小 ,减少手机耗电量,减少游戏由于占用内存过大导致的崩溃概率。
「缺点」 :不同的压缩纹理格式对手机设备的支持 不尽相同,所以 需要根据市场情况选择不同的压缩格式。纹理压缩后的文件 远远大于png等压缩格式的大小,对于热更新,动态远程加载资源 来说 是很大的考验,时间久资源包体大。可以进行zip压缩解压缩,处理这种问题。
在cocosCreator中配置及使用纹理压缩功能
官方文档参考
https://docs.cocos.com/creator/manual/zh/asset-workflow/compress-texture.html?h=纹理压缩
最后 「关注微信 公众号 亮亮同学TT」 发送 「压缩纹理」 获取 「批量设置纹理压缩模式,批量设置去黑边的脚本文件」 。