LearnOpenGL笔记——五、高级光照:“SSAO”

五、LearnOpenGL笔记——五、高级光照:“SSAO”

5.9 SSAO

  • 我们已经在前面的基础教程中简单介绍到了这部分内容:环境光照(Ambient Lighting)。
  • 环境光照是我们加入场景总体光照中的一个固定光照常量,它被用来模拟光的散射(Scattering)
  • 在现实中,光线会以任意方向散射,它的强度是会一直改变的,所以间接被照到的那部分场景也应该有变化的强度,而不是一成不变的环境光。
  • 其中一种间接光照的模拟叫做环境光遮蔽(Ambient Occlusion),它的原理是通过将褶皱、孔洞和非常靠近的墙面变暗的方法近似模拟出间接光照。
    • 这些区域很大程度上是被周围的几何体遮蔽的,光线会很难流失,所以这些地方看起来会更暗一些。
    • 站起来看一看你房间的拐角或者是褶皱,是不是这些地方会看起来有一点暗?
    • 尽管这不是一个非常明显的效果,启用SSAO的图像确实给我们更真实的感觉,这些小的遮蔽细节给整个场景带来了更强的深度感。
  • 环境光遮蔽这一技术会带来很大的性能开销,因为它还需要考虑周围的几何体。
  • 我们可以对空间中每一点发射大量光线来确定其遮蔽量,但是这在实时运算中会很快变成大问题。
  • 在2007年,Crytek公司发布了一款叫做**屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)**的技术,并用在了他们的看家作孤岛危机上。
  • 。这一技术使用了屏幕空间场景的深度而不是真实的几何体数据来确定遮蔽量。
  • 这一做法相对于真正的环境光遮蔽不但速度快,而且还能获得很好的效果,使得它成为近似实时环境光遮蔽的标准。
  • SSAO背后的原理很简单:
    • 对于铺屏四边形(Screen-filled Quad)上的每一个片段,我们都会根据周边深度值计算一个遮蔽因子(Occlusion Factor)。
    • 这个遮蔽因子之后会被用来减少或者抵消片段的环境光照分量。
    • 遮蔽因子是通过采集片段周围球型核心(Kernel)的多个深度样本,并和当前片段深度值对比而得到的。
    • 高于片段深度值样本的个数就是我们想要的遮蔽因子。
      在这里插入图片描述
  • 上图中在几何体内灰色的深度样本都是高于片段深度值的,他们会增加遮蔽因子;几何体内样本个数越多,片段获得的环境光照也就越少。
  • 很明显,渲染效果的质量和精度与我们采样的样本数量有直接关系。
    • 如果样本数量太低,渲染的精度会急剧减少,我们会得到一种叫做波纹(Banding)的效果;
    • 如果它太高了,反而会影响性能。
    • 我们可以通过引入随机性到采样核心(Sample Kernel)的采样中从而减少样本的数目。
    • 通过随机旋转采样核心,我们能在有限样本数量中得到高质量的结果。
    • 然而这仍然会有一定的麻烦,因为随机性引入了一个很明显的噪声图案,我们将需要通过模糊结果来修复这一问题。
    • 下面这幅图片(John Chapman的佛像)展示了波纹效果还有随机性造成的效果:
      在这里插入图片描述
    • 你可以看到,尽管我们在低样本数的情况下得到了很明显的波纹效果,引入随机性之后这些波纹效果就完全消失了。
  • Crytek公司开发的SSAO技术会产生一种特殊的视觉风格。
    • 因为使用的采样核心是一个球体,它导致平整的墙面也会显得灰蒙蒙的,因为核心中一半的样本都会在墙这个几何体上。
    • 由于这个原因,我们将不会使用球体的采样核心,而使用一个沿着表面法向量的半球体采样核心。
  • 通过在**法向半球体(Normal-oriented Hemisphere)**周围采样,我们将不会考虑到片段底部的几何体.
  • 它消除了环境光遮蔽灰蒙蒙的感觉,从而产生更真实的结果。
  • 这个SSAO教程将会基于法向半球法和John Chapman出色的SSAO教程。

