大气散射学习笔记

一些学习笔记和效果制作的记录

Volumetric Atmospheric Scattering - Alan Zucconi

首先还是推荐上面链接国外大佬的概念介绍

rayMarching和signed distance functions不能有效的模拟大气散射,渲染大气这种实心半透明物体,更合适的方法是volumetric single scattering体积单次散射。实时渲染中更多的还是考虑体积单次散射。

Out-Scattering 射向相机的光线被偏转

大气散射学习笔记_第1张图片

In-Scattering 没有射向相机的光线被偏转向相机,其会导致光源周围出现光晕

大气散射学习笔记_第2张图片

体积单次散射的整个流程就是:

  1. 视线从A看向B,像素最终值是AB路径上多个P点in-Scattering的共同影响的结果
  2. 从太阳到P点的光在路径中有out-Scattering损失
  3. 从P点到A点的光在路径中有out-Scattering损失

大气散射学习笔记_第3张图片

 当然,实际情况肯定有很多别的光线通过其他路径到达相机,但是体积单次散射只考虑view direction上的in-scattering的光线

大气散射学习笔记_第4张图片

大气散射学习笔记_第5张图片

假设光线从C->P->A

T表示衰减系数 表示某段路径上光照的衰减程度

S表示散射系数 表示有多少光散射的角度为θ,λ为波长,h为高度

所以单个P点最终到人眼的A的光照为:

大气散射学习笔记_第6张图片

 最终到人眼的光照为ViewDir路径上的P值的积分

大气散射学习笔记_第7张图片

 由于太阳光来自很远的地方,所以到达大气的每一个点的光照方向都可以视作一样的,所以对于A点in-Scattering的θ角度是一样的,这样就是个定值可以优化表达式。实际操作中的具体优化会在之后提及

以上是单次散射的流程,那么针对现实中真实的散射效果,目前主流的是俩种数学散射模型来进行模拟

散射模型

Rayleigh Scattering

大小远小于光线波长的粒子,由于粒子比波长还要小很多,所以光的波长也会影响散射程度

Mie Scattering

大小远大于光线波长的粒子,由于光的波长相较于这些粒子大小来说是可以忽略的,所以认为Mie Scattering和光线波长无关,Mie Scattering是太阳周围光晕的主要成因

Rayleigh Scattering

蓝线表示散射光的首选方向

大气散射学习笔记_第8张图片

 散射函数 表示入射光散射到特定方向上的光

大气散射学习笔记_第9张图片

 λ光的波长,θ散射角度,h高度,n=1.00029空气的折射率,N=2.54*10的24次方,标准大气密度,ρ(h)密度比,在海平面为1,随高度呈指数下降

 

 一般使用指数函数对其真实曲线进行数学拟合,对于Rayleigh Scattering,通常设H=8500米,对于Mie Scattering H一般在1200米左右

大气散射学习笔记_第10张图片 大气散射学习笔记_第11张图片

上图显示三种不同波长,h=0时的散射系数

Rayleigh散射方程表示有多少光向特定方向散射,但并不能知道一共散射了多少光。所以需要做球面积分得到总的散射系数:

公式推导:

上图所示是基于二维的函数图像,要计算空间中的总散射,需要做球面积分

大气散射学习笔记_第12张图片

大气散射学习笔记_第13张图片

大气散射学习笔记_第14张图片

 考虑海平面0时,密度比为1,上式可化为

 

大气散射学习笔记_第15张图片

所以蓝光散射的比较厉害,所以白天的时候天空为蓝色。而当黄昏的时候,由于光线几乎平行于地平线传播,所以阳光要穿越更厚的大气层,大多数蓝光都被散射未进入人眼,所以天空会偏红。

Rayleigh 散射原始方程可分解为俩个分量,一是β(λ,h)定义强度,二是γ(θ),表示有多少光散射到θ角度上,称为相位函数。

 Rayleigh 散射的相位函数为:

可以看出散射函数就等于总散射系数×相位函数

 Rayleigh 散射方程分解:

Mie Scattering

散射系数

大气散射学习笔记_第16张图片

 上图式子β(λ)也是考虑海平面为0时的情况,考虑p(h)时为下式

相位函数

大气散射学习笔记_第17张图片

衰减系数 T

以上散射系数是考虑散射到某一特定角度上的光线比例,现在需要考虑经过一次散射之后,入射方向上还剩下多少光

设I0在一次散射后损失了β比例的光,这个β就是上面提到的散射系数。则剩余的光为I1

根据该式,得到衰减一段距离x后剩余的光为

 

 公式推导:

大气散射学习笔记_第18张图片

 大气散射学习笔记_第19张图片

 所以如果β是定值的情况下,从C到P的光量为

 如果是手游中的实时渲染,可能恒定的大气密度就可以满足一个计算就能实现比较不错的效果。但是如果是精度要求较高的话,由于大气密度是随高度变化的,所以需要每个计算点的散射系数来计算,用积分表示

简化,可以直接代入β散射系数方程得到

大气散射学习笔记_第20张图片

 就是那段积分的值,称之为光学距离

所以最后式子就简化为:

如果只考虑Rayleigh时的最终方程:

 

 

 大气散射学习笔记_第21张图片

 大气散射学习笔记_第22张图片

 之前都是理论,实际应用的时候,我们需要考虑怎样简化计算:

