cocosCreator 压缩纹理及详细介绍 (性能优化必看)

我的公众号 亮亮同学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」 发送 「压缩纹理」 获取 「批量设置纹理压缩模式,批量设置去黑边的脚本文件」

25赞

亮亮同学很靓

亮亮同学很靓

大佬,麻烦问下这个实时内存你是怎么看的?perfdog 感觉有延迟的感觉

我是 记录60秒左右 内存占用趋于稳定后记录的 ,包括 切后台再切回来。这数据 不稳定的 ,我觉得跟cocoscreator的压缩纹理机制和处理纹理缓存的时机还有手机机型有关。多测几次 取平均值。另外,这种测试主要还是烘托 压缩纹理 的优势 ,不管怎么测 压缩纹理占用内存都要小2倍左右 哈哈。 :rofl:

哈啊哈 :laughing:

:yum:

请问对于assetsbundle得纹理压缩有考虑过方案么?因为assetsbundle得分包没有压缩选项,如果分包使用纹理压缩,分包得包体会翻好几倍。

请问一下微信小游戏适合用压缩纹理吗?我试过,H5的包,好像容量非常大,小游戏根本装不下。

占个楼,收藏=会了

嗯 压缩纹理后的 文件大小非常大,目前觉得不适合h5和小游戏呢 :upside_down_face:

试了下,pvrtc rgb seperate a 是不是不能压缩jpg格式的,是否要加上jpg的配置去适配呢?

emm,png和jpg读到内存后占用的大小是一样的,jpg 是失真压缩格式,png是无损数据压缩格式。建议用png格式的图片文件 进行压缩纹理呢。

就是说项目内不要有jpg的图片,这样处理比较好是吧

通常情况下项目中会选择png格式的图片文件作为纹理。
这要看项目 想要达到哪种效果 ,如果是原生平台 ,需要压缩纹理的情况下 尽量选择 png。 如果不需要压缩纹理,想要减小包体或者进行远程动态加载资源时降低加载时间的话,同时对画质要求不高 推荐选用 jpg格式,因为jpg格式的图片文件 要比 png格式的图片文件 占用磁盘空间小一些。

1赞

好的,谢谢

大佬,来我技术群呗 一起交流技术 群号117871561

有个疑问就是:压缩纹理之后的图片比png图片要大,为什么构建出来的安卓包和ios包,反而小了?

1赞

apk 本质上是个 zip

是的,但是压缩的对象本身越大,压缩成zip包的时候zip包不是会更大一些吗?