Hotdry.

Article

基于物理的天空渲染:Rayleigh/Mie 散射与体积光照的 WebGL 工程实践

解析基于物理的散射模型与 Rayleigh/Mie 近似,涵盖 WebGL 体积光坐标变换、阴影映射、性能优化等工程参数调优。

2026-05-12ai-systems

在 WebGL 和 Three.js 生态中,天空渲染与大气散射仿真是将 3D 场景从技术演示升维为沉浸式体验的核心技术点。Maxime Heckel 在其关于体积光照的深度技术文章中,系统性地阐述了如何将后处理管线与体积光线步进(Volumetric Raymarching)相结合,从而在浏览器中实现可与游戏美术相媲美的体积光效果。这一技术路径不仅适用于人造光源的光束渲染,更是通往基于物理的天空颜色渐变、日落分层与行星大气可视化的必经之路。

物理模型基础:Rayleigh 与 Mie 散射的数学框架

大气散射的物理本质是光与大气分子及气溶胶粒子的相互作用。在工程实现中,Rayleigh 散射与 Mie 散射构成了天空着色的两大支柱。Rayleigh 散射由大气分子主导,其散射系数与光波长的四次方成反比,这解释了天空为何呈现蓝色而日落时分呈现橙红色 —— 短波长(蓝光)在穿越大气路径时被更强烈地散射,而长波长(红光)则相对直穿。标准 Rayleigh 散射系数为 vec3 (5.5e-6, 13.0e-6, 22.4e-6),分别对应 RGB 三通道的散射强度。Mie 散射则由气溶胶与较大颗粒主导,其散射不具备波长选择性,但具有显著的前向散射特性,Mie 相函数中的不对称因子 g 控制了这一特性,典型值在 0.758 左右。

Scale Height(标高)是另一个关键参数,它描述了散射密度随高度衰减的速率。Rayleigh 标高约为 8 公里,Mie 标高约为 1.2 公里,这意味着在更高海拔处,Rayleigh 散射贡献急剧降低,而 Mie 散射影响范围更为局限。对于行星大气可视化场景,行星半径通常设为 6371 公里,大气层外半径设为 6471 公里,即大气厚度约 100 公里。wwwtyro 的 glsl-atmosphere 库提供了完整的 GLSL 实现,其 API 接受太阳位置、散射系数、标高、不对称因子等参数,可直接用于 WebGL 着色器开发。

体积光照的坐标系统变换

将体积光效果叠加到 3D 场景的后处理过程中,是 Heckel 方法论的核心洞见。传统的光线步进在三维世界空间中运行,而后处理管线则工作在二维屏幕空间。要在这两个空间之间建立桥梁,需要完成从屏幕坐标到世界坐标的完整变换链:屏幕空间 UV 坐标首先被转换到 NDC(归一化设备坐标),再通过投影矩阵的逆变换回到视图空间,最后通过视图矩阵的逆变换映射到世界空间。这一变换过程可用 GLSL 函数表示为接收 UV 与深度纹理值,返回该像素对应的世界空间位置向量。

在实际工程中,投影矩阵逆矩阵与视图矩阵逆矩阵可直接从相机的 camera.projectionMatrixInverse 与 camera.matrixWorld 属性获取。fragment shader 中的深度值则通过 postprocessing 库的 EffectAttribute.DEPTH 属性暴露为 depthBuffer uniform。这一基础设施使得后处理 pass 能够为场景中的每个像素重建其三维空间位置,从而为后续的体积光步进提供精确的起点与方向向量。

体积光线步进与深度缓冲停止机制

体积光的核心循环沿着从摄像机出发的射线方向逐步累积光照密度与衰减。对于每个步进采样点,需要计算其与光源的相对位置、距离衰减、以及该点是否处于场景物体的遮挡范围内。初始实现使用简单的指数衰减函数 exp (-k * distance) 模拟光强随传播距离的减弱,但这种各向同性衰减无法复现真实体积介质中的方向性散射效果。

深度缓冲停止机制是提升体积光真实感与性能的关键优化。未经优化的光线步进会持续穿透不可见区域(如墙体背后的空气),导致光线穿透物体的视觉穿帮,同时浪费大量计算资源。通过在每个步进点比较其与相机的距离和场景深度纹理的对应值,当步进距离超过场景深度时立即终止循环。这一优化不仅消除了光线穿透问题,还将有效步进范围限制在可见场景内,显著降低了每像素的着色计算量。

阴影映射与遮挡检测的工程实现

体积光效果中最具工程挑战性的部分是阴影计算。要在体积介质中产生真实的阴影条纹,需要生成场景从光源视角看到的深度图,即阴影映射。实现流程包括:创建专用的渲染目标(Render Target)并附加深度纹理;创建虚拟相机并将其放置在光源位置;将场景渲染到该虚拟相机以获取深度信息;在后续的体积光步进循环中,对每个采样点执行世界坐标到光源屏幕空间的变换,并比较该点在光源视图下的深度与阴影映射中的深度值。