样本缓冲

  • SSAO需要获取几何体的信息,因为我们需要一些方式来确定一个片段的遮蔽因子。对于每一个片段,我们将需要这些数据:
    • 逐片段位置向量
    • 逐片段的法线向量
    • 逐片段的反射颜色
    • 采样核心
    • 用来旋转采样核心的随机旋转矢量
  • 通过使用一个逐片段观察空间位置,我们可以将一个采样半球核心对准片段的观察空间表面法线。
  • 对于每一个核心样本我们会采样线性深度纹理来比较结果。
  • 采样核心会根据旋转矢量稍微偏转一点;我们所获得的遮蔽因子将会之后用来限制最终的环境光照分量。
  • 由于SSAO是一种屏幕空间技巧,我们对铺屏2D四边形上每一个片段计算这一效果;也就是说我们没有场景中几何体的信息。
  • 我们能做的只是渲染几何体数据到屏幕空间纹理中,我们之后再会将此数据发送到SSAO着色器中,之后我们就能访问到这些几何体数据了。
  • 果你看了前面一篇教程,你会发现这和延迟渲染很相似。
  • 这也就是说SSAO和延迟渲染能完美地兼容,因为我们已经存位置和法线向量到G缓冲中了。
  • 由于我们已经有了逐片段位置和法线数据(G缓冲中),我们只需要更新一下顶点着色器,让它包含片段的线性深度就行了。回忆我们在深度测试那一节学过的知识,我们可以从gl_FragCoord.z中提取线性深度。
  • 提取出来的线性深度是在观察空间中的,所以之后的运算也是在观察空间中。
  • 确保G缓冲中的位置和法线都在观察空间中(乘上观察矩阵也一样)。观察空间线性深度值之后会被保存在gPositionDepth颜色缓冲的alpha分量中,省得我们再声明一个新的颜色缓冲纹理。
  • 这给我们了一个线性深度纹理,我们可以用它来对每一个核心样本获取深度值。
  • 注意我们把线性深度值存储为了浮点数据;这样从0.1到50.0范围深度值都不会被限制在[0.0, 1.0]之间了。
  • 接下来我们需要真正的半球采样核心和一些方法来随机旋转它。

法向半球

  • 我们需要沿着表面法线方向生成大量的样本。
  • 就像我们在这个教程的开始介绍的那样,我们想要生成形成半球形的样本。
  • 由于对每个表面法线方向生成采样核心非常困难,也不合实际,我们将在切线空间(Tangent Space)内生成采样核心,法向量将指向正z方向。
  • 假设我们有一个单位半球,我们可以获得一个拥有最大64样本值的采样核心.
  • 我们在切线空间中以-1.0到1.0为范围变换x和y方向,并以0.0和1.0为范围变换样本的z方向(如果以-1.0到1.0为范围,取样核心就变成球型了)。
  • 由于采样核心将会沿着表面法线对齐,所得的样本矢量将会在半球里。
  • 目前,所有的样本都是平均分布在采样核心里的,但是我们更愿意将更多的注意放在靠近真正片段的遮蔽上,也就是将核心样本靠近原点分布。我们可以用一个加速插值函数实现它。
  • 每个核心样本将会被用来偏移观察空间片段位置从而采样周围的几何体。
  • 我们在教程开始的时候看到,如果没有变化采样核心,我们将需要大量的样本来获得真实的结果。
  • 通过引入一个随机的转动到采样核心中,我们可以很大程度上减少这一数量。

随机核心转动

  • 我们创建一个4x4朝向切线空间平面法线的随机旋转向量数组。
  • 由于采样核心是沿着正z方向在切线空间内旋转,我们设定z分量为0.0,从而围绕z轴旋转。
  • 我们接下来创建一个包含随机旋转向量的4x4纹理;记得设定它的封装方法为GL_REPEAT,从而保证它合适地平铺在屏幕上。

SSAO着色器

环境遮蔽模糊

应用环境遮蔽

  • 以上三部分内容参考官网及代码理解即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值