多数游戏开发者在渲染逼真的天空和云层时,第一反应往往是开启现代商业引擎自带的体积云系统,或者堆叠昂贵的射线步进算法。独立航海探索游戏《Around The World》的开发者 Thomas ten Cate 近期发布的开发日志,给出了一条完全相反的工程解法:避开高开销的物理模拟,用数百行 Rust 离线烘焙加一行法线着色器欺骗,在 Godot 引擎里把厚重云层和晚霞天光算得既轻量又干净。
很多团队在做体积介质渲染时,常常把画面发黑、发脏归咎于材质参数没调好。但这背后其实是老牌工具的隐性物理缺陷与商业引擎算力负担之间的两难。
老牌工具的认知陷阱:为什么单散射永远算不对云底
云朵在物理上是由高浓度微小水滴构成的参与介质。水滴的反照率极高,光子扎进云体内部后不会立刻熄灭,而是会在微粒之间经历数十次甚至上百次折射与弹射,也就是物理学上的多重散射。正是这种高阶光线传输,让现实中的积雨云即便遮天蔽日,云底依然能保持柔和且带有一定明度,而不是直接变成一块死黑的石头。
Thomas ten Cate 起初借助经典渲染器 POV-Ray 生成用于运行时的查找表(LUT),希望根据光照角度与云层密度控制散射强度。但他发现,无论把采样数调得多高、间隔划得多细,生成的测试球体底部始终黑得像一块实心金属。
问题并不在采样不足。POV-Ray 官方文档和核心开发者 clipka 的解释早已点明了根源:其介质材质模型采用的是单散射近似。文档中写明的蒙特卡洛积分,仅仅代表沿着单条射线前进时做数值估算,程序并不会递归发射次级光线来追踪多重弹射。
换句话说,在单散射假设下,光线穿不过高密度的介质,云层底部拿不到任何折射光。增加采样数只会让单散射的黑底变得更平滑,根本不可能无中生有解出多重散射的高阶能量。
数百行 Rust 与一张离线查找表
看清了工具本身的物理边界,开发者没有继续在参数微调上浪费时间,而是用 Rust 写了一个数百行的简易递归蒙特卡洛光线追踪器。
这个独立小工具的目标极为克制:它不支持复杂的场景几何体,代码完全硬编码,只渲染一个内部密度均匀的理想正球体云。在多线程环境下,程序让光子在球体内部真正发生递归折射和多重弹射。
尽管物理几何被极度简化为一个球,但运算出来的多重散射查找表与旧版单散射相比发生了根本性变化。低密度区域由于光线碰撞概率小,多重散射影响不明显;而在中高密度区域,原本漆黑的球体背光面被大量多次散射出来的漫反射光线均匀填补。
将这张新烘焙的查找表导入游戏后,原先笼罩在云层表面的金属反光彻底消失,较厚积云底部的平滑度和透光感回到了现实中应有的水准。
法线朝天:近乎零开销的环境光欺骗
解决了直射阳光的多重散射,另一个棘手问题随之浮现:云层不仅受太阳直射,还会接收整片天空穹顶散射下来的蓝光。到了日落时分,这种散射光还会夹杂着晚霞的红橙色。
如果完全按照物理准确的方式去追踪整片天空对云体每个体素的环境光投射,开销是小型独立项目无法承受的。Thomas ten Cate 利用 Godot 引擎的环境光采样机制,做了一次极具启发性的着色器欺骗(Normal Bending)。
在 Godot 的渲染管线中,环境间接光主要通过辐照度立方体贴图(Irradiance CubeMap)来采样,其采样方向直接取决于材质表面的几何法线。对于云朵底部而言,真实的几何法线垂直指向地面,因此引擎理所当然地为它赋予微弱的地表反射光,造成云底发灰、与天色脱节。
与其费力计算光线如何从天顶穿透云层,不如把云底的法线直接掰向天空。
开发者的改动极其微小:他在着色器中对云层下表面的法线向量进行人为偏转,强制让朝下的法线改为朝向天顶。
这一改动立刻触发了连续的视觉收益:
- 白天状态下,云朵底部由于采样了朝天的半球辐照度,自然带上了一层天蓝色调,使原本生硬的灰白云块柔和地融入大背景。
- 日落时分,瑞利散射导致直射阳光变为暖橙色,而天空顶端仍保留蓝青色。朝天的法线精准捕获了顶部的蓝光,与直射过来的红橙光混合,直接渲染出了现实黄昏中标志性的粉紫色晚霞积云。
整套处理完全没有引入额外的缓冲层或后处理光照通道,仅仅靠篡改传给引擎的光照法线,就以零算力代价达成了动态天光的环境染色。
- 结论.善用引擎现成的环境探针与着色器小技巧,能在不增加管线负担的前提下,解决大部分看似需要全局光照才能处理的柔和着色问题。
工业巨兽与独立破局:算力账本的取舍
回顾主流游戏工业界,解决体积云的多重散射与天光混合,走的是一条重型装备路线。
虚幻引擎在处理体积云多重散射时,采用基于多阶倍频的逼近算法。每增加一阶倍频,着色器的光追迭代成本就成倍增加;其环境天光则高度依赖 Sky Light 组件进行实时的环境图捕获。寒霜引擎在 SIGGRAPH 2016 披露的数据显示,在 Xbox One 上即便把主视图体积步进分辨率降到 640×360 配合时间性重投影,单帧耗时依然达到约 0.720ms,环境半球采样还要额外吃掉 0.090ms。
即使是 Sébastien Hillaire 在 2020 年提出的生产级大气 LUT 方案,在桌面级显卡 GTX 1080 上的运行耗时也需要 0.31ms 左右。更关键的是,这类两维大气查找表主要针对均匀行星大气层积分,根本无法直接套用到形态多变的局部浓云内部。
对中小团队而言,在有限的帧预算里硬塞几套多阶步进着色器,往往得不偿失。
Thomas 的做法展示了一种非常清晰的工程审美:当面对高阶复杂的物理传输时,先用离线工具把最昂贵的能量分布规律算死在一张图里;在运行时,则大胆利用引擎原生的环境光管线,以一行法线重映射达到八九成接近物理真实的画面效果。
- 提醒.法线强行朝天是一种完全脱离物理规律的艺术化妥协,在极端俯视机位或穿透非均匀复杂厚积云时,可能会露出光照方向失真的破绽。
计算机图形学在游戏领域的演进,从来不是单向的物理还原竞赛。工业大厂在用堆砌算力的方法逼近光度学极值,而聪明的独立工程师,总能找到用算力账本上最小的面额买下整片天空的捷径。