阴影映射的一个常见问题是阴影痤疮(Shadow Acne),即由于深度精度导致的沿着表面可见的条纹状伪影。通过引入阴影偏差(Shadow Bias)参数 —— 将阴影映射深度与实际深度比较时加上一个小的偏移量 —— 可以有效避免自遮挡问题。同时需要处理光源视锥体外的采样点,这些区域应被视为被照亮而非处于阴影中。

Henyey-Greenstein 相函数与方向性散射

各向同性衰减的改进方案是引入 Henyey-Greenstein 相函数,该函数在云计算与大气渲染领域有着广泛应用。它通过单个参数 g(不对称因子)控制散射的方向分布:当 g 接近 0 时散射接近各向同性;当 g 接近 1 时呈现强烈的前向散射;当 g 接近 -1 时呈现强烈的后向散射。在体积光步进中,相函数值通过计算视线方向与光方向的点积获得,并乘以光源亮度与衰减因子作为最终的光照贡献。

Mie 相函数在前向散射方向会产生尖锐的光晕效果,这与现实中气溶胶粒子产生的大气光学现象(如太阳周围的耀斑)相符。通过调整不对称因子 g 并结合 Rayleigh 与 Mie 的双层散射模型,可以构建出从湛蓝天空到橙红日落的完整色彩过渡。

Beer-Lambert 定律与透射率计算

体积介质中光的吸收与透射遵循 Beer-Lambert 定律,其数学表达为透射率等于指数衰减的密度 - 路径长度乘积。在光线步进循环中,每个步进的透射率贡献为 exp (-stepDensity * stepSize),累积透射率通过将每个步进的透射率连乘获得。最终像素颜色等于场景原始颜色乘以累积透射率,再加上每个步进点发出的累积光照。stepDensity 参数控制了大气的浑浊程度 —— 较高的值产生浓密雾霾效果,较低值则呈现清澈通透的大气。

将 FBM(Fractal Brownian Motion)噪声叠加到 SDF 形状因子上,可以模拟大气中密度不均匀分布的效果,使体积光呈现出动态云雾的质感。通过随时间滚动噪声采样位置,还能实现大气流动的动画效果。

蓝噪点抖动与性能优化

体积光线步进的主要性能瓶颈在于循环次数与每步的计算复杂度。直接增加步长虽然能减少循环次数,但会导致可见的条带状瑕疵(Banding Artifacts)。蓝噪点抖动提供了一种优雅的解决方案:为每条射线在起始位置引入一个随机偏移量,使得原本均匀分布的采样点被随机化分布,从而将条带瑕疵转化为几乎不可察觉的高频噪点。通过使用 1024×1024 的蓝噪点纹理,并根据帧号滚动噪声图案的偏移,可以实现稳定且高质量的输出。

在 Heckel 的测试中,通过蓝噪点优化,步进次数从 250 降至 50,同时步长从 0.05 增至 0.5,总迭代次数从 5000 降至 100,而视觉质量几乎没有明显下降。阴影映射的分辨率选择也需要权衡:过低的分辨率会产生阴影闪烁,过高则影响性能,Heckel 建议在复杂场景中使用 512×512 以达到性能与质量的平衡。

多光源与立方体阴影映射的扩展

单光源场景相对直接,但真实环境往往需要多光源支持。多光源体积光的实现需要为每个光源创建独立的虚拟相机、阴影映射纹理与后处理 uniform,并在最终合成时将各光源的累积光照叠加。代码复杂度随光源数量线性增长,但在现代 GPU 上运行数十光源的体积光仍是可行的。

球点光源(能够向所有方向投射阴影的光源)需要更复杂的阴影映射方案。传统阴影映射依赖单一方向的虚拟相机,无法覆盖球点光源周围的全空间。Three.js 的 CubeCamera 提供了六面立方体渲染目标,可以同时从六个方向渲染场景。然而 CubeCamera 不提供深度纹理输出,需要自定义 ShaderMaterial 计算每个表面到光源中心的归一化距离,并将其编码为颜色输出。这种 hack 方案在生产环境中需要根据具体需求进行优化。

工程参数调优清单

面向 WebGL/Canvas 实现天空渲染与大气散射时,以下参数需要重点关注与调优:Rayleigh 散射系数 vec3 (5.5e-6, 13.0e-6, 22.4e-6) 决定天空的基准色调与日落时的红橙分层;Mie 散射系数约 21e-6 控制大气浑浊度与光晕强度;Rayleigh 标高 8 公里与 Mie 标高 1.2 公里决定散射层的高度分布;不对称因子 g 约 0.758 决定前向散射的尖锐程度;大气半径与行星半径的差值决定大气层的厚度。

对于实时交互场景,建议将 NUM_STEPS 设置在 50–100 范围,STEP_SIZE 在 0.1–0.5 范围,配合蓝噪点抖动使用。阴影映射分辨率建议 256×256(简单场景)至 512×512(复杂场景)。光源强度 iSun 在 10–22 范围时,配合指数曝光映射 1 - exp (-1.0 * color) 可获得自然的 HDR 效果。

参考资料

Maxime Heckel 关于体积光照与后处理的技术博客(blog.maximeheckel.com);wwwtyro 的 glsl-atmosphere 开源实现(github.com/wwwtyro/glsl-atmosphere)。

ai-systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com