别的不多扯,直接进入正题,HBAO全程Image-space horizon-based ambient occlusion
对于屏幕上的像素点P,HBAO算法通过以下几个步骤来计算它的环境光遮蔽
1:将其周围360的角度进行均分,每个方向分别做RayMarching,如下图实线部门,分为四个方向进行Ray Marching(每一个像素不能用相同的四个方向,所以要在方向上旋转一个随机角度,如下图中的虚线部分)
2:对于其中任意一个方向,可以得到一个一维的高度场,如下图所示,在这个方向上Marching得到一个最大的Horizon angle(水平角),其实也就是最高的那个点。
3:根据点P和它的法线N,计算出它的Tangent angle(切面角)
算法会保存每个像素的法线N,由于插值法线会造成一些错误的遮挡,所以保存的法线N是面法线。
这里需要说一下顶点法线和面法线的区别,面的法线是与面垂直的线(数学意义)。严格意义上讲,点是没有法线的。点的法线是在使用Phone或Gouraud模型时计算光照使用。如果一个面上的所有法线都一样,他们的光照也就一样,就会产生 flatness 效果,而如果把每个顶点的法向设置不同,则更平滑。
一个计算顶点法线最直接的方法就是针对每个顶点,先找到共享此顶点的所有三角形,然后计算这些三角形的面法线并相加,得到顶点的法线。
继续讲回刚刚HBAO的法线保存部分。如下图所示,在使用插值法线的时候,如果点P正好在一些几何体边缘部分,那么就会错误的将P左侧平面下方截取的区域计算入遮挡点,所以HBAO会用face normal从而解决这些错误遮挡问题
下面说一下face normal的计算,需要在几何阶段,基于眼空间坐标系,用ddx/ddy这操作就可以算出来了(DX),opengl的话就是dFdx dFdy了,对于眼空间坐标系的话,其实对应的是观察空间到投影与齐次裁剪空间的过程,如下图所示,对于透视投影,它定义了一个观察平截头体,以眼睛坐标指定。在眼睛坐标中,“眼睛”位于原点,并向下俯视-Z轴。
4:经过第2步和第3步,已经有了horizon angle和 tangent angle,那么可以计算出当前方向的环境光遮蔽值,计算公式如下图所示,括号中的值代表当前的方向(通过绕-Z轴渲染的角度来确定)
5:对剩下的三个方向也做同样的操作,最终得到点P在四个方向上的AO值(2D),把他们加起来做一个平均也就得到了最终点P的AO值,经过这几步就已经完成了算法的核心计算,能得到下图这样的结果
这个结果并不好,还存在一些问题(很多明显的带状区域,还不如SSAO...),下面就存在的问题和解决方案 一 一 说明
一: Low-Tessellation 问题
通过添加一个Angle Bias解决
Angle Bias为30度的结果对比
这个问题看起来很抽象,其实结合实际对比图片还是能看出来他主要解决的问题。
对于上图中的圆拱门部分(曲面),我们能看到一些很规整的条纹,其实这就是因为在这些曲面中Face Normal的使用就会造成一些错误遮挡,因为曲面是一个连续的面变化,切面总会将一部分区域计算入遮挡,而HBAO希望这部分不要计算入遮挡,所以就加了个偏差,就能得到一个没有AO的很干净的曲面
二:不连续问题
对于相邻的两个像素P0和P1,他们的AO值相差0.7-0 = 0.7,相差幅度过大,会带来不连续问题,然而我们需要的是柔和的环境光遮蔽效果,HBAO通过一个衰减方程来解决这个问题,下图是衰减公式
那么如何应用这个衰减公式呢,如下图所示,在采样方向上有两个点S1和S2(AO计算最终用的是S2的,因为它的仰角最大)
首先初始化WAO = 0,然后先计算S1的AO,同时用衰减公式更新WAO
S2同理
这里的WAO就是这个方向上最终的AO值,W(S2)代表与点P距离为r的点S2贡献的AO值的权重,如下图所示,如果不考虑采样点贡献的AO对于当前像素点P距离的衰减的话,那么权重就一直是1,距离衰减也可以理解为,如果距离点P特别近的采样点用来贡献点P的环境光遮蔽,那么点P的AO基本与这个采样点一致,越远AO衰减的越多
三:噪声
这是由于每个像素点的随机化方向造成的,下图是取6个方向,每个方向采6个点计算出来的AO图
这里就是老生常谈了,模糊一下噪点就可以,不多扯了,HBAO使用高斯模糊,简单放一下效果
最终可以得到HBAO的整套渲染流水线,如图所示,(在渲染AO的时候可以降分辨率渲染,这里不讲了,主要讲原理,降分辨率渲染的话得单独准备一张RT)
AO计算的性能主要取决于以下几个方面
到这里为止,HBAO就已经讲的很清楚了,相对来说比较简单,毕竟08年的技术,用延迟渲染管线的话就很容易实现了,前向渲染的话(苦逼的Mobile端)可能需要在前一帧就把这些信息保存好吧。
下一篇准备弄GTAO,有时间的话会贴一些自己实现的shader代码,Have A Nice Day.