大气散射学习笔记_第23张图片

 以Raylieigh散射方程为例,上式中θ λ 和密度比ρ不是定值,其他都是定值。所以在实际运用中的计算流程是先在CPU端计算散射系数在海平面为0时的β(λ)

 上式为定值,算好后穿值给材质。密度比ρ和散射角度θ这些变量则在材质中计算。

并且如参考文章和GPU精粹2中大气散射优化部分所说,进一步的优化,可以将这些复杂的计算预处理存到LUT中,运行时直接读数据即可。

 在实际游戏应用中,大气散射效果分成天空盒和雾效俩个部分。关于雾效的部分有几个需要注意的点,首先由于光线的来源方向是viewDirection,所以使用后处理材质来添加雾效时,获取viewDir的方式为用深度图重新构建世界坐标,再用worldPos-camPos算出viewDir。那么不写深度的半透物件如果也需要受到雾效影响的话,就需要单独在它们的材质中用worldPosition去计算散射雾效。同时恒定空气密度的雾效没有做到密度随高度增高而减低的影响,所以为了模拟低处雾效更浓的效果,一般还需要添加一个高度雾配合使用。

GitHub - SlightlyMad/AtmosphericScattering: Atmospheric Scattering for Unity

这里极力推荐这位大佬的工程,其包括了raymarch计算+LUT优化+LightShaft等,是非常好的学习资料

这里简单记录下他的做法:

天空盒:

在shader中,方式一是做raymarching计算density,优化版本的方式二是通过LUT存储in scattering的计算信息,用的是3D LUT,Rayleigh和Mie是分开的,有俩张LUT

LUT中存储的值通过compute shader计算,在Start()中计算LUT传值给shader。compute中计算LUT的时候也需要for循环计算in scattering的部分

雾效:

在shader中,与上面相同,同样方式一是做raymarching计算in scattering,优化版本的方式二是通过LUT存储Inscattering和Extinction,这俩LUT也是在compute shader中计算,并且在一个for循环中就能算好。

并且需要拿到深度图用来和视线方向相乘来作为步进距离,无论是raymarch方式还是LUT方式,都需要用到深度信息。

InscatteringLUT存储compute计算好的整个inscattering部分的颜色,ExtinctionLUT存储衰减部分。最终颜色:

并且还有前置的AmbientLight部分计算采样随机_RandomVectors贴图 DirLight部分采样ParticleDensityLUT   DensityLUT计算

Pass0 密度比预计算

Pass1 根据随机方向vector 计算模拟环境光带来的inScattering部分

Pass2 光学距离预计算

Pass3 雾效计算  同样也需要用到深度图重建世界坐标,其用到的Inscatter和衰减系数信息同样来自于俩张3D LUT

所有的LUT都在compute shader中计算

当然 以上雾效还未考虑物件遮挡产生的体积光效果,计算LightShaft部分需要将世界坐标转换到shadowmap空间判断可见性,然后就是正常体积光dither、模糊之类的操作

可以看出 就算使用了LUT存储的方式,计算LUT的过程中compute中也会有大量的for运算,并且要声明非常多的LUT,所以对于手机平台而言,可能恒定密度比简化计算是不错的选择。既能保证不做过多的计算,又能有一个相对不错的效果

大气散射学习笔记_第24张图片

 延伸到如果是做24小时的TOD,那么就需要定义一些颜色曲线根据时间变化动态改值。如我这里就简单调整了一些曲线。如散射的颜色,云的颜色,海水相关颜色如整体颜色、SSS颜色和反射颜色等。凌晨的雾浓度应该比较高,也可以添加float曲线控制雾效的距离。总之到这一步就是根据美术效果调参即可。

我如下图中的实现,就用的恒定的密度比,没有raymarch的计算,其实效果也不差。但如之前所说,用恒定密度的雾效一般需要额外加一个高度雾的效果。

简单调的颜色曲线

大气散射学习笔记_第25张图片

效果如下,动图大小有限制所以压的比较糊: 

顺便提一下云的效果,用的是2D面片云,这里没有使用法线贴图。而是用houdini出云的厚度图,然后用视差的步进方法计算自阴影,这里就不展开说了。这样算出来的效果其实并不逊于法线图的效果,并且更风格化一些~

大气散射学习笔记_第26张图片

一些云的效果参考 

Parallax Mapping with self-shadowing implementation solution here ? · Issue #1009 · UPBGE/upbge · GitHub

大气散射学习笔记_第27张图片

大气散射学习笔记_第28张图片

 houdini中就主要用自带的cloud相关那几个节点就行,可以建个简模来做大型

大气散射学习笔记_第29张图片

大气散射学习笔记_第30张图片大气散射学习笔记_第31张图片

 大气散射学习笔记_第32张图片

视频效果 B站1080压缩也很糊:

TOD效果_哔哩哔哩_bilibili

 参考:

[Rendering] 基于物理的大气渲染 - 知乎

基于物理的大气散射 in Unity URP - 知乎

GitHub - SlightlyMad/AtmosphericScattering: Atmospheric Scattering for Unity

【实战】从零实现一套完整单次大气散射_一 - 知乎

你可能感兴趣的:(学习笔记,unity,图形学)