第 10 章

第10章 全三维的代价(约 1995 年)

约翰·罗梅罗在走廊里站住,看着走廊尽头那扇门。门底下漏出一道光。白光,细长,稳定得像一根拉紧的弦。他手里的咖啡杯已经空了,杯底残留着一圈深褐色的渍迹。他在脑子里过了一遍今天——现在是晚上十一点二十分——他收到的那几封邮件。卡马克的提交说明。上午十点十四分,重构实体裁剪算法,提升场景遍历效率。下午四点零二分,修改光照贴图UV坐标生成逻辑。没有任何一封邮件超过三行。没有一封邮件以“罗梅罗”开头。它们只是出现在收件箱里,像气象台发布的天气数据,客观、精确、不针对任何人。他把空杯子放在走廊里一张没来得及搬进办公室的折叠桌上,推开自己的房间门。三台显示器亮着,左边的屏幕上是版本控制系统的提交日志,中间是《Quake》关卡编辑器,右边是上一次成功构建的测试截图——一个石砌大厅,拱形穹顶,悬挂的铁链,墙壁上跳动的火把光线。截图是五天前截的。

在今天的引擎版本里,同一个关卡文件渲染出来的是另一番景象:穹顶的多边形面片彼此穿透,铁链的末端悬浮在离天花板半米高的空气里,火把的光源偏移到了北墙之外,照亮一片虚空。他坐下来,打开提交记录。中午十二点三十一分,卡马克提交了新的渲染核心,改动了BSP树的构建逻辑。提交说明只有一行:“优化空间分割策略,减少渲染调用批次。”十二个单词。没有预先通知,没有设计团队评审,没有任何人被告知这个改动会让现有关卡几何体的面片索引失效。罗梅罗的团队在过去十天里搭建的三个关卡原型全部无法在当前版本中正常渲染。不是画面质量下降——是顶点坐标不再指向正确的多边形,纹理坐标在表面上游移,光照计算把阴影投在几何体不存在的面上。编辑器读得懂文件格式,引擎画不出文件内容。他关掉提交记录,在编辑器里打开其中一个关卡。城堡大厅。他把视角切换到线框模式,那些代表墙壁、拱门、台阶的绿色线段仍然存在,它们在文件里被精确地记录着。但引擎读取它们的时候,顶点顺序错了。

本该构成凸面的四个点变成了交叉对角的两个三角面,中间漏出一个空洞。他把鼠标移到那个空洞上,在三维空间里旋转视角,看它从不同角度显现出来。每一个角度都看见同样的东西:一个缺口。一个引擎无法闭合的空间。他在键盘上敲了几下,开始手动重新排列顶点索引。一个一个面片地修复。编辑器里每个面片由三个顶点组成,每个顶点的坐标值是三个浮点数,浮点数的精度受到引擎数据结构里坐标缩放因子的约束。他做这件事的时候脑子很安静。不是因为专注,是因为他知道愤怒没有用。他和卡马克合作了五年,他知道卡马克不回应愤怒。卡马克回应数据。如果你能证明一个改动的负面影响大于它的效率收益,他会撤回去。如果你不能——如果他的改动在性能预算上的收益是显著的,而关卡几何体的破损被视为编辑器层面的适配问题——对话就结束了。不是他拒绝讨论。是他已经完成了计算。六十分钟后,他修复了大厅穹顶的大部分面片。还剩下一个区域,靠近北墙上方。

这时候门被推开。阿德里安·卡马克走进来,手里拿着一沓打印出来的测试截图。他三十五岁,比罗梅罗和卡马克都年长,是id Software的联合创始人之一,负责所有的美术和视觉设计。他在Softdisk的日子里就和这两个约翰一起工作了,1987年,他受雇于Softdisk,在那里他既是程序员又是软件杂志月刊的编辑。他和他的同事约翰·罗梅罗、约翰·卡马克、汤姆·霍尔一起创立了id Software,并且作为创意指导和设计师进行工作。

