« Lua 中 Cache 冷数据的落地 | 返回首页 | 如何优雅的实现一个 lua 调试器 »

ETC 图素的合并

在制作 2d 游戏时,通常我们需要把大量小图素合并到一整张大贴图上。这可以使用装箱算法 (Bin Packing)完成。当然,很多人很懒,那么就用别人做好的工具,比如 Texture Packer 。

但是在实际开发中, Texture Packer 有几个严重的缺陷 ,我个人还是建议自己来做合图的工具,完善工具链。

缺陷 1 :装箱过程其实并不需要了解图片上的内容,而只需要知道图片的尺寸。所以装箱过程需要的内存量应该只和被装的图素个数相关,和图片大小无关。而 texture packer 并不是这样做的,它把装箱和合成贴图两部工作放在一个黑箱里了,会导致运行时无谓的内存消耗(更不用说它本质上是一个 GUI 程序),不是很适合自动化工具链。

缺陷 2 :如果要求最终合并的图是 pvr 或 etc 压缩贴图,那么还需要最后再对目标图做一次压缩。通常这个压缩过程是比较慢的。

这个缺陷 2 在开发期需要反复打包资源时,对开发效率影响尤其大。但其实如果自己好好设计工具链,是完全可以避免的。

下面就谈谈应该怎么处理 ETC 这类压缩贴图的合并问题。

ETC 这类压缩贴图,内部其实是按 4x4 像素为一个单位区分开的。各个单元之间没有相关性,也只有这样,显卡才能快速处理。所以,完全没有必要在合并图素后,对目标大图做压缩。

正确的做法是,为小图生成对应的压缩数据,好比编译器将 .c 文件 编译成 .o 文件;而装箱合图的过程好比链接器,将压缩后的小图合并到目标贴图上去。

开发过程中,每次修改,主要针对的都是部分小图素;甚至只是添加新的图素,而并没有改动老的。所以这样处理可以极大的减少每次合成大贴图的时间。而装箱程序,只需要输入每个图素的尺寸,输出目标图上的排列就够了,然后用图像处理工具根据装箱布局去组合小的压缩过的图像数据,合成最终的贴图。

我们可以找到一些开源的工具来压缩图素,比如 Ericsson 开源的 etcpack 这个实现的非常糟糕,但用的人很多的工具。这个工具可以把图片文件转换成用 ETC 算法压缩过的数据,生成一个后缀为 .ktx d额压缩图片文件。

我今天写了一个 lua 库,帮助你完成合并多个 .ktx 为一个 .ktx 的过程。

如果真想看一眼的话,那么它的代码在 github 上,它没有人维护,没有使用说明,没有注释,没有测试,也不保证运行结果正确。当然如果你发现有 bug 的话,又乐于修正的话,提个 pull request 还是很欢迎的。

Comments

哎哟,我的工具好像正好可以用上。不过我最近没有时间折腾工具了,先凑合用了。感谢云风分享这些非常实用的技能。
然后你怎么动态合并,使用texutrepacket之前得到的plist进行合并吗?
2d游戏使用有损不担心图片质量吗?好的做法应该不是把用到的图片都载入到显存而是只载入当前显示的部分。
有机会找你指点下有关2d的游戏
to 酿泉 找Array Texture的时候看到过bindless texture, 不过这个貌似还不是标准, 只能算扩展, PC上的兼容性都很差, 更不用提OpenGL ES.
to dwing 可以看 bindless texture.
续楼下: 找了一下, OpenGL还真的支持过纹理数组(Array Texture), 估计OpenGL ES 2.0可能不支持, 需要3.0才行.
其实从本质上来讲, 我感到奇怪的是为什么一个drawcall只能同时访问一个或有限的几个纹理数据, 而不能在一个drawcall里高效地定位显存中很多的小纹理呢. 解决了这个, 合并纹理就全无意义了.
TexturePacker有提供命令行工具

Post a comment

非这个主题相关的留言请到:留言本