Minecraft 设计思想
卷三 · 技术实现呈现与交互

客户端与渲染

从方块到三角形的拼装流水线;网格、剔除与透明的取舍;资源包证明表征可换;优化模组用数倍帧率证明原版有债——民间承担了官方实现的一半。

本章命题:原版渲染的保守是排序而非能力——在「系统正确性、兼容性、渲染先进性」的优先级表上,渲染常年垫底,欠下的债由民间优化模组代偿;优化模组在不改游戏语义的前提下把帧率翻上数倍,证明这债是选择出来的,不是不可避免的。若原版渲染债是底层架构的必然,优化模组就不可能在语义不变的情况下存在——它们存在,即是证伪。

1问题

同一台电脑,同一个存档,装上某个社区优化模组,帧率翻上两三倍——这是 Minecraft 玩家圈人尽皆知的体验。用别的游戏类比一下就知道这件事多反常:没人能给一个 3A 大作装个「帧率翻三倍」的补丁,因为那类游戏的渲染已经把硬件榨干了。

Minecraft 能被这样优化,只有两种解释:要么民间开发者是魔法师,要么原版的渲染留有巨大的效率余地。答案是后者,而且这个余地是历史与优先级共同选择的。本章把渲染这门手艺从「把方块变成屏幕上的像素」讲起:世界如何被拼成三角形、哪些东西被聪明地不画、透明为什么难缠、资源包如何证明表征可换,最后看优化模组现象对「官方与社区分工」这个全书主题的又一次印证。

2看得见的世界如何被拼出来

显卡只认识一种语言:三角形。任何画面——人物、水面、山——最终都是无数小三角形拼出来的。Minecraft 的方块世界在显卡眼里因此是一道翻译题:把几千万个方块,翻译成十几万个三角形,而且要翻译得足够快(每秒几十次)。

翻译的核心动作叫网格化(meshing):把一个区块(16×384×16 的柱体,卷三第 1 章)里所有「会被看见的表面」提取出来,拼成一张顶点表,一次性交给显卡。注意「会被看见」四个字——被泥土完全包住的那块钻石,它的六个面一个都不用画。一个表面是否可见的判定极其简单:它挨着的邻居方块如果不透明,这个面就藏着,跳过。整张区块网格,就是这样一面一面「问邻居」问出来的。

网格化之后,这张顶点表在区块不变时可以反复使用——玩家改一方块,只需重算那一小块的网格。于是渲染的日常成本被摊成了两类:静态成本(存好的网格,画出来即可,便宜)与动态成本(网格的重建,贵,但只在世界变化时发生)。玩家挖一块方块的那一下「闪烁」,就是一次小规模的网格重建。

3渲染简史:一条落后业界十年的演进线

Minecraft 的渲染架构跟过 OpenGL 的几代潮流,但每一步都比图形工业界慢半拍:早期用最古老的方式逐个画,后来学会把顶点批量打包(批处理),再后来跟上现代的可编程管线——每一步都是必要的现代化,每一步也都发生在社区已经用模组演示过之后或业界普及多年之后。

最古早的那一步值得讲透,因为它解释了「批处理」为什么是渲染优化的第一定律。显卡与 CPU 之间隔着一条昂贵的通道:每次「调用显卡画点东西」(专业术语 draw call)都要走一遍握手、递交、确认的流程,通道成本远高于画一个方块本身的成本。早年的渲染是「一个方块一次调用」——几万个方块就是几万次握手,显卡大部分时间在签收文件而不是画画。批处理的思路是把成千上万个方块的数据打包成一次调用——握手一次,整批画完。这就是为什么「区块网格」(上一节的产物)那么重要:它天然就是现成的批次。这一改不改玩法、不改存档、玩家毫无感知,帧率却天差地别——渲染优化里性价比最高的一类工作,永远在这条通道上做文章。

这条慢半拍的演进线是本卷「技术债」命题的又一例证:渲染不是这个产品的竞争要地。Mojang 的工程资源长期优先投给生存、多人、世界格式这些「玩法正确性」问题;渲染只要「能看、不挡玩法」就排不上号。十几年积下来,就形成了一个奇特景观:一款画面极简的游戏,反而是「装模组能大幅提升性能」纪录的保持者——简陋的画面与低效的画法,是两回事。

4网格、剔除与透明的取舍

渲染省钱的学问,大半是「少画」的学问。专业名词叫剔除(culling),玩家可以把它翻译成「不画看不见的东西」。它有三个层次,Minecraft 的原版完成度依次递减。

背面剔除:显卡自带,任何面都只画正面——免费。视锥剔除:你视野之外的区块整个不画——原版做得不错,这就是为什么把头埋进沙里帧率会涨。遮挡剔除:被山挡住的村庄,理论上一个三角形都不用画——但判定「被挡住」本身需要额外的空间结构,原版长期只做了最粗略的版本。你翻过一道山脊、身后的整片基地明明看不见却还在被画——这笔浪费,就是优化模组的第一桶金。