他在公司里的角色介于两个极端之间:他不是卡马克那样的底层架构建造者,也不是罗梅罗那样的肾上腺素传教士。他是一个画家。他关心一件东西看起来是否对。在《Doom》时代,这意味着精灵动画的帧数、尸体贴图的朝向、墙壁纹理的拼接无缝度。在《Quake》时代,这意味着全三维空间里的多边形模型、骨骼动画、动态光照和粒子效果。意味着复杂度跃升了不止一个量级。“你看看这个。”阿德里安把截图放在键盘旁边。截图上是食人魔的模型。阿德里安为这个怪物花了两周时间——概念草图、黏土模型、多边形建模、骨骼绑定、纹理贴图、动作测试。在上一版引擎里,食人魔的动作流畅,左臂挥击的轨迹自然,死亡动画里身体倒下的重心转移看起来很真实。在当前版本里,左臂在挥击的第三帧开始穿过胸腔,手掌从肋骨位置穿透出来,手指张开。像一个解剖学标本被投错了影。“骨骼绑定接口变了。”罗梅罗说。这不是问句。“坐标系的缩放因子。卡马克今天下午改的。他在提交说明里写了。”

“你看到了?”

“看到了。写得不够详细。我以为影响范围在动画后期处理模块。实际影响在骨骼变换矩阵里。我用了四个小时重新绑定了肩关节和肘关节的坐标约束,做完之后右膝盖又出了问题。现在整个下半身的动作链都在抖动。”

阿德里安的语调平稳。他不是来抱怨的。他和罗梅罗一样清楚抱怨的无效性。他是来确认问题范围的。食人魔的模型需要从头重建骨骼绑定,这意味着他的进度表上要抽走几天时间,意味着其他怪物的建模进度会往后推。他要确认罗梅罗知道这件事,因为关卡设计需要怪物,怪物需要动作,动作需要骨骼。这是一条依赖链,链的顶端是卡马克办公室里的那台电脑。“我今晚做不完三个怪物,”阿德里安说,“下周三之前只能给你一个。食人魔。僵尸和骑士往后推。”

“僵尸可以先给我一个简化版。不需要骨骼。用顶点变形做攻击动作。”

“那样会看起来很僵硬。”

“僵硬没关系。我需要怪物放置坐标和碰撞检测数据。等你骨骼做完再替换动画。”

阿德里安想了想,点头。这不是他想要的解决方案。作为一个画家,把不完美的作品放进游戏里让他不舒服。但他也知道罗梅罗的压力。关卡设计不能停。一旦关卡设计停下来,整个项目的可见进度就归零了。威尔伯那边在和出版社谈判,《Quake》的发行协议要求春季之前拿出可玩版本,出版社的市场部门正在紧张地盯着开发周期。威尔伯不是技术人员,他没办法向出版社解释为什么一个骨骼绑定接口的变更会导致三个月延期。他能说的只有进度。进度数字在报表上是阿拉伯数字,不附带技术注释。阿德里安离开后,罗梅罗继续处理城堡大厅的关卡。他在编辑器里放置了怪物触发点——玩家走到某个坐标,食人魔从门后破墙而出。这个机制在《Doom》里很简单,一个触发线,一个怪物衣柜,玩家踩线,墙壁升起,怪物冲出来。在《Quake》里,破墙效果需要墙壁本身的多边形面片做碎裂动画,碎片要分离、旋转、下落,同时产生粒子效果和声音。

威尔伯不是技术人员,他没办法向出版社解释为什么一个骨骼绑定接口的变更会导致三个月延期。他能说的只有进度。进度数字在报表上是阿拉伯数字,不附带技术注释。这让他想起1991年1月,id团队拿到第一张版税支票时——天极支付的10,500美元。那时他们以为可以全职开展事业,无需为Softdisk打工。霍尔和他担心,若不礼貌地告知Softdisk,很可能会招至诉讼。但罗梅罗和卡马克认为,没有可以被起诉的资产,此想法纯属多虑。不久,卡马克与雇主、Softdisk持有人阿尔·维科维斯发生冲突。团队工作日渐浮躁、不上心,且数次申请升级电脑,维科维斯已有所怀疑。公司其他雇员也告诉维科维斯,团队在私自开发游戏。他认为卡马克不擅说谎。卡马克坦诚,他们用公司电脑开发《指挥官基恩》且不感到愧疚,并计划全员离开公司。数周谈判后,id团队承诺每两周为Softdisk开发一款游戏,并于1991年2月1日创办id Software。那时的技术债,如今已变成引擎重构的代价。

