图形学篇 — 环境光遮蔽(AO)

Posted by Xun on Monday, January 1, 0001

环境光遮蔽(AO)技术,用于模拟场景中的光照,使场景中的物体看起来更加真实。

简介

  • 随着设备的更新换代,现代游戏玩家对画面质量的要求越来越高,全局光照成为提升游戏视觉效果的关键技术。全局光照技术基于物理光学原理,通过计算光线在场景中的反射、折射和散射等过程,模拟真实世界的光照效果,使得游戏场景看起来更加逼真。然而,这种真实带来的代价就是计算成本过高,离线生成一个静态场景的效果可能需要花上几个小时,并不适用于实时渲染。因此,需要通过简单但在视觉上仍然令人信服的解决方案的进行替代,一种基本的全局照明效果是环境光遮蔽(Ambient Occlusion)。

基础概念

立体角(Solid Angle)

  • 平面角定义为角所对的弧长 s 与半径 r 的比值,用 ω 表示。 Math_AmbientOcclusion_1.png
  • 立体角(Solid Angle)则是在三维空间下的角度,其所对的面积 A 与半径 r 的平方的比值,用 Ω 表示。 Math_AmbientOcclusion_2.png
  • 立体角通过 θφ 两个角度来表示,其中 θ 是与 z 轴的夹角,φ 是与 x 轴或 y 轴的夹角。 AmbientOcclusion_1.png AmbientOcclusion_2.png
  • 如图所示,对于单位立体角 (即 ),其所对的面积 A 即为矩形 ABCD(近似)的面积,即 Math_AmbientOcclusion_3.png 其中,AB 为 对应的弧长,CD 为 对应的弧长,则有 Math_AmbientOcclusion_4.png 因此 Math_AmbientOcclusion_5.png

辐射能量(Radiant Energy)

  • 辐射能量(Radiant Energy)是指电磁辐射的能量,用 Q 表示。

辐射通量(Radiant Flux)

  • 辐射通量(Radiant Flux)是指单位时间内的辐射能量,用 Φ 表示。 Math_AmbientOcclusion_6.png 其中,Q 是辐射能量,t 是时间。

辐射强度(Radiant Intensity)

  • 辐射强度(Intensity)是指单位立体角内的辐射通量(所有面积光总和),用 I 表示。 Math_AmbientOcclusion_7.png 其中,Φ 是总辐射通量,Ω 是立体角。

辐照度(Irradiance)

  • 辐照度(Irradiance)是指单位面积上接收到的辐射通量(所有立体角方向总和),用 E 表示。 Math_AmbientOcclusion_8.png 其中,Φ 是总辐射通量,A 是接收面积。

辐射率(Radiance)

  • 辐射率(Radiance)是指单位立体角,在单位面积上辐射通量,用 L 表示。 Math_AmbientOcclusion_9.png 其中,Φ 是总辐射通量,Ω 是立体角,A 是接收或光源面积,对应入射或出射辐射率。基于理想漫反射表面(Lambert 表面),只有垂直于光的投影面积,才是真正的辐射面积,所以辐射率最终需要对面积进行修正,即 A cosθ
  • 由于总辐射通量是所有面积所有方向的辐射通量总和,所以需要对立体角和面积进行二次微分。

渲染方程(Rendering Equation)

  • 渲染方程(Rendering Equation)是全局光照模型中的基本方程,用于描述光在场景中的传播和反射。渲染方程的基本形式为: Math_AmbientOcclusion_10.png 其中,p 为观察的物体表面位置,v 为观察方向,l 为光的入射方向,n 为物体表面法线,n · l 表示入射光被物体表面接收(和投影面垂直)的比例,f 为物体表面反射率(接收到的光反射到观察方向的比例)。

