当我加入了Raylib 6x Game Jam时,我知道我想做一些3D东西。主题被宣布后,我决定解决我对程序化玩具如TownscaperTiny Glade的主要烦恼。 我想要至少有一些挑战 - 由紧密网格规则和结构色彩匹配依赖的空间策略谜题。 但我也希望玩家能够带着一份3D艺术作品离开。 这个解决方案是什么? 一种内置的导出器,让你可以从浏览器直接下载你的霓虹摩天大楼的glTF文件。 但是在疯狂的7天的竞赛窗口中建立一个导出器意味着你要以速度而不是大小来编码。 我的第一版输出了一个庞大的1.5MB glTF文件,其中包含1024个六边形棱柱。 在竞赛被锁定在投票期之后,我无法更新游戏的二进制文件。 我发现自己陷入了“超时周”,我决定唯一合理的做法是:模仿我的内心理查德·亨德里克斯,锁住自己在一个房间里,戴上我最喜欢的电子舞曲(Skrillex - Syndicate),打开“中间出”压缩gif,专注于纯粹的数据驱动优化谜题。 通过三个不同的阶段,我成功压缩了3D导出文件,减少了到70KB,仅比原始纯文本游戏存档文件本身大25KB。 这是如何追求完美威斯曼分数的分解。 # 阶段1:吃掉顶点汤(1.5MB -> 600KB) 在疯狂的7天的压力下,我脑子会默认到最容易的路径:dump一个原始的“顶点汤”。 对于每个单独的1024个六边形棱柱,导出器都会写出重复的、未索引的顶点坐标。如果两个三角形共享一个角,那么这些坐标会被写出两次。 第一步是实现顶点索引。通过定义一个唯一的顶点位置列表并使用轻量级的元素数组缓冲区来索引它们,我停止告诉文件每个角的位置了。 * 结果:文件大小从1.5MB减少到600KB。 * 教训:永远不要低估冗余几何坐标的重量。 # 阶段2:修剪JSON(600KB -> 中间里程碑) 在顶点索引完成后,我遇到了一个巨大的文本瓶颈。因为Neon Triad Tower是基于严格结构化的刚性几何六边形网格的,位置和偏移遵循严格的几何间隔。导出器花费了字节在JSON骨架、访问器、节点变换和其内包装的base64载荷上。 每个纯文本.gltf文件中的字符都花费一个字节的字符串空间,而数字就是特别需要的。 我也尝试了二进制glTF(.glb),但它仍然不是我想要的明显银弹。 有时文件格式就是一种饮食计划,有时就是一种不同的形状的烤饼。 # 阶段3:指向桶(中间里程碑 -> 70KB) 最后的优化之王是停止导出静态几何体而改用网格重用。现在,导出器写出每个唯一颜色桶的几何数据作为一个单独的,完美索引的六边形棱柱网格。剩下的文件大部分都是一个光荣的放置清单:1024个节点,携带着转换向量,每个节点都指向正确的桶网格,如一个守法的小官僚。 # 克服Draco压缩(在某些情况下) 最终测试一个优化文件格式是将业界标准压缩算法扔进它。 当我将谷歌的Draco压缩(KHR_draco_mesh_compression)应用到我的原始未索引顶点汤时,它轻松地将其压缩到22KB。 Draco在处理乱七八糟的浮点几何体时发挥作用,通过将其放在更紧密的数字饮食上,然后压缩剩余的尴尬。 但当我将Draco应用到我的最终70KB文件时?它无法将其压缩成一个字节。事实上,尝试将这个70KB.gltf转换为.glb实际上会使文件2KB更大因为GLB规范的刚性二进制填充头部比我的精简、削减的文本数据更昂贵。 我们设计了一个数据结构,完全缺乏膨胀和熵,专业压缩工具看起来根本没有什么可优化的,即使文件是完全有效的glTF。 今天,最大化六边形棱柱的最终glTF导出文件大小为70KB。 它可以立即下载,能够在web环境中运行,并可以放入Blender、Godot或web查看器如Babylon.js Sandbox或three.js编辑器。 # 实验膨胀:尝试CLI选项! 如果你想在反向看到优化数学,桌面/CLI版本的Neon Triad Tower包括标志,让你有意地重新引入膨胀。 默认情况下,导出器使用全网格重用和顶点索引来保持文件非常精简。 这是当你切换这些系统时你的导出文件大小发生什么变化: * --unique-shapes (禁用网格重用) * 它做了什么:阻止导出器在节点之间重用桶网格,并且直接将每个颜色桶的几何数据写入文件,因此大家都得带着自己的椅子。 * 大小惩罚:将你的文件大小从70KB增加到约600KB。 * --raw-vertices (禁用顶点索引) * 它做了什么:完全禁用顶点索引,并导出原始几何体,其中三角形不再共享角数据。 * 1KB的戏剧性转折:如果你只使用这个标志,实际上会将你的文件大小减少到1KB! 因为导出器仍然重用每个颜色桶的共享网格,并且丢弃索引缓冲区,会将二进制载荷和一些访问器记录减少。 * 相互作用的陷阱:当你组合--unique-shapes --raw-vertices时,微小的1KB节省会逆转。 --unique-shapes会阻止重用共享桶网格,并且--raw-vertices会从每个桶网格中去掉索引,导出器会写出每个桶的全世界空间几何体,文件会从70KB一下子跳到最大1.5MB顶点汤