一个操作让游戏内存立减 50%!

共 3263字,需浏览 7分钟

 ·

2021-03-17 12:11

在游戏中,纹理不仅占据大量的包体,也占据了大量的内存。传统的图片压缩格式(如 JPEG、PNG 等)虽能减少资源大小,但是不能被 GPU 直接识别,还是需要先加载到内存通过 CPU 解码,转换成 RGB/RGBA 等能被 GPU 识别的格式,才能传送到 GPU 进行渲染。

为避免这些问题,社区 Cocos Star Writer 楚游香带来针对 GPU 的纹理压缩方案,使纹理能够直接被 GPU 识别并进行渲染,它具有以下优点:

  • 无需 CPU 解码,节省了 CPU 运算,减少耗电量;

  • 纹理直接被传送到 GPU,避免了内存占用,提高渲染性能;

  • 高效的压缩算法,减少了包体大小。

以下是具体操作讲解,欢迎阅读。


01

压缩纹理的原理 



传统的图片压缩主要目的是存储和传输,为了尽可能的高效压缩,使用了可变的压缩比率,因此在解压时需要解压更多的像素位才能读取某个像素的位置,不适合随机和快速读取,也发挥不了 GPU 的并行处理优势。

而压缩纹理使用一个固定的压缩比率,将纹理划分成多个像素块,每个像素块包含 2*2 或 4*4 个像素,然后对每个像素块进行压缩,被压缩的像素信息存储在一个像素集合中,每个像素块的索引位置存储在一个块索引图中。

读取时,首先将纹理坐标转化为块索引值,然后在像素集合中查找对应的像素块,最后在这个像素块中找到纹理颜色值。

因为采用了固定的压缩比率,GPU 内部可以并行处理,从而快速的解压缩。与之相对的是,纹理的压缩过程发生在程序运行之前,并不在意编码速度,因此在压缩时会遍历所有可能性,找到和原始像素差值最小的编码,这也是纹理压缩耗时较久的原因。

顺便说一下,普通图片格式中,PNG 是无损压缩,JPEG 是有损压缩。而压缩纹理都是有损压缩,只是在绝大部分情况下,手机上看不出来而已。


02

常用的压缩纹理格式



手机上使用压缩纹理依赖于 OpenGL ES 的支持,OpenGL ES 2.0 本身并没有定义任何纹理压缩格式,它仅提供 glCompressTexImage2D()  方法供应用程序上传压缩纹理,压缩纹理的格式由各个 GPU 厂商定义和实现。

OpenGL ES 3.0 提供了压缩纹理标准,使各个平台都可以使用同一种压缩纹理,但市面上的设备还需要很长时间才会全部过渡到 OpenGL ES 3.0。因此,仍然需要对不同的平台和设备使用不同的压缩纹理格式。

手机游戏中常用的有以下格式。

2.1 ETC1 

ETC1 把 4*4 的像素块压缩成固定的 64 位编码(8 个字节),4*4 像素块是 16 个像素,每个像素 4 字节,一共占 64 个字节,所以压缩比是 64/8=8。

但是 ETC1 只能存储 RGB 信息,不适用带透明度的纹理,为解决这个问题, Creator 在 ETC1 文件中额外写入了透明度信息,即 ETC1+A 格式,它的压缩比是 64/16=4。ETC1/ETC1+A 需要 OpenGL ES 2.0(对应 WebGL 1.0)环境,目前几乎所有 Android 手机都支持 ETC1,但是 iOS 不支持。ETC1/ETC1+A 纹理的长宽可以不相等,但要求是 2 的幂次方。

2.2 ETC2 

ETC2 是 ETC1 的扩展,压缩比率一样,但压缩质量更高,而且支持透明通道,能完整存储 RGBA 信息。

ETC2 需要 OpenGL ES 3.0(对应 WebGL 2.0)环境,目前还有不少低端 Android 手机不兼容,iOS 方面从 iPhone5S 开始都支持 OpenGL ES 3.0。

