雾效分类与整体实现原理分析
雾效分类:按表现/实现 方式
高度雾/顶点雾(该雾效需要对场景中所有物体的Shader 追加雾效Shader)
深度雾/后期雾(通过后处理进行计算)
雾效实现原理分析(物理原理与实现方式)
物理原理:在水汽充足、微风及大气稳定的情况下,相对湿度达到100%时空气中的水汽便会凝结成细微的水滴悬浮于空中,使地面水平的能见度下降。这种天气现象称为雾。
实现方式:雾效的核心是使用一个新的颜色(雾色)替换(一部分 )物体本身计算的颜色。其中主要的复杂计算在于正确的雾效浓度,其次是在有光源的散射产生的颜色混合;在向前渲染中,大作使用顶点雾,即在每个场景物体进行着色的最后一步进行雾效计算,直接将混合结果输出到物体上;而后期雾主要是指通过读取buffer中的信息例如深度信息而计算雾的方式,通常用于延迟渲染等渲染管线。
雾效的分解
雾效果分为对场景中 地面、天空的影响
天空的部分,从上往下呈现逐渐减淡,黄色部分是模拟光的散射
地面部分
指数雾密度的计算
雾的密度与相对高度呈指数相关(相机与顶点高度差越小,雾密度越低;雾由浓至淡的变化高度本身相对相机存在高度差:雾从海拔高度为0向海拔高度为400m逐渐稀薄,但是摄像机在海拔200m位置,则高度差为-200m)
雾密度
雾密度 = 全局密度 * 2 ^ (相机高度 - 目标位置高度 - 雾变化高度范围相对摄像机的高度差)
由于角色会在场景中移动,角色视角中最近的物体 雾的强度也最低,因此使用相机的位置和物体顶点的位置的差作为高度雾的指数。(为了让雾气更可控,添加两个参数:对雾整体强度的控制(——GlobalDensity),高度差参数(——FogHeight))
指数雾强度计算
为什么要用指数来模拟?因为要达到这样一个效果:近处雾的变化较缓,远处雾的变化较快。
雾散强度 = 全局雾散系数 * (目标位置高度 - 相机高度 - 雾变化高度范围相对摄像机的高度差)
参数——FogFallOff对雾的指数变化进行控制;x为距离
雾强度:FogFactor = (1-exp2(-Falloff)/Falloff)
f=kx,这里的 k = _FogFalloff , x = (posWorld.y - _WorldSpaceCamarePos.y - _FogHeight)
当高度产生的数值增加,雾的强度呈指数上升,相对高度越高,雾的强度增长得越大
距离计算
雾密度与相对距离相关,相机与顶点的距离越远,雾越浓。距离摄像机过近的位置,雾会被稀释,很难看到雾;因此拟合雾与相对距离正相关,并且有一个可控的起始变化距离。
雾随距离变化的强度:
视线向量 = 目标位置世界坐标 - 摄像机世界坐标
视线距离 = 视线向量 的长度
雾距离强度 = (视线距离 - 手动控制起始距离)/ 距离变化系数
ps:如果实际项目中想要让雾的衰减看起来像一个平面的话,需要单独对顶点到摄像机的这个向量(实现向量)进行处理。
(总)雾整体的强度
雾 = 雾强度 * 雾密度 * 雾距离强度
光散射强度
当然如果雾是一个单色的话,在白天会显得有点儿假,因为实际情况是太阳会发生散射。(收光照射的顶点,其雾的颜色会受到光源颜色的影响,由于雾效是边缘模糊的低精度效果,此处光强可以使用基本光照模型进行近似)
散射强度计算:
散射强度 = (归一化视线向量的反方向 与 入射方向 的夹角)^ 指数衰减系数
我们在这里参考Lambert光照模型,即光强度 = 顶点法线与入射光夹角;此处由于雾效距离较远(近处的雾浓度低散射强度低,使用dot(n,l)会导致远近强度一样),因此我们最终使用视线方向的逆方向代替顶点法线进行计算,同时给予指数衰减参数_FogInscatteringExp进行控制
散射衰减
光的衰减与距离有关,较近处由于雾气密度较薄,散射强度小,越远处越强。
散射颜色混合
fogColor = lerp(_FogColor, _LightColor0,saturate(inscatteringFactor));
最终雾效颜色 = 雾效色与光源颜色的散射强度插值
最终效果
雾效Shader编写注意事项(头文件)
函数复用:由于雾效需要对不止一个Shader生效,因此最好将函数封装进头文件使代码更加干净
提供分支开关:雾效应当提供开关以便特殊处理以及查看结果,此处使用Shader feature 关键字进行处理,并保持关键字名称一致,以使用单个全局开关统一控制