每一个碎裂的多边形面片都是一个独立的实体,要在物理系统里注册质量、速度、旋转惯量和碰撞边界。引擎的实体数量上限——卡马克在上周的一份技术说明里写了——单场景同时存在的动态实体不得超过一百二十八个。一面墙壁的碎裂动画至少需要十二个碎片。一个食人魔需要二十个多边形面片做身体部件。加上玩家发射的弹药实体、弹壳掉落、血液粒子、掉落的物品——一百二十八的上限在复杂的战斗场景里很快就会被用完。罗梅罗在编辑器里布置了一个战斗场景:玩家进入大厅,触发两个食人魔破墙而出,同时从高处的走廊上出现三个僵尸射击弩箭。五个怪物,两个破墙事件,二十四片碎石,弩箭在空中飞行的轨迹实体,玩家发射的弹药——总数在一百到一百二十之间。踩在边缘线上。他在测试模式里跑了几遍,每一次跑到破墙触发的瞬间,画面帧率都会掉到二十帧以下,持续零点几秒,然后恢复。这个掉帧在单机模式下可以接受。在网络多人模式下——他的大脑自动计算出网络同步这些实体状态的数据包大小——不行。

他把破墙效果从一个改成两个。关掉一个食人魔的碎石动画。怪物现在不是破墙而出,而是门打开,它们走出来。像一个舞台上的演员通过正常的出口上场。失去了惊吓效果,失去了环境破坏的实感,但节省了十二个实体。他把这十二个实体配额留给了弩箭轨迹,因为玩家需要在视觉上判断远程攻击的来源。这是设计上的取舍,不是在完美和瑕疵之间选择,而是在几种不同的瑕疵之间选择哪一个对核心体验损害最小。晚上一点过后,罗梅罗去了茶水间。整层楼的灯大部分关了,只剩下走廊里的应急照明和美工区阿德里安桌面上的一盏台灯。阿德里安还在那里,面对着一个灰度纹理在Photoshop里放大到像素级别,用笔刷逐一修正纹理接缝处的不连续。他做这件事的时候身体纹丝不动,只有右手手腕在数位板上细微移动。他在这栋黑色玻璃大楼里度过了过去几个月的几乎所有白天和夜晚,为《Quake》创建纹理库——石墙、木门、铁栅、地砖、血渍、哥特式窗花。

每一张纹理都要符合二的幂次方尺寸限制,每一张都要在内存预算内挤出一席之地,每一张都要准备多套分辨率变体以适应不同硬件配置。罗梅罗倒了一杯咖啡站在他身后看了一会儿。屏幕上是一扇哥特式窗户纹理,灰度,均匀,没有色彩。罗梅罗记得这扇窗户的彩色版本——阿德里安在几个月前做过一版,深蓝和血红的几何碎片,模拟中世纪教堂的玫瑰窗。但引擎的光照系统在处理彩色玻璃纹理时会产生灰度值不均匀,导致光照贴图出现色阶分离。卡马克建议使用均匀灰度临时替代,等项目后期优化光照模型后再恢复彩色版本。“彩色版本还留着?”罗梅罗问。“锁在备份图层里。”阿德里安用触控笔点了点屏幕上一个不可见图层的图标。“光照模型优化之后可以切回去。”

“什么时候?”

“他说透明水面之后。三周。可能四周。”

三周或四周。这是卡马克给出的时间框架,是从他的优先级列表里推导出来的派生日期。但在id Software没有正式的项目时间表,只有卡马克的优先级列表。这个列表不是写在会议室白板上的,不是讨论出来的,不是投票决定的。它存在于卡马克的脑子里,偶尔以邮件形式部分披露,每次披露的内容都可能在下一次引擎重构后改变。透明水面在骨骼绑定之后,光照模型在透明水面之后,粒子系统上限的优化在光照模型之后。每一项都需要时间,每一项都合理,每一项都依赖于前一项的完成。阿德里安的彩色玻璃排在第四位。罗梅罗回到自己的办公室,关上门。他坐在黑暗里,只有三台显示器的光照着他的脸。左边屏幕上是版本控制系统的日志,一行一行提交记录从下往上排列,像地质层积岩。每一行记录旁边都有时间戳:凌晨两点三十一分、凌晨四点十七分、清晨六点零五分。卡马克的工作时间不是昼伏夜出——昼伏夜出的人还有一个“伏”和“出”的节律。卡马克没有节律。

