第 15 章
实时光照的圣杯
2014到2016年间追逐实时光照圣杯的真正遗产,不是某一算法的胜利,而是引擎被迫承认自己永远找不到圣杯。这个反直觉的判断在2014年3月19日尚未进入任何人的视野——但那个关于“必须再次打破的契约”的问题,即将在接下来的三年里得到残酷的回答:G-Buffer架构确实被打破了,但不是被一种更优雅的实时算法打破,而是被预计算路线用空间换时间的策略绕了过去。
那天旧金山莫斯康展览中心的GDC主会场里,一种近乎庆典的气氛笼罩着满堂开发者——后排站满了人,两侧过道也被挤占。Epic Games创始人蒂姆·斯威尼走上台时,会场安静下来的速度快得不寻常。在场的工程师和美术师们知道,这一刻他们已经等待了近十年:虚幻引擎3在2004年亮相后历经数次迭代,但始终没有触及根本性的架构重写。而今天,虚幻引擎4将完整揭开面纱。
斯威尼没有用华丽的辞藻开场。他将一个中型场景加载进编辑器,点击了“构建光照”按钮。屏幕上,进度条开始移动。
几分钟后,场景中的间接光照浮现出来:光线在墙壁间反弹,暖色从一面砖墙渗到相邻的灰泥表面,天花板角落里的阴影带着柔和的渐变而非生硬的截断。这就是Lightmass,UE4全新的全局光照系统。
它的首次公开亮相并非以理论阐述的形式,而是以一个进度条的移动开始——这个细节本身就说明了预计算路线的本质:真实的光照需要时间,而开发者必须学会等待。Lightmass背后的工程逻辑是激进而诚实的。它并不试图在运行时实时计算全局光照——那在2014年的消费级硬件上仍然遥不可及。
相反,它将辐射度算法与光子映射混合,在离线阶段完成所有繁重计算。系统首先从每个光源发射虚拟光子,追踪它们在场景几何体间的反弹路径,在表面缓存光子能量分布;随后进入辐射度阶段,对光照贴图的每一个像素进行最终收集——采样周围光子的入射辐射度,计算出该点的间接光照颜色。整个过程完全在编辑器内执行,结果被烘焙进二维纹理,运行时只需一次纹理采样即可还原复杂的间接光照效果。
这不是一个新想法。光照贴图烘焙技术自1990年代就已存在,Quake引擎在1996年就使用了基于辐射度的光照预计算。但Lightmass将这一思路推向了工程极限。
它的光子映射实现支持多次漫反射反弹——不是一次,不是两次,而是可配置的多次,使得光线可以在场景中充分传播后再被收集。更关键的是,Epic构建了一套名为Swarm的分布式烘焙系统:一个场景的光照计算任务可以被自动分割,分发到局域网内的多台机器上并行处理。对于拥有数十台工作站的大型工作室,这意味着一个开放世界场景的全局光照烘焙可以从数天压缩到数小时。
Epic在UE4的官方文档中明确表达了这一技术路线的哲学立场:将场景中的几何体标记为静态,将光源标记为静态,然后让Lightmass在离线阶段完成所有繁重工作。运行时的成本几乎为零——只是一次纹理查找。这是预计算路线的极致形态:用空间换时间,用离线算力换运行时性能,用烘焙时的耐心换画面质量的确定性。
同一年,另一条预计算路线正在平行推进。Unity Technologies正在紧锣密鼓地整合来自英国剑桥的Geomerics公司的Enlighten中间件。
当Unity 5在2015年3月的GDC上正式发布时,Enlighten已经深度集成进引擎的渲染管线。它提供的同样是预计算全局光照,但技术路径与Lightmass截然不同。Enlighten的核心是预计算辐射传输的实时变体。它在离线阶段将场景几何体分割为表面区块——不是逐像素,而是以相对粗糙的区块为单位——然后预计算这些区块之间的可见性关系和光传输系数。
这个预计算过程生成的是一个传输矩阵:描述了场景中每一对表面区块之间,光能从一方传输到另一方的效率。在运行时,当光源的位置或强度发生变化,系统仅需更新直接光照的输入,然后通过这个预计算的传输矩阵实时求解出间接光照的近似结果。
这意味着在Lightmass的哲学里,改变一盏灯的位置需要重新烘焙整个场景——或者至少是受影响区域的光照贴图。而在Enlighten的哲学里,你可以移动光源,间接光照会实时更新。代价是精度:表面区块的分辨率远低于像素级,阴影边界和细节反射被模糊化处理。
但换来的是动态性——这在Unity所瞄准的移动端和中端硬件市场上,是一个决定性的差异优势。两条预计算路线在2014至2015年间形成了清晰的并置。Epic押注最高质量的静态场景渲染,适合那些拥有大量离线计算资源、追求电影级画质的AAA工作室。Unity押注实时动态光照,适合那些需要昼夜循环、可移动光源和交互式环境的项目——以及那些没有数十台烘焙工作站的小型团队。
然而,真正的范式压力并不来自这两条预计算路线之间的竞争。它来自开发者群体中正在积聚的一种渴望——对完全动态场景的执念。
2015年前后,三个趋势正在同时发酵。可破坏环境:游戏不再满足于静态的混凝土盒子,玩家期望墙壁可以被炸开、建筑可以坍塌、掩体可以被摧毁——每一次破坏都改变了场景的几何拓扑,使得预计算的光传输路径失效。
昼夜循环:开放世界游戏越来越普遍地要求太阳可以移动、天空颜色可以渐变、阴影可以随时间拉伸和旋转——光照条件不再是静态的,甚至不再是离散的几种状态,而是连续的时变函数。程序化生成世界:从体素沙盒到星系生成,场景几何体在运行时才被创建,根本不存在离线烘焙的可能性。
这三个趋势共同指向一个结论:预计算路线存在一个根本性的天花板。无论Lightmass的光子映射多么精确,无论Enlighten的传输矩阵多么高效,它们都依赖一个前提——场景的几何体和光源配置在运行时基本保持不变。一旦这个前提被打破,预计算的数据就变成了过期的缓存,渲染结果就会出现错误的光照。而开发者们正在打破这个前提。2015年SIGGRAPH会议上,一个来自NVIDIA研究团队的报告引起了广泛关注。
他们展示了一种基于体素锥追踪的实时全局光照方案:将场景体素化为三维网格,从每个表面点发射若干锥形射线进入体素空间,采样沿途体素中存储的光照和材质信息,从而近似计算出该点的间接光照。这种方法不需要预计算,可以处理完全动态的几何体和光源。但它有一个明显的代价:体素化的分辨率受限于显存带宽,锥追踪的采样数量受限于计算预算。结果是噪点、模糊和漏光——在体素网格的边界处,光线可能穿透薄墙,在另一侧产生不应存在的亮斑。
同一年,另一个方向也在取得进展。屏幕空间反射技术已经被集成进多个商业引擎。它利用已经渲染完成的帧缓冲中的颜色和深度信息,在屏幕空间内进行光线步进,模拟反射效果。
SSR的优点是代价极低——它只处理屏幕上可见的像素,不需要额外的场景表示。但它的局限同样致命:当反射方向指向屏幕之外时——例如一面朝向玩家的镜子反射出玩家身后的物体——SSR就无法获取那些离屏像素的信息。
结果是反射在水面、镜面和光滑地板上的图像会在屏幕边缘突然消失,或者退化为一个模糊的立方体贴图代理。这种离屏缺陷在2015至2016年间成为图形论坛上反复出现的截图主题:一扇玻璃窗反射出街道景象,但当视角转动,反射内容在窗框边缘骤然截断,露出下面粗糙的替代纹理。
还有第三条路线在实验室中酝酿。2016年,距离场表示法开始在虚幻引擎中扮演更重要的角色。距离场是一种隐式几何表示——它不存储表面的三角形,而是存储空间中每一点到最近表面的有符号距离。这种表示天然适合进行光线步进:从表面点出发,查询距离场获取安全步长,沿射线方向前进,直到击中某个表面或超出范围。距离场可以处理动态几何体——只要在几何体移动时更新局部距离场——并且不受屏幕空间的限制。但它的精度同样受限于距离场的分辨率,在薄几何体和尖锐边缘处容易产生伪影。
三条路线——预计算、屏幕空间、体素与距离场——各有其不可替代的优势,也各有其无法克服的缺陷。预计算提供最高质量但拒绝动态变化;
屏幕空间提供即时响应但受限于可见像素;体素和距离场拥抱动态性但受困于精度与性能的权衡。
没有一条路线能够单独解决实时全局光照问题。而就在开发者们在这三条路线之间艰难取舍的时候,硬件厂商投下了一枚重磅炸弹。2016年5月,NVIDIA在台湾举行的GPU技术大会上发布了基于帕斯卡架构的GTX 1080显卡。在发布会的技术演示中,NVIDIA展示了一段使用实时光线追踪渲染的场景——尽管当时还没有专用的光线追踪硬件单元,演示使用的是计算着色器在通用CUDA核心上实现的软件光线追踪。但黄仁勋在台上明确表示,NVIDIA正在投资光线追踪硬件,并暗示未来一代GPU将具备专用加速能力。
同年,AMD也在推动类似的技术方向。其Radeon ProRender渲染器使用了基于OpenCL的光线追踪实现,虽然主要面向离线渲染市场,但AMD的工程师在GDC演讲中多次提及实时化的可能性。
两家GPU巨头的动作传递出一个清晰的信号:硬件光线追踪正在从学术研究走向工程实现,消费级显卡在可预见的未来将拥有追踪真实光线的能力。
这个信号在开发者社区中引发了复杂的情绪。一方面,它点燃了希望——如果硬件可以高效追踪光线,那么全局光照就不再需要预计算、不再受屏幕空间限制、不再依赖粗糙的体素近似。光线追踪是光照问题的物理正确解:它模拟光子的行为,从摄像机反向追踪光线,在场景中弹射、折射、遮蔽,最终计算出每个像素的精确辐射度。这是图形学研究了三十年的圣杯。
但另一方面,它也引发了焦虑。那些已经在Lightmass或Enlighten上投入大量工程资源的团队,那些已经围绕预计算管线构建了完整内容生产流程的工作室,是否要再次推倒重来?更重要的是,第一代光线追踪硬件的性能是否足以支撑完整的实时全局光照——而不仅仅是少数反射或阴影效果?没有人知道答案。2016年8月,史克威尔艾尼克斯蒙特利尔发行了《杀出重围Go》。
这是该工作室继《杀手Go》(2014)和《劳拉Go》(2015)之后推出的第三部回合制解谜游戏,也是该系列的收官之作。游戏在E3 2016前的新闻发布会上首次公开,随后登陆Android、iOS以及Windows平台。
从技术角度看,《杀出重围Go》与实时光照圣杯的追逐似乎毫无关联——它是一款俯视角、回合制、预渲染美术风格的手游,不涉及任何复杂的实时全局光照计算。但这恰恰是理解那个时刻的关键。
《杀出重围Go》代表的是另一条路径:放弃对完全动态场景的执念,接受静态或半静态的光照条件,在受限的技术框架内追求极致的艺术表达。它的每一个关卡都是手工布置的光照环境,每一个阴影都是美术师精心调整的结果。这种路径在移动端游戏、独立游戏和中等规模项目中广泛存在——而它们构成了游戏产业的绝大多数。在AAA工作室为圣杯争得头破血流的时候,大多数开发者早已选择了务实的妥协。那些追逐圣杯的AAA工作室正在承受越来越大的压力。
2016年,一个使用Lightmass烘焙的开放世界场景可能需要四到六小时的分布式计算时间——前提是拥有一个十台以上工作站的Swarm集群。一旦美术师调整了场景中的任何静态几何体,或者改变了光源的位置或属性,烘焙就必须重新执行。在内容生产的快速迭代循环中,这意味着美术师每天只能看到有限几次完整的全局光照结果。
而Enlighten的用户虽然可以实时移动光源,却必须接受表面区块精度的模糊间接光照——在需要锐利阴影或精确反射的场景中,这同样无法满足要求。
屏幕空间路线的情况更加微妙。SSR在2016年已经成为几乎所有现代引擎的标准配置,它的极低性能开销使其成为反射效果的默认选择。但它的离屏缺陷正在变得越来越难以忽视。随着游戏场景的复杂度增加——更多的室内外过渡、更多的镜面表面、更多的透明材质——屏幕空间反射失效的情况越来越频繁。
开发者开始采用混合策略:在屏幕空间内使用SSR,在离屏区域退化为静态立方体贴图,在两者之间进行某种形式的混合。
但混合本身就引入了新的问题:接缝、过渡不自然、两种反射源的色温不匹配。体素锥追踪在2015至2016年间经历了短暂的追捧期,但很快暴露出工程实现的复杂性。高质量的体素化需要大量显存带宽,锥追踪的采样模式需要仔细调校以避免噪点,而体素分辨率与场景尺度的权衡几乎在每个项目中都需要单独处理。一些团队尝试将体素追踪用于漫反射全局光照,将屏幕空间反射用于高光反射,将预计算光照贴图用于静态背景——三种技术在一个引擎内共存,各自负责场景的一部分光照需求。
这就是2016年底的局面。引擎架构师们面对的不再是选择某一条技术路线的问题,而是如何让多条技术路线在同一帧内协同工作的问题。这个问题比选择单一方案困难得多。不同的光照技术有不同的输入数据需求:Lightmass需要光照贴图UV和预烘焙纹理,Enlighten需要表面区块的传输矩阵,SSR需要上一帧的颜色和深度缓冲,体素锥追踪需要三维体素网格,距离场需要有符号距离场体积纹理。
不同的技术有不同的更新频率:光照贴图从不更新,Enlighten在光源移动时更新,SSR每帧重新计算,体素追踪在几何体变化时重新体素化。不同的技术有不同的覆盖范围:SSR只能处理屏幕可见部分,体素追踪受限于体素网格的边界,距离场受限于距离场体积的边界,预计算方案覆盖整个场景但只对静态部分有效。
将这些异构的技术整合进一个统一的渲染管线,要求引擎架构做出根本性的改变。渲染不再是一条从几何体到像素的线性流水线,而是一个需要动态调度、混合和切换多个子系统的复杂框架。引擎必须在运行时判断:当前像素的材质属性是什么?它需要漫反射全局光照还是高光反射?场景中哪些部分是静态的,哪些是动态的?当前视角下,屏幕空间反射是否足够,还是需要退化为其他方案?
这些判断不是离线做出的——它们必须在每一帧、每一个像素上实时执行。虚幻引擎4的文档开始引导开发者理解这种新的思维方式。
文档不再宣称Lightmass是正确的全局光照方案,而是将其描述为适用于静态场景的高质量选项。文档详细介绍了如何将Lightmass烘焙的静态全局光照与屏幕空间反射的动态高光反射结合使用,如何在静态区域使用预计算光照贴图、在动态区域使用距离场环境光遮蔽,如何在两者之间进行平滑过渡。引擎提供的不是一条正确路径,而是一套可配置的工具箱——开发者需要根据项目的具体需求,选择、组合和调校不同的光照技术。
Unity的文档也在经历类似的转变。Enlighten仍然是被推荐的实时全局光照方案,但文档开始详细说明其局限性——表面区块精度导致的细节丢失、对动态几何体的不支持、在开放世界场景中的内存开销——并提供了替代方案和混合策略。开发者被鼓励在静态场景中使用烘焙光照贴图,在需要实时更新的区域使用Enlighten,在反射表面使用屏幕空间反射,在所有这些方案之间手动划分场景的光照区域。这种架构转变的深远影响远远超出了光照领域。
它标志着引擎哲学的一次根本性断裂。自1990年代以来,游戏引擎的核心承诺一直是提供一条正确的渲染路径——从id Tech的软件光栅化到Quake的硬件加速,从Unreal的延迟渲染到Unity的前向渲染,每个引擎都有其明确的渲染范式。开发者接受这个范式,在其约束下工作,获得可预测的结果。但现在,引擎承认了范式的局限。它不再声称知道正确的答案,而是提供多种可能的答案,将最终的选择权交还给开发者。
这场圣杯追逐战没有产生胜利者。Lightmass没有胜出,Enlighten没有胜出,屏幕空间反射没有胜出,体素锥追踪没有胜出。它们都没有被淘汰,因为每一个都在特定的条件下不可替代。但它们也都没有成为普适解,因为每一个都在特定条件下失效。引擎架构被迫接受了一个此前被抗拒的现实:不存在一种普适的全局光照方案。
存在的只是一个异构的混合系统,在其中,预计算辐射传输、体素锥追踪、屏幕空间反射和正在地平线上浮现的硬件光线追踪必须共存——不是作为过渡期的权宜之计,而是作为架构的永久特征。
到2016年底,一个使用虚幻引擎4的典型AAA项目可能同时运行着四套光照子系统。Lightmass烘焙的静态全局光照贴图覆盖所有不动的建筑和地形;距离场环境光遮蔽在动态物体上提供近似的间接阴影;屏幕空间反射处理所有光滑表面的镜面反射;而一个实验性的光线追踪插件正在技术美术的工作站上运行,为未来的项目积累经验数据。每一套子系统都有自己的性能预算、精度参数和失效条件。引擎的渲染管线在它们之间分配帧时间,在它们的输出之间进行混合,试图在屏幕上的每一个像素处缝合出一个连贯的光照结果。这个混合系统的总性能开销是可观的。
在一个典型的中高端PC上,2016年的全局光照管线可能消耗三到五毫秒的GPU时间——其中光照贴图采样几乎免费,屏幕空间反射大约一毫秒,距离场环境光遮蔽一到两毫秒,再加上各种混合和过渡的额外开销。在移动端,预算要紧张得多:Enlighten的实时更新可能消耗两到三毫秒,在低端设备上这已经接近整个帧预算的十分之一。而在高端PC上,当开发者尝试开启实验性的体素锥追踪时,单是体素化和锥追踪就可能消耗五毫秒以上——只有最强大的GPU才能在保持六十帧的同时负担这样的开销。
这些数字不是抽象的技术参数。当美术师在编辑器中移动一盏灯,他们等待的不是实时反馈,而是一个进度条——Lightmass的烘焙可能需要几十分钟到几小时,取决于场景规模和Swarm集群的规模。当程序员在代码中标记一个物体为可破坏,他们知道这个物体从此被排除在预计算光照系统之外,只能依赖精度更低的实时近似方案。
当设计师规划一个室内外过渡的场景段落,他们必须考虑屏幕空间反射在门口处是否会突然消失——以及这种消失是否会被玩家注意到。
这些约束塑造了2016年游戏的面貌。那些最受赞誉的画面——静态建筑在夕阳下的暖色反弹光、古老森林中透过树叶的柔和散射、密闭空间内复杂的光线弹射——几乎都是预计算的结果。而那些最令人印象深刻的动态时刻——爆炸的火光照亮坍塌的墙壁、昼夜循环中阴影的缓慢旋转、镜面中实时反射的移动角色——都依赖屏幕空间或体素方案,并在特定条件下暴露其局限性。玩家看到的是两者的混合:大部分时间,光照是正确的;偶尔,反射会消失,阴影会模糊,间接光照会延迟更新。这些瞬间提醒着所有人,圣杯尚未被找到。
而硬件的承诺正在加速逼近。NVIDIA的帕斯卡架构在2016年已经展示了软件光线追踪的可行性,尽管性能还远不足以支撑完整的实时全局光照。两家公司都在与引擎开发商进行闭门会议,讨论未来硬件的能力边界和API设计。
这些会议的内容不会公开,但它们的后果正在引擎架构决策中显现:虚幻引擎4的渲染管线开始预留光线追踪的接入点,Unity的脚本化渲染管线在架构上为自定义光照方案留出了空间。引擎不再假设预计算或屏幕空间方案是永久答案——它们被设计为可替换的组件,等待硬件成熟时被更精确的方案接替。
这就是圣杯追逐战在2016年底留下的局面。不是一个算法的加冕,而是一个架构的转型。引擎从提供单一正确渲染路径的封闭系统,演化为提供可配置渲染工具箱的开放系统。光照不再是引擎替你做出的决定,而是引擎提供的一组可能性——开发者必须理解每一种可能性的优势和局限,然后为自己的项目做出选择。当2017年的曙光来临时,引擎开发者们手中握着的不是圣杯,而是一张写满了性能数字、精度参数和失效条件的技术地图。地图上没有标出通往圣杯的道路,因为圣杯根本不存在——存在的只是取舍、混合和永无止境的工程迭代。