一、SSAO介绍
AO
环境光遮蔽,全程Ambient Occlustion,是计算机图形学中的一种着色和渲染技术,模拟光线到达物体能力的粗略的全局方法,描述光线到达物体表面的能力。
SSAO
屏幕空间环境光遮蔽,全程 Screen Space Ambient Occlusion,一种用于计算机图形中实时实现近似环境光遮蔽效果的渲染技术。通过获取像素的深度缓冲、法线缓冲来计算实现,来金丝的表现物体在间接光下产生的阴影。
SSAO历史
AO这项技术最早是在Siggraph 2002年会上由ILM(工业光魔)的技术主管Hayden Landis所展示,当时就被叫做Ambient Occlusion。
2007年,Crytek公司发布了一款叫做屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)的技术,并用在了他们的看家作孤岛危机上。
二、SSAO原理
- 计算深度、法线缓冲
- 深度->像素坐标
- 法线->法向半球随机向量
- 计算像素随机后的坐标(多次采样)
- 获取随机后深度并比较
- 判断加权AO
- 后期(模糊等)
样本缓冲
- 深度缓冲
-
- 深度缓冲中的depth值用于当前视点下场景的每一个像素距离相机距离的一个粗略表达,用于重构像素相机空间中的坐标(Z),来劲死重构该视点下的三维场景。
- 法线缓冲
-
- 相机空间中的法线信息,用于重构每个像素的“法线-切线-副切线”构成的坐标轴,用于法线半球中的采样随机向量(随机向量用于判断、描述该像素的AO强度)。
法向半球
- 黑色表示我们需要计算的样本
- 蓝色向量表示样本的法向量
- 白色灰色为采样点(很明显,采样点的多少影响最后的渲染效果),其中灰色表示被遮挡采样点(深度大于周围),据此判断最终AO的强度。
- 右图表示法向球形采样(后背抛弃),原因是该方式采样导致凭证的墙面也会显得灰蒙蒙的,因为和心中一般的样本都会在墙这个几何体上。
三、SSAO算法实现
Buffer
- 获取深度&法线缓冲数据
- C#部分
- Shader部分
- UnityCG.cginc
如果是延迟渲染这一步可以省略,G-Buffer中可以直接拿到
中间相机空间坐标
- 重建方法
-
- 参考链接:Unity从深度缓冲重建世界空间位置 - 知乎
- 本例实现使用其中的“NDC空间中重构”方法得到样本在相机空间中的向量,乘以深度值得到样本的坐标。
- 从NDC空间重建
-
- 1.计算样本屏幕坐标(利用Unity内置的函数)
- 2.转化至NDC空间中
- 3.计算相机空间,从中到远屏幕的方向(内置变量_ProjectionParams.z存放相机远平面值far)
- 4.矩阵变换至相机空间中的样本相对相机的方向
- 5.重构相机空间的样本坐标(在像素着色器中)
- 在相机空间中通过样本的相对相机方向以及深度,来拟合重构坐标
构建法向量正交基
- 设置法向量
- 生成随机向量(用于构建的正交基随机,而非所有样本计算的到的正交基一致),先归一化
- 求出切向量,再利用函数cross叉积求副切线向量
AO采样核心
- 传入给定的随机采样向量,并通过法向量正交基转化至法线半球中的向量。
- 获取随机坐标点。
- 转换至屏幕空间坐标
- 计算随机向量转化至屏幕空间后对应的深度值,并判断累加AO
四、SSAO效果改进
随机正交基(增加随机性)
- 为了不使求得的法向半球的正交基一致,我们引入随机向量,已求得不用想象的切向量。
- 利用uv采样一张Noise贴图(如下图4x4像素的Noise贴图,可选择其他尺寸),或者随机向量。
- 并在C#中传入噪声贴图。
AO累加平滑优化
范围判定(模型边界)
- 样本采样,可能会采集到的深度差非常大的随机点,会导致边界出现AO,如下图
- 加入样本深度和随机点的深度值判定(效果如下图)
自身判定
如果随机点深度值和自身一样或者非常接近(可能会导致虽然在同一平面,也会出现AO),如下图
判断深度值的大小时,增加一个变量,来改善问题
AO权重
AO深度判断,非0即1,比较生硬,为其增加一权重,如下图
本例中的权重为:发现半球中随机采样后的点x、y(切线平面)距离样本的距离为参考
模糊
采用基于法线的双边滤波原理(Bilateral Filtering)
五、对比模型烘焙AO
烘焙方式
- 三维建模软件烘焙AO方式
-
- 通过三维建模软件(如3DMax),设定好渲染参数,对模型(单一选择模型实体),烘焙AO到纹理。
- 游戏引擎烘焙AO方式(Unity3D Lighting)
-
- 通过Unity的Lighting功能(主菜单/Window/Rendering/Lighting Settings)进行整体场景的烘焙,AO信息包含于此。
建模软件烘焙优缺点
- 优点
-
- 单一物体可控性强(通过单一物体的材质球上的AO纹理贴图),可以控制单一物体的AO的强弱;
- 弥补场景烘焙的细节,整体场景的烘焙(包含AO信息),并不能完全包含单一物体细节上的AO,而通 过三维建模软件烘焙到纹理的方式,增加物体的AO细节;
- 不影响其(Unity场景中)静态或者动态;
- 缺点
-
- 操作较其他方式繁琐,需要对模型进行UV处理,再进行烘焙到纹理;
- 不利于整体场景的整合(如3DMax烘焙到纹理,只能选择单一物体,针对整体场景的处理工作量巨大);
- 增加AO纹理贴图,不利于资源优化(后期可通过其他纹理通道利用整合资源);
- 只有物体本身具有AO信息,获取物体之间的AO信息工作量巨大(不是不可能)。
Unity烘焙优缺点
- 优点
-
- 操作简易,整体场景的烘焙,包含AO的选择;
- 不受物体本身的UW影响,Unity通过Generate Lightmap UVs生成模型第二个纹理坐标数据;
- 可生成场景中物体与物体之间的AO信息;
- 缺点
-
- 缺少单一物体的细节(可调整参数提高烘焙细节,但换之将增加烘焙纹理数量和尺寸,以及烘焙时间);
- 受物体是否静态影响,动态物体无法进行烘焙,获得AO信息。
SSAO优缺点
- 优点
-
- 不依赖场景的复杂度,其效果质量依赖于最终图片像素大小;
- 实时计算,可用于动态场景;
- 可控性强,灵活性强,操作简单;
- 缺点
-
- 性能消耗较之上述2种方式更多,计算非常昂贵;
- AO质量上要比较离线式烘焙(上述2种)不佳(理论上)。
六、SSAO性能消耗
AO核心采样消耗说明
AO法向半球的随机采样
双边滤波的多重采样
本例SSAO算法中,主要核心为计算AO随机法向半球的采样点,并加以半段计算AO权值。
- 利用For结构代码进行半球堆积向量的采样,If、For等对于GPU计算性能上不友好
- 采样数的数量(上图的_SmpleKernelCount,针对For循环的次数),过低的采样数得不到好的结果;以64为例,1334*750的分辨率,每个像素计算循环64次,合计1334*750*64次AO核心计算。
- 循环体重采样,同样以64为例,每个像素计算需要采样64次来求得屏幕深度值法线值。
滤波采样消耗说明
本例采用的是双边滤波(Bilateral Filter),为保证不被模糊,采样基于法线的双边滤波。
- C#后期脚本中,Blit两次(横向和纵向),合计调用两次滤波渲染Pass;
- 单一滤波渲染Pass中,多重采样,包括7次主纹理的采样和7次屏幕像素的法线信息的采用,屏幕中每个像素合计14次纹理采样。