ETC2 和 ETC1 一样,长宽可以不相等,但要求是 2 的幂次方。

2.3 PVRTC 

Creator 中常用的是 PVRTC4+A,压缩比和 ETC 一样,iOS 全系列支持,但是 Android 不支持。另外 PVR 要求纹理长宽相等(正方形)且是 2 的幂次方,例如 1280*720 的 PNG 图片,转换后变成 2048*2048,这一点会大大增加内存消耗。

在实测中还发现转换后的图片质量不如 ETC1,存在模糊、毛边现象,对画面要求高的游戏不适合。


03

压缩纹理的使用



压缩纹理的使用非常简单,根据构建平台添加需要的格式即可,具体参见 Creator 官方文档,本文不再重复。

Creator 编辑器还提供了转换压缩纹理的选项,根据转换速度分为 Fast、Slow 等好几档,速度越慢则画面质量越好。但不管选哪个,只影响显示效果和转换时长,显存占用都是一样的。

一般情况下,显存占用就是压缩纹理的文件大小,例如文件大小是 1.5M,则它占用的显存也是 1.5M。

在设置压缩纹理格式时,目前 Creator 2.x 版本还需手动一个一个设置。如果想一次性设置所有或部分资源,记得有大佬提供过插件,当然自己写个脚本遍历修改对应的 .meta 文件也比较方便。

这里是一个我写好的脚本:

https://www.chuyouxiang.com/archives/760一键自动化设置压缩纹理格式)


04

总结



在实际项目中的测试结果是,单图、自动图集、TexturePack 合图加起来超过两千张图片的 Creator 工程,使用 PNG 时打出来的 apk 包大小近 500M,内存占用 1.3G。采用压缩纹理后,包体大小降到 150M,内存占用降到 600M。

  • 压缩纹理的初始文件大小比 PNG 大 1-2 倍,但经过 zip 或打包成 apk、ipa 后,大小比 PNG 小了 1/2-1/3,对减小包体有巨大好处。 

  • 从 OpenGL ES 2.0 开始,GPU 纹理支持非 2 幂次方(例如,小于 2048 的图片比 2048 图片更节省内存),目前所有手机都已经是 OpenGL ES 2.0 及以上了。

  • 对于 Android 原生平台,要想兼容尽可能多的设备,又想发挥内存和包体优势,目前最佳选择是 ETC1。 

  • 对于 iOS 原生平台,PVR 画面质量不佳,如果只考虑 iPhone5S 及以上设备,则使用 ETC2 比 PVR 好。 

  • OpenGL ES 3.0 开始新推出一种 ASTC 格式,Android 和 iOS 都支持,画面质量比 PVR 好,且不要求纹理长宽相等和 2 的幂次方。ASTC 可能会是未来的统一格式,但目前很多 Android 低端设备还不支持。



以上是来自社区 Cocos Star Writer 楚游香的个人经验分享,大家可根据个人项目实际情况酌情使用。

至于压缩纹理在 Creator 中的配置方法、使用方法,以及对不同平台的支持情况等,可参考官方文档

https://docs.cocos.com/creator/3.0/manual/zh/asset/compress-texture.html

社区有许多大佬除了技术过硬外,独立做游戏好多年,不仅前端、后端自己搞定,还各种外服一起搞,感谢大佬们一直不吝分享自己的经验,普惠广大开发者,也希望更多的同学可以一起加入到我们的行列中。


05

直播预告



最后,本周五(3 月 19 日)晚 19:30,Cocos 引擎组放空老师将携神秘嘉宾在 B 站开展直播,带来关于《Cocos Creator 3.0 轻松玩转 npm 海量资源《FrontJS SDK,你的线上黑猫警长》等内容。

欢迎各位开发者准时围观,也欢迎大家提前准备关于 Cocos Creator 2.x 升级 3.0 所遇到的问题,引擎组会在直播间里为大家解答噢!期待您的参与!

最后,欢迎大家常在社区交流玩耍!

浏览 28
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报