本案例学习资料来源
Volumetric Atmospheric Scattering
案例学习——Unity基于体绘制的大气散射shader
0 效果展示
先看看实现的效果(米氏散射和瑞利散射结合的地球大气+云层+地球昼夜)
1 引入
抬头望天,我们会发现天空经常是蓝色
日出日落时天空经常会是红色
这样的光学现象主要是光进行了瑞利散射(Rayleigh scattering),本文依照AlanZucconi大神的教程,介绍如何对大气散射进行数学建模,来重现这些大气中的视觉效果。
1.0 介绍
对于传统的渲染技术,会假设物体是一个空的外壳,我们在外壳表面即可进行所有效果的计算。这种简化方式对于渲染物体表面来说是很高效的。
但是有些效果是由于光穿透了物体才能实现的,比如半透明物体正是如此。不过聪明的人们也研究了一些快速近似半透明物体的方法(GDC 2011 – Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look)。
但是大气就很难这么做了,因为天空并不是一个“物体”,我们不能只是渲染表面的壳,我们还需要模拟光线在大气中到底经历了什么。
不光光渲染壳,同时也要渲染物体内部的光线传播,这个技术通常被称为体积渲染/体绘制(volumetric rendering),在本文的上一篇文章做出过一些小的探讨(比如光线步进和有向距离函数)。
不过仅是这样还不足以模拟大气散射,接下来会介绍一种更合适的方法,被称为体积单次散射(volumetric single scattering)。
1.1 单次散射(Single Scattering)
在游戏引擎的基本光照模型实现中,都假设光线在真空中传播,所以物体的表面属性往往是影响光照的唯一因素。
然而在物理上,传播媒介对光的影响也是很重要的,对于大气来说,穿过的空气多少或者空气的成分就很能影响光照的效果。
在图形学进行大量的简化之后,空气影响我们感知光线的方式,通常会分为两种,分别是出射散射(Out-Scattering)和入射散射(In-Scattering)
1.1.1 出射散射(Out-Scattering)
出射散射也就是光子打中空气分子后,原本要射向摄像机的光线进行了偏转,光线的方向进行了改变。
对于一个大光源来说,能够发射出很多很多光子,因而在空气中传播时经常会发生出射散射。
空气密度越大,光线传播的距离越长,出射散射发生的光线偏转越多,对光线的削弱效果越明显。
1.1.2 入射散射
与出射散射相反,本来不指向相机的光线也可能被偏转到相机的方向,这就是入射散射。
入射散射允许相机看到不在可视范围内的光源,比较明显的例子就是光晕,比如下图由于Particle的偏转,会让人觉得沿着视线和Particle的连线处有光线,看起来也就是光晕。
1.2 基于体绘制的单次散射模型(Volumetric Single Scattering)
光线在实际传播当中会偏转很多次,就像下图这样
进行仿真是光线追踪的内容,对于本文来说,我们只考虑单次散射——即光线从太阳发出过、只经过一次散射改变方向后射入我们的眼睛。
对于渲染一个行星的大气,我们会逐步构建一个模型,首先我们考虑相机
- 摄像机的视线从A处进入大气,经过B处
- 我们计算光线从B到A的过程中,每一个位置P造成的出射散射的衰减贡献&入射散射的叠加贡献
该模型中也存在光源的贡献,我们通常假设是太阳的光线经过入射散射的偏转来到我们眼前
太阳在照射到P的过程中也存在出射散射
总结这些部分,混合在一起,也就是如下的样子
- 相机的视线从A进入,经过行星大气到B
- 我们需要去计算AB段上每一点P的散射贡献
- P点接受的光线都来自于太阳
- P点接受的光线进入大气层时会受到出射散射的影响
- P点接受的光线经过入射散射偏转进入摄像机,途中又会经过出射散射偏离
2 大气散射背后的理论
2.1 透射函数
为了计算传入相机的光线有多少,我们可以先考虑一段光线,如下图所示
- 光线从太阳传到C,此时是真空,所以没有损失,我们用 I C I_C IC指代C点的光强
- 在从C到P的过程中,经过出射散射,光强会衰减,我们用 I P I_P IP指代P点的光强
- I P I_P IP比 I C I_C IC的值也就是透射率(transmittance) 。
- 透射率 T T T表示在某段路径上的对光照的衰减程度。 T ( C P ‾ ) = I P I C T(\overline{CP})=\frac{I_P}{I_C} T(CP)=ICIP
- 对于某一个值的透射率 T T T,P点的光强也就是 I P = I C ∗ T ( C P ‾ ) I_P=I_C*T(\overline{CP}) IP=IC∗T(CP)
2.2 散射函数
P点在接受光照后,会因为散射偏转一部分
于是我们需要散射函数 S S S来表示某一方向上光线的偏转情况。
如下图,那些偏转了 θ θ θ角的光线才能被指向A点的摄像机
用 S ( λ , θ , h ) S(λ,θ,h) S(λ,θ,h)的值来代表发生了 θ θ θ度偏转的光线比重。
λ λ λ代表光线的波长, θ θ θ是偏转角度, h h h是P点的离地高度(高度会影响大气密度,密度会影响散射程度)
于是我们可以得到从P点出发到A点的光强了
带入之前求出的 I P = I C ∗ T ( C P ‾ ) I_P=I_C*T(\overline{CP}) IP=IC∗T(CP)
整个过程是这样
- 光从太阳进入 C C C点,真空中无影响
- 从 C C C点进入大气传到 P P P点,受到出射散射影响只有占比 T ( C P ‾ ) T(\overline{CP}) T(CP)的光线到达了 P P P点
- P P