他会在任何时间开始工作,在任何时间停止,睡眠时间随机分布,吃饭时间压缩到最短。他的办公室里有冰箱,里面有外卖送来的食物,他不需要离开房间来维持身体运转。整层楼的其他人都是白天来晚上走,或者晚上来白天走——他们和外部世界之间还有一种松散的耦合。卡马克没有。他的时间完全由代码的逻辑分支和编译周期决定。罗梅罗在右边屏幕上打开了一个文件。不是《雷神之锤》的关卡。是CROSS.WAD。一个玩家自制的《毁灭战士》关卡,去年通过id的FTP服务器流传出来的众多自制关卡之一。他保存这个文件不是因为它的设计出色——它的设计很粗糙,一个巨大的十字形走廊,四条臂膀通向一个圆形大厅,在战术上是自杀式的,玩家在中央会同时暴露在四个方向的交叉火力下。他保存它是因为它的符号意义:一个匿名的玩家,用id提供的工具,制作了一个他想象中的形状。一个十字。一个在他脑子里盘旋了很久的东西。安德鲁·威廉姆斯在2017年著作《数字游戏史》中称,和之前的平台电脑游戏不同,《指挥官基恩之沃提康入侵》不是把屏幕片段拼接起来,而是营造了玩家「轻松移动」探索开放大空间的感觉;那感觉如今被锁在引擎的精度里。

他把那个十字放进了《毁灭战士》的二维平面引擎里,引擎没有阻止他。因为《毁灭战士》的引擎是稳定的。它的限制是已知的、固定的、写在文档里的。你不需要担心某天半夜的一次BSP树重构让你的十字形走廊的墙壁出现空洞。你画一条线,它就一直在那里。罗梅罗关掉CROSS.WAD。关掉版本控制日志。只留下中间的关卡编辑器。屏幕上是城堡大厅的线框网格,那些绿色的几何线条在灰黑色背景上缓慢旋转。他想到了昨天——还是前天?——他在走廊里对威尔伯说“春季之前”。他说出口的时候音量正常,语速正常,听起来像一句承诺。现在这句话在他脑子里重新播放,音质变得不同。春季之前。

引擎要稳定到关卡设计可以规模化推进的程度,阿德里安的怪物骨骼系统要稳定到不会因为下一次接口变更而爆炸的程度,武器系统的伤害数值要和碰撞检测的精度匹配,死亡竞赛地图的实体密度要和网络同步的带宽限制匹配,被删掉的动态光源要在某个时间点加回来,被简化成平面的壁龛要恢复成弧形的拱门,今天凌晨手动修复的那二十几个顶点索引可能在明天的新提交之后再度失效,然后一切重来。所有这些事情要在春季之前完成。不是不可能。是他不敢算概率。走廊尽头那扇门底下仍然漏着光。卡马克还在那个没有装饰的房间里。他可能在处理透明水面的折射计算,可能在优化渲染通道的调用顺序,可能在修补网络同步协议的一个边缘竞争条件。他做完之后会提交一个新版本。提交说明会是三行字:做了什么,为什么做,性能收益百分比。然后第二天的某个时间,罗梅罗会打开某个关卡文件,发现某样东西不再能正确渲染。他会检查提交记录,定位改动来源,评估影响范围,然后决定是手动修复还是简化设计。

这个循环在过去几个月里已经重复了足够多次,多到他开始在不打开提交记录的情况下就能预判哪些类型的引擎改动会破坏哪些类型的关卡几何体。这不是卡马克的错。罗梅罗很清楚这一点。卡马克不是故意在设计上制造障碍,不是不在乎罗梅罗的困境。如果他不在乎,就不会在凌晨四点修复骨骼绑定接口的坐标系兼容性问题,就不会在下一个版本里加上对斜坡地形上大型实体碰撞检测的特殊处理,就不会把阿德里安的彩色玻璃放在优先级列表上,等着光照模型优化之后恢复。他在乎。他只是在乎的方式不同。对他而言,引擎是建筑的地基,地基的每一块石头都必须精确到毫米,因为上面要承载整个结构的重量。罗梅罗在设计穹顶的弧度和壁龛的细节,他抬起头发现地基在移动。不是快速移动,不是有意移动——是每次移动几毫米,累积起来,墙就裂了。罗梅罗从显示器边框上撕下那张黄色便签纸。

