NASA 那张航天飞机 Endeavour 的照片很适合当起点:低地球轨道,黑色太空压在上方,地球边缘露出一层薄薄的大气。橙、蓝、黑挤在一起,像把日落剖开给人看。
Maxime Heckel 这篇长文做的事,就是从这张照片往回推。不是发产品,也不是写科普散文,而是用 WebGL 和 Shader,把天空、日落、行星大气壳拆成一套能在浏览器里实时跑的近似模型。
有意思的地方在这里:很多实时天空还停在贴图、渐变、调色。可可信的天空不是一张蓝色背景。它是太阳光穿过空气分子、气溶胶、臭氧之后,被散射、吸收、衰减留下的结果。
这篇文章到底做了什么
目标很清楚:先在浏览器里实时渲染天空穹顶,再把同一套思路扩展到行星外层的大气壳。
它走的不是“做一张漂亮 skybox”的路线,而是把观察方向、太阳方向、大气密度、光学深度都放进计算里。画面要随着太阳高度、相机位置、行星曲率变化,而不是只在一个角度看起来对。
核心模块可以压缩成这张表:
| 模块 | 解决的问题 | 画面结果 |
|---|---|---|
| Raymarching | 沿视线在大气中分段采样 | 空气不再是背景色,而是有体积的介质 |
| 光学深度 + Beer 定律 | 估算光穿过介质后的衰减 | 天空亮度和颜色开始有层次 |
| Rayleigh phase / Rayleigh scattering | 描述空气分子对短波长光的散射 | 白天蓝天成立 |
| Mie scattering | 描述尘埃、气溶胶等大颗粒散射 | 太阳附近的雾感、光晕成立 |
| Ozone absorption | 模拟臭氧对部分波长的吸收 | 黄昏和地平线颜色更厚 |
| Sun transmittance / light marching | 从采样点朝太阳方向再算透光率 | 日出日落不再只是橙色滤镜 |
最容易低估的是 light marching。
只沿相机视线算一次,只能知道“光从某个点到眼睛损失了多少”。但日落为什么红、为什么暗、为什么越贴近地平线越像烧起来,还要算太阳光抵达那个点之前,已经穿过了多厚的大气。
少了这一步,夕阳很容易变成一团发白的雾。看着有光,逻辑是空的。
这篇文章也没有把 Shader 近似包装成严格物理模拟。它站在实时图形的现实里:要可信,要可交互,还要跑得动。绝对精确不是目标。帧率预算里的“足够像”,才是目标。
真正有用的是变量分工
这类文章对开发者最有价值的地方,不是给一个“复制就完事”的答案,而是把变量的责任分清。
Rayleigh 管蓝天。短波长更容易被空气分子散射,所以蓝色更多进入视线。
Mie 管浑浊感。尘埃、气溶胶、水汽这类更大的粒子,会让太阳附近出现发白、发亮、发糊的光晕。
臭氧吸收不负责“加颜色”。它负责拿走一部分光。很多色彩深度不是加出来的,是减出来的。
这点和摄影很像。好照片不全靠提亮,有时是阴影压得准。
对前端图形和 WebGL/Three.js 开发者,直接动作是:别一上来就堆后期滤镜。先判断你的天空是不是会被用户交互打穿。
| 场景 | 更适合的做法 | 现实约束 |
|---|---|---|
| 静态官网背景、短暂停留页面 | 渐变、贴图、预渲染 skybox | 成本低,维护简单,物理一致性要求不高 |
| 可拖动太阳角度的 Web 叙事 | 物理近似 + 少量艺术调参 | 需要控制采样数和 Shader 成本 |
| 游戏或实时可视化中的昼夜变化 | 大气模型、LUT、分层优化 | 不能只追求真实,要服从性能预算 |
| 行星浏览、教育可视化 | 行星大气壳 + sun transmittance | 曲率、视角高度、背光面都会暴露假模型 |
对关心游戏渲染、可视化教育的人,判断也很简单:如果用户只看一张图,贴图能赢;如果用户能转动视角、改变时间、穿过大气边缘,模型迟早要上桌。
限制也要说清。Raymarching 不便宜。采样数、步长、噪声、banding、移动端 GPU 压力,都会找上门。Sebastian Hillaire 那类 LUT 路线,本质就是把昂贵计算提前压缩,用查表换实时性能。
真实世界没有免费午餐。只是把成本藏在运行时、预计算、贴图内存,还是美术调参里。
好看的实时画面,正在从调色走向建模
我更在意的是背后的转向。
早年的很多实时画面,是美术资产的胜利。贴图、渐变、后期滤镜,把结果调到顺眼。现在更硬的路线,是把自然现象拆成能运行的近似方程。
这不是为了炫物理。是因为交互会拆穿假象。
用户不动,假图很好骗。用户一动,太阳高度变了,相机升高了,视角擦过大气边缘了,行星转到背光面了。每一个动作都在逼问模型:你理解的是现象,还是只画了一个像它的壳?
这和早期 3D 图形从手绘光影走向实时光照,有点像。不完全一样,但结构相似:当场景开始可交互,静态美术的权力会下降,模型、近似和预算的权力会上升。
“形而上者谓之道,形而下者谓之器。”放在这里不玄。道是散射、吸收、透射这些规律;器是 Shader、WebGL、raymarching、LUT 和性能预算。只谈规律,跑不动。只谈工具,画面空。
所以这篇文章最该被学习的,不是某一段 Shader 写法,而是一种判断顺序:
- 先问现象由哪些物理变量决定;
- 再问哪些变量必须实时算;
- 再问哪些可以近似、查表、预计算;
- 最后才轮到调色和风格化。
这对团队也有现实影响。做 Web 交互叙事的人,可以先用简化模型验证方向,不必一开始追求电影级真实。做游戏或实时可视化的人,要更早把美术、图形工程、性能预算放在一张桌上谈。否则天空看着更真实,帧时间先炸。
我不太买账的是那种“物理化就天然高级”的说法。工程里没有天然高级,只有适合不适合。一个静态落地页用复杂大气模型,可能只是浪费。一个可飞行的行星场景还靠蓝色渐变,就会露怯。
判断边界在交互强度。交互越多,物理近似越值钱。画面越静,贴图和美术越划算。
回到 Endeavour 那张照片,它打动人的不是颜色多漂亮,而是大气层薄得吓人。Maxime Heckel 这篇文章把这种“薄”拆成了光路、密度、吸收和散射。浏览器里当然不是真正的大气科学,但它至少让天空不再是一块蓝布。
天空不是蓝色背景。日落也不是橙色滤镜。
它们是光在空气里走过一段路,最后交给 GPU 的一笔账。