环境光遮蔽(Ambient Occlusion)

  • 为了实现全局光照模型效果,则需要求解渲染方程,常用的方法有两种,即有限元方法和蒙特卡洛方法。其中,光能传递是基于有限元方法的算法,各种形式的光线追踪则是使用蒙特卡洛方法。然而,这些方法虽然可以产生较好的效果,但生成一帧图像可能需要花费数个小时,并不适用与动态场景。
  • 为了将全局光照效果应用到计算生成的场景中,需要使用一些简化的模型方法,一种基本的方法是环境光遮蔽(Ambient Occlusion,AO)。为了简化,假设两个条件:
    • 物体表面为 Lambert 表面。
    • 入射辐射率在各个方向上都为相同的常量 L'
  • 根据前面的辐射率公式,可以得到辐照度 EMath_AmbientOcclusion_11.png
  • 然而,当前辐照度并未考虑可见性,即某些方向的光可能被场景中其他物体或自身某些部分阻挡,则这些方向的入射辐射度不为 L'。假设来自被遮挡方向的入射辐射度为 0 ,未被遮挡方向的入射辐射度为 1,则 Math_AmbientOcclusion_12.png 其中,v 为可见性函数,L' 后的积分部分为环境光遮蔽因子,用 k 表示,即 Math_AmbientOcclusion_13.png
  • 当所有方向都没有遮挡时,v 为 1 ,此时 k 有最大值。当所有方向都被遮挡时,v 为 0 ,此时 k 有最小值。 Math_AmbientOcclusion_14.png
  • 因此,归一化的环境光遮蔽因子 k'Math_AmbientOcclusion_15.png 辐照度 EMath_AmbientOcclusion_16.png
  • 通过环境光遮蔽方法计算全局光照效果,最终会转换为通过计算环境遮挡因子实现。计算环境遮挡因子可能很耗时,通常需要执行在渲染之前离线进行。预先计算任何与光照相关的过程,包括环境遮挡在内的信息,通常被称为烘焙。预计算环境光遮挡最常见的方法是通过蒙特卡洛方法,即在法线周围的半球面上,均匀地随机取 N 个方向,并沿着这些方向追踪光线,检查这些方向最终是否可见,对结果求平均值,即为 k' 的估算值,则能计算出对应的辐照度。

屏幕空间环境光遮蔽(Screen Space Ambient Occlusion)

  • 计算环境遮挡因子的离线方法,能得到较好的表现效果,但需要进行光线追踪计算,计算成本较高,且仅适用于静态场景。对于实时动态场景,需要使用更加简化的模型,避免大部分此类计算。对于动态场景,可以通过将物体进行分组后,再用简化模型替代每一组,之后计算每一个简化模型的 SDF 信息,就能通过锥体追踪得到光线的遮挡信息。
  • 然而,在物体空间下进行计算的方法,随着场景复杂度的提升,计算量会越来越大,造成新的性能压力。事实上,关于遮挡的一些信息可以完全从屏幕空间数据中推断出来,如:深度、法线,这些数据在渲染过程中已经生成。屏幕空间下计算的方法,不受场景复杂度的影响,而是仅和渲染过程使用的分辨率相关,因此具有恒定的计算成本。
  • 屏幕空间下的环境光遮蔽(Screen Space Ambient Occlusion,SSAO),通过使用 z-buffer 深度缓冲区作为唯一输入,来估算每个像素的环境遮挡因子。在以像素位置为圆心的球面上,随机取一组采样点,进行深度测试,最终通过深度测试的样本数量占比即为环境遮挡因子。 AmbientOcclusion_3.png
  • 如图所示,相机在正上方,黄色点为当前计算的像素位置点,其余点为采样点,分布在以黄色点为圆心的球面上。其中,红色点在物体内部,即未通过深度测试,而蓝色点虽然在物体外部,但在相机方向上被遮挡,即同样未通过深度测试,仅绿色点能通过深度测试,因此环境遮挡因子 k' 为 0.2 。
  • 其中,样本的选取,不是只考虑位于表面上方半球内的位置,而是包括了物体内部的位置。在这种采样方式下,会出现一个平坦的表面会变暗,且边缘比周围更亮的情况。尽管如此,这种表现结果通常在视觉上依然能令人满意。