上面用铅笔写着他过去三周对城堡大厅关卡做的提交统计:十九次提交,十四次被动适配引擎变更,三次因性能限制被迫修改设计,两次主动优化布局。十四,三,二。他把这张纸揉成一团扔进废纸篓,然后又捡出来,展开,放进一个抽屉里。抽屉里还有别的便签纸,别的数字统计。他不确定自己为什么要保存这些。也许是为了以后有一天给别人看:你看,我们当时是在这样的条件下做出来的。也许只是为了给自己看:这确实发生了,不是你夸大了。凌晨三点,他听到走廊里有脚步声。不是卡马克——卡马克不需要离开他的房间。是约翰·卡什,《Quake》的网络程序员。卡什从程序员隔间那边走过来,手里拿着几张打印纸,上面是今晚多人测试的网络数据包捕获日志。他看到罗梅罗办公室的门开着,里面亮着灯,拐进来。“竞技场的第二次测试结果。”卡什把打印纸放在桌上。罗梅罗拿起来看。测试场景是他今天调整过的那个死亡竞赛竞技场——中央区域的三个动态火把减到一个,高级武器刷新点挪到了东北角凹陷处。

测试环境是四个玩家,两个局域网,两个通过调制解调器从城区的另一栋建筑连接。结果:局域网流畅,调制解调器连接在玩家进入竞技场中央时仍然出现延迟尖峰,两百毫秒。原因是中央区域剩下的那个火把的动态光照数据与实体状态数据在网络帧里产生了同步竞争。一个动态光源,在四个玩家的客户端上各自产生一组光照计算,这些计算的结果要在网络帧里和玩家位置、武器状态、弹药数量、怪物AI决策一起打包传输。数据包的优先级排序算法在某个边缘条件下把光照数据排到了实体数据前面,导致玩家的移动更新延后了一个帧周期,延迟从四十毫秒跳到两百毫秒。卡什已经给卡马克发了邮件。卡马克回复了:网络栈优化暂时无法解决多动态光源同步竞争,需在引擎后续版本中重构网络帧优先级调度算法。短期解决方案是减少该区域动态光源至零个,或使用静态预计算光照替代。零个。罗梅罗盯着这个词。一个竞技场没有动态光源意味着什么?意味着火把不会在墙壁上投射跳动的影子。意味着怪物走过时光线不会变化。

意味着石墙的纹理在火光下不会产生明暗的细微波动。玩家走进这个空间,视觉上会感觉到某种不对劲——不是因为画面难看,而是因为画面太静止了。人类的视觉皮层习惯了光线的微小变化,哪怕注意不到,大脑也会感知到。当光完全静止,空间的材质就成了塑料。他打开编辑器,删掉最后一个火把。在原本火把的位置放置了一个静态环境光——一个没有动态计算、没有实时投射、只是一个均匀亮度值的点。它照亮了竞技场中央,但没有阴影,没有跳动,没有怪物经过时遮挡光源产生的明暗变化。像一个日光灯管下的停车场。他运行了一遍测试模式,在竞技场里移动。一切正常。帧率稳定。网络测试结果会改善。四个玩家不会在中央区域遭遇延迟尖峰。代价是竞技场的中央从一团跳动的火焰变成一个均匀的灰色光斑。他在测试模式里站了很久,角色静止在竞技场中央,抬头看着天花板。原本火把的位置现在是一个灰色的光点。他按下了截图键。

然后退出游戏,打开截图文件,把它保存在一个文件夹里,文件夹名称是“Quake_Lighting_History”,里面已经存了十几张截图,记录着这个竞技场的光源从三个变成两个变成一个变成零个的每一次变化。他看着这些截图按时间顺序排列,像是在看一部关于光如何慢慢消失在《Quake》世界里的动画。凌晨四点,卡什走后,整层楼彻底安静了。阿德里安的美工区台灯熄了,他已经离开。威尔伯在一楼的商务办公室也早就关了门。只有走廊尽头那扇门底下的白光仍然亮着,像一根绷紧的神经。罗梅罗从抽屉里拿出一张空白光盘,把今天的关卡文件刻录进去——城堡大厅v6,竞技场v4,还有几个还在早期搭建中的地图草稿。他给光盘贴上标签,用黑色马克笔写上日期。然后把光盘放进抽屉,和其他几张已经刻录过的光盘放在一起。最早的一张日期是三个月前。三个月前,城堡大厅还是v1。那时候引擎没有BSP树遍历重构,没有光照贴图UV坐标生成逻辑变更,没有骨骼绑定缩放因子调整。

