大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

时间:2023-03-08 23:07:58
大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

效果图

这次先上效果图*4

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

散射概念

光线击中空气中的微小颗粒后的偏折导致了光线的散射。我们看到的阳光应该是由视线上的散射在视线方向上的集合。如果由地面的反射,还要加上经过散射计算的地面反射。

Rayleigh散射

由较小的空气分子引起的散射,对不同波长的光有不同的散射程度,蓝色最强。也就是天空为啥是蓝色的原因。

Mie散射

由较大的漂浮颗粒(气溶胶……PM2.5????)导致的散射

相位方程

相位方程描述有多少光会倍散射到相机方向上。

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering
θ:采样点处光线(太阳到采样点)和视线(相机到采样点)的角度。

g:影响对称性,对Rayleigh散射,g可以取0。对Mie散射,g一般是在-0.75到-0.999之间。

外散射

就是计算散射对光的影响

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering
:外散射是向散射点为球心的球面上均匀散射的,所以这个是球表面积,单方向的散射就没有4π了

光深(optical depth ): 就是公式的积分部分,可以理解为两点间的平均大气密度,这个值显然跟高度有关系。h就是归一化之后的采样点高度。H0大气平均密度高度,可以理解为在这里密度是1。选取的值是0.25。

散射系数K(λ):散射系数,这个系数跟海平面大气密度有关,也跟波长有关。不过rayliegh和mie都有所不同,比如大部分mie的实现是忽略波长的。

内散射

散射在视线方向上的集合,整个公式就是不进行球面积分的散射。

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

采样点处的两个外散射:采样点到相机和太阳到采样点的散射

Is(λ):光强度,可以在这里修改太阳光色,正常按白色就可以差不多。

表面散射

表面散射就是将地表的反射光/自发光进行到相机的散射处理

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

Ie(λ):地表发出的光(反射/自发光)。这有两个方案:1.认为地表自发光,地表的颜色就是这个值。2.认为地表的光是反射,在计算反射之前,要算上入射光经过大气层的散射,所以这个值要比没有大气直接反射小。

注意:这个方案中忽略了反射方向上的散射积分,所以地表颜色会有点片暗。

简化计算

进行归一化,将从海平面到大气上界的高度值scale到0~1

预计算查询表

将积分采样计算预先进行,生成相应的查询表

太阳光在大气内散射的预计算

将阳光认为是平行光,此时可以用高度和与平行光的角度来描述大气层内的任意一点,不唯一的点数值也都是一样的。

更好的预计算方法

上一个预计算方法只能解决两个外散射计算中的太阳光散射部分,怎么把视线散射部分也解决?
对于一个均匀大气层来说,任意一点按一定角度到任意方向大气上界的射线,都可以用射线发起点高度,和一个偏移角来描述。这个射线可以既可以用在光线方向的散射计算,也可以用在视线方向的散射计算,只要能描述两条射线就都没问题。
这样只要预先计算采样射线上的光深和大气密度(exp(-h/H0)),这样两个外散射积分就都不用计算了

使用预计算表注意

预计算表存的都是从采样点到大气上界的值,要是相机在大气内,是需要剪掉同方向上从相机位置到大气上界的相应计算结果的。
这种情况下如果采样点(定点)在相机上方,有可能出现计算用的射线穿过地表的情况,这个时候在低精度的shader中肯定由精度问题。于是将射线方向反转,向采样点方向取两个射线,计算结果是一样的(距离一样)。

Shader实现

shader的思路是不使用预计算,而用结果近似的简单计算。用一点效率来降低shader的硬件需求。

消除预计算表取值

使用x=0(海平面)的曲线将其他采样曲线归一化得到这个结果

v = exp(-4x)*scale(y)

scale(y),就是海平面处的曲线。这样x轴就被干掉了
这个scale曲线并没有什么通用的方案,是使用曲线拟合获得的一个多项式计算公式。于是这个实现有一个问题就是:**如果scale height(平均密度高度)不是0.25(从海面到大气上界的25%),这个scale的近似公式就要重新进行曲线拟合**

4个shader

首先地面和天空的顶点计算完全不同。另外要解决之前提到的大气内取值的问题,在大气内会有一些计算是大气外不需要的。为了减少shader内的逻辑判断所以分成4个shader,从大气看地面,从宇宙看地面,从宇宙看天空,从大气看天空。

一些奇怪的参数

有一些参数非常的怪异,文章中并没有什么说明。稍微说一说,省得以后自己忘了。
单位:波长的单位一般是nm,10^-9m。海平面分子数密度,2.55*10^25。 这种计算float基本不行了,所以在单位上要进行一些修正。由于Rayleigh中的散射系数是跟λ^4相关的,将λ变成10^-3单位,每个乘了10^6,4次就是10^24。这就几乎没有0 了。

Kr,4πKr:Kr是Rayleigh的散射系数。这里取值是0.0025。

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

我计算了一下β

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

这个结果和
[Efficient Rendering of Atmospheric Phenomena]中的基本相似

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

但是这时计算的K是 9.3 * 10^-8 这个我立刻就方了。根本不一样好不好,差好几个数量级呢!(差了3.72*10^-5)

我现在还没有想通,猜测有两个方向:1.光深计算上的区别,2.高度归一化的影响。四处看了几天也没有结果,下次我继续搞Eric.Bruneton那个计算了多重散射的再继续研究

Km,4πKm: Km是Mie散射的系数,也一样有很让人迷惑的计算结果

g:一个影响散射对称性的参数。
[Display_of_The_Earth_Taking_into_Account_Atmospheric_Scattering]里面有一点说明,不过更详细的在另外一篇文章。

大气散射 GPU Gems2 Chapter 16. Accurate Atmospheric Scattering

u和空气质量相关,0.7~0.85

不过基本上对Rayleigh散射g=0,对Mie散射在-0.75到-0.999之间

---

需要测试的问题以及额外的研究

大气内shader
生成预计算表,改成取值形式的shader
g对散射效果的影响
H0对散射效果的影响
参与散射的云
分开Mie和Rayleigh的相关计算
表面散射使用反射机制
表面散射增加视线上的散射积分
HDR 更丰富的战线

题外话

在研究散射系数的时候真的是很有一点挫败感,感觉虽然GPU Gems这书里面提供了一个很好的实现,但是道理讲得就有点模糊,想要继续挖掘的时候就显得很尴尬。
之后会作几个简单的改进,至少实现预计算取值形式的shader和简单的工具。再之后的……如果有作宇宙题材游戏的机会再进一步研究吧