透明是另一个臭名昭著的难点。水与玻璃是半透明的,而半透明物体的绘制顺序会影响结果(先画远的再画近的),排序在三维空间里是出了名的麻烦。原版的取舍是按区块为单位粗略排序——够用,但凑近看会有可察觉的瑕疵(隔着多层玻璃看世界的微妙错乱)。优化模组的方案更精细但更复杂。这笔账再一次显示同一模式:原版选择「够用的正确」,把「精细的正确」留给社区。

把前面几节合起来,可以看到原版渲染的一个整体性格:它的每一个子系统——网格化、剔除、排序、批处理——都在「快而糙」与「慢而对」的光谱上各自取了一个偏保守的点,而且取点的逻辑一致:错误不能影响玩法,性能不能拖垮 2009 年的机器,美观与效率让位。这套取点在 2009 年是整体最优的;硬件涨了十倍、玩家的显示器涨了四倍、期望涨了不止十倍之后,那些取点就成了系统性的余量。优化模组做的事情,本质上不是「发明新技术」,而是在每条光谱上把取点向另一端移动——移动的空间是原版留出来的,移动的方向是硬件进化指出来的,移动的手是社区伸出来的。

至于业界那招最著名的省钱术——贪婪网格化(把相邻的同种材质表面合并成大面,成倍减少三角形数)——原版至今没有全面采用。原因是真实的工程权衡:合并之后的表面在做逐顶点光照、贴图对齐、AO 阴影时会遇到一串复杂度;而对 2009 年的机器,未合并的网格本来也跑得动。当年合理的选择,在硬件与期望都涨了十倍后成了债——债没有恶意,它只是过期资产。

5资源包:表征层的官方接口

卷二第 1 章做过「换皮测试」:把表现层整个换掉,结构关系照旧成立。资源包就是这场思想实验的工程实现——贴图、音效、模型、字体、甚至方块的样子,全部可以替换,而游戏规则一个比特都不动。

它的架构意义比玩法意义大:资源包是官方给「表征与结构分离」签的正式合同。玩家社区用它完成了海量的二次表达(写实风、卡通风、恐怖主题的整套换皮),而本书更看重的是它证明的架构性质——Minecraft 的「样子」从来不等于「它是什么」。卷二第 1 章说像素是皮肤、网格是度量衡;资源包就是这句论断的官方实现。

资源包之外,社区还把表达欲推到了更深的层:光影包。它换的不是贴图而是「画法」本身——体积云、动态阴影、水面反射,极限作品甚至用路径追踪把方块世界渲染出照片级的光照。光影包的载体的演化本身就是本卷主题的缩影:它起于模组(改渲染管线的客户端模组),后来官方在原版加入了着色器接口让它有了正统的挂载点。贴图换样子(资源包),管线换画法(光影包),两层都换而游戏还是那个游戏——表征层的可替换性被社区一路测试到了极限,而底下的玩法结构纹丝不动。这是「换皮测试」做过的一切实验里,规模最大、耗时最长、结论最稳的一次。

6优化模组:民间官方实现

现在收拢开头的问题。优化模组(从老牌的 OptiFine 到近年重新定义「能跑」的 Sodium 一系)在不改任何游戏语义的前提下,用更聪明的网格化、更彻底的剔除、更现代的批处理,把原版的帧率翻上数倍。这一现象的证据价值有三层。

第一层,它证明了原版有债——而且是纯渲染层的债:这些模组没有改玩法,没有改存档,没有动红石的一根线;它们只动了「把世界画出来」这一层,就榨出了数倍性能。第二层,它证明债是可以还的——语义不变的渲染重写是可能的,原版的保守不是架构宿命。**第三层,也是对全书主题最重要的:它证明了民间可以承担官方实现的一半。**第 5 章的服务器章写过 Paper 之于原版服务端的关系——「民间官方实现」;渲染层的优化模组是同一物种:大量玩家日常玩的其实是「社区渲染 + 官方玩法」的混血版本,而官方与这些实现保持着一种默契的共生——社区先行验证方向,官方在后续版本吸收其思路(近年官方版本的渲染优化,确实在朝社区验证过的方向走)。

这层共生关系对「技术债」话题的最终修正值得记下:技术债不总是要还得——当你的生态里有足够强的民间工程力量时,债可以外包。Mojang 把渲染债外包了十几年,省下的工程资源投给了玩法与兼容,从产品结果看这是一笔精明的账。但它能成立的前提是那个前提本身:一个自愿无偿给官方修渲染的社区。这又是那个抄不走的答案了。

7这一章留下什么

  • 爱好者:装优化模组获得的那些帧率,不是魔法——是原版替你「省着没花」的余量,被社区捡起来花掉了。
  • 开发者:能抄走的是优先级排序的勇气——渲染先进性可以垫底,前提是你清楚自己什么必须最优(Minecraft 选了玩法正确性与兼容);以及「表征与结构分离」的架构合同(资源包)。抄不走的是代偿生态:渲染债外包的前提是民间有图形学高手愿意白干——找到这批人之前,先把债还了。

On this page