v1的拱顶是完整的,铁链挂在正确的位置,火把有三个。他那时以为那个版本会在最终产品里出现。他关掉显示器。房间陷入黑暗。然后他站起来,推开办公室门,走进走廊。走廊里铺着地毯,脚步声被吸收成低沉的闷响。他在距离走廊尽头那扇门三米的地方停下来。门缝下的光在他运动鞋的鞋尖前面投出一条明亮的细线,把走廊的地毯分割成明暗两个区域。他站了几分钟。卡马克在门后面,可能在处理透明水面折射的纹理采样优化,可能在修补网络帧优先级算法的另一个边缘条件,也可能只是在盯着屏幕上一段无法通过编译的代码,大脑在运算可能的原因。不管他在做什么,他知道门外没有人。罗梅罗不会敲门。罗梅罗转身走回去。在走廊中段,他经过阿德里安的工作区。从门口可以看到阿德里安桌上的数位板,旁边放着一叠打印出来的纹理参考图。最上面一张是中世纪彩色玻璃窗的历史照片——巴黎圣礼拜堂的玫瑰窗,深蓝、血红、金黄的光谱在照片里呈现出一种几乎不可能的饱和度。

照片旁边是阿德里安画的灰度版本,同样的几何切割,同样的铁栅线条,所有的颜色被抽走,变成从白到黑的二百五十六级灰阶,像一张建筑的X光片。罗梅罗站在门外看了一会儿,然后走回自己的办公室。他推开门,在黑暗中坐回椅子上。没有开显示器。只是坐在那里,听着服务器机柜的嗡鸣声透过墙壁传过来的低频震动。这栋黑色玻璃大楼的隔音效果很好,好到你听不见隔壁房间的键盘敲击,听不见走廊尽头的代码编译警告音,听不见茶水间咖啡机的水烧开的咕嘟声。墙吸收了所有的声音。还吸收了别的——那些在会议桌上没有展开的设计讨论,那些在邮件草稿箱里被删掉的抗议,那些在凌晨三点独自面对十九次提交记录时涌上来的、没说出口的、找不到收件人的话。这栋楼把它们全部吸收了,储存在墙体的石膏板和隔音棉之间,变成一种静默的质量,压在每个留下来加班的人的后脑勺上。他重新打开显示器。

屏幕亮起的瞬间,城堡大厅的线框网格图重新出现,那些绿色的几何线条安静地从当前角度展示着它们的结构——经过六次修改后的结构。穹顶弧线被简化了,壁龛被填平了,北墙上方那个无法修复的复杂交界面被替换成了平面。它不再是五个月前罗梅罗在设计文档里画的那个哥特式大厅的概念图。但它能在引擎里正确渲染。它能在玩家跑过时保持帧率稳定。它能容纳那些因为实体上限而改用门替代破墙的食人魔,容纳那些因为网络同步压力而被迫改为静态的火把光线。他把这张线框图截下来,新建一个文件夹。文件夹的名字改了三次。第一次叫“妥协”,删掉了。第二次叫“适配”,删掉了。第三次他没有输入任何名字,只是按了一个下划线,一个短横,然后点下确定键。一个没有名字的文件夹,里面存着一张没有色彩的线框图,来自一个还不知道要经历多少次引擎重构的游戏。他点击保存。然后靠在椅背上,用手掌压住眼睛。掌心的黑暗里有细小的光点在视网膜上漂浮。

那些光点是他看着屏幕上的绿色线框太久的残影——它们排列成线框的形状,在黑暗的背景上继续旋转了几秒钟,然后慢慢消散。走廊尽头那扇门缝下漏出的白光仍然在那里,透过紧闭的眼皮也能感觉到它的亮度。它穿过走廊的空气,穿过他办公室门缝的间隙,在黑暗中形成一个模糊的、遥远的、不肯熄灭的记号。那道光不需要睡眠。它有自己的时间,那是引擎核心的时钟频率,是代码在凌晨的编译周期,是一个正在被他建造出来的圣杯的重量。它的光芒透过门缝,照在铺着地毯的走廊上,而整栋黑色玻璃大楼的隔音墙壁里,储满了所有没有发出的邮件和所有没有敲响的门。