games202:四,实时全局光照Real-Time Global Illumination:RSM、LPV、VXGI、SSAO、HBAO、SSDO、SSR

全局光照=直接光照+间接光照(多bounce弹射次级光源、焦散、次表面)

实时渲染中的全局光照指如何简单快速地计算多bounce次级光源(Secondary Light Sourse)光照。

本章主要讲几种3d全局光照方法

(1)图像空间方法

一,反射阴影贴图Reflective Shadow Map(RSM)

  • RSM的思路是建立在Shadow Map上的,即Shadow Map是就是场景中会被照亮的区域,而被照亮的区域≈次级光源(全局光照方法基本都基于这个思路)。
  • RSM就是在SM的基础上,多储存了一些次级光源必须的信息:深度、世界坐标、法线、光源能量。
  • RSM是2pass的方法,要知道某点次级光源的光照结果,我们需要知道:
    1. 哪些物体是次级光源(shadowmap可以获得这个信息)
    2. 每个次级光源的光照贡献

由于问题2光照贡献的计算量太大了,于是我们假设:假设所有反射物(次级光源)都是diffuse的(不用管入射方向观察方向了),但接受物不一定。

既然所有的次级光源都可能贡献到表面p,那么先计算一个,然后把每个都积分起来就是最终结果。

在这里插入图片描述
上图中q点是一个次级光源,p点为接收点,如何计算q点对p点的光照贡献呢?
L o ( p , ω o ) = ∫ Ω p L i ( p , ω i ) V ( p , ω i ) f r ( p , ω i , ω o ) c o s θ i d ω i L_o(p,ω_o) = \int_{Ω_p}L_i(p,ω_i)V(p,ω_i) f_r(p,ω_i,ω_o)cosθ_i dω_i Lo(p,ωo)=ΩpLi(p,ωi)V(p,ωi)fr(p,ωi,ωo)cosθidωi = ∫ A p L i ( q → p ) V ( p , ω i ) f r ( p , q → p , ω o ) c o s θ p c o s θ q ∣ ∣ q − p ∣ ∣ 2 d A = \int_{A_p}L_i(q→p)V(p,ω_i) f_r(p,q→p,ω_o)\frac{cosθ_pcosθ_q}{||q-p||^2} dA =ApLi(qp)V(p,ωi)fr(p,qp,ωo)∣∣qp2cosθpcosθqdA
根据次级光源都是漫反射的假设,得知 f r ( q ) = ρ π , L i ( q → p ) = f r ( q ) ⋅ Φ d A f_r(q) = \frac{ρ}{π},L_i(q→p) = {f_r(q)} \cdot {\frac{Φ}{dA}} fr(q)=πρ,Li(qp)=fr(q)dAΦ(Φ is energy of q).将 L i L_i Li带入渲染方程,dA抵消,得到 E q ( p , n p ) = Φ q m a x ( 0 , n q ⋅ ( p − q ) ) m a x ( 0 , n p ⋅ ( q − p ) ) ∣ p − q ∣ 4 E_q(p,n_p) = Φ_q \frac{ {max(0,n_q \cdot (p-q))max(0,n_p \cdot (q-p))}}{|p-q|^4} Eq(p,np)=Φqpq4max(0,nq(pq))max(0,np(qp)) = Φ q m a x ( 0 , n q ⋅ p − q ∣ p − q ∣ ) m a x ( 0 , n p ⋅ q − p ∣ q − p ∣ ) ∣ p − q ∣ 2 = Φ_q \frac{ {max(0,n_q \cdot \frac{p-q}{|p-q|})max(0,n_p \cdot \frac{q-p}{|q-p|})}}{|p-q|^2} =Φqpq2max(0,nqpqpq)max(0,npqpqp)
最终p点接收的所有次级光源能量为: E ( p , n ) = ∑ q E q ( p , n ) E(p,n) = \sum_{q}E_q(p,n) E(p,n)=qEq(p,n)

剩余的就是可见性、方向性、距离了:

  1. 可见性:对于一个着色点,shadowmap上所有的pixel不可能都有贡献,但因为无法对每个次级光源都做shadowmap,所以实时渲染中的间接光一般不考虑Visibility可见性项。
  2. 方向性:次级光源能够贡献到的方向只有自身的法线平面,着色点能接收光线的方向,也只有自身的法线平面,所以需要计算二者法线余弦值,以保证光线能正常传播。(同一平面的次级光源就没有贡献)
  3. 距离:通常只找距离足够近的次级光源。
  • 算法加速:对距离的计算实际中近似为找在RSM中与p点的投影接近(或深度接近)的次级光源,并且引入权重弥补稀疏采样的误差:权重近小远大,密小稀大。(一般一个着色点采样400次就可以)

  • RSM优劣势:

    1. 优点:容易实现。属于shadowmap流程
    2. 劣势:性能随光源数量下降、可见性省略计算导致不真实、假设次级光源都diffuse和加速优化有误差、采样率需要和质量进行平衡。

在这里插入图片描述

  • 总结
    1. RSM共需存储4种信息:光源空间深度(shadowmap)、世界坐标(用于比较距离)、法线(用于计算方向性)、光源光强flux
    2. 因为RSM的效率上和效果上的缺点,实际开发中应用并不多。但它是后续很多算法的基础,比如LPV,其思想值得借鉴。

(2)三维空间方法

三维空间的2个方法不会像RSM那样说的那么细节,因为内容实在太多了。

二,光线传播体积Light Propagation Volumes (LPV)

  • LPV是由 CryEngine3 提出的一种基于RSM和球谐函数的、实时的、无需任何预计算的全局光照技术,效果又快又好且不含预处理,比如《孤岛危机》中就使用该技术。
  • 其核心思想是将场景划分为一系列三维网格(体素化)来模拟光线的传播,随后利用「Radiance在直线传播过程中保持恒定」这一特征,计算出每个shading point上的间接光照。

LPV步骤:

  1. 生成(Generation)----确定哪些点可以作为次级光源计算(接收直接光照的点):用RSM找到次级光源(可以采样来降低次级光源数量)。

  2. 注入(Injection)----这些点接收到的直接光照放入“场景格子”中:定义3d空间网格、计算任意格子内所有次级光源往周围发射的radiance的初始值(光线分布),然后用SH(2阶即可–4个)来压缩替代。
    在这里插入图片描述

  3. 传播(Propagation)----在网格中传播radiance:每个格子向他空间相邻的6个格子传播(不考虑可见性),然后更新迭代SH直到稳定(一般更新4、5次就可以稳定)。
    在这里插入图片描述

  4. 渲染(Rendering)----渲染结果:已知每个格子所受光照情况,因此对于任意着色点,只需使用期所在格子的sh计算即可。

LPV的问题

  • 由于注入和传播时没有考虑可见性,会出现“背面也被照到”的Light Leaking漏光现象,根本原因其实是网格划分精度不够导致的。
  • 这里又涉及一个质量和性能的取舍问题,工业界一般使用自适应的网格尺度----级联网格(类似LOD的加速方式)。
    在这里插入图片描述
  • tips:
    1. 格子数量一般比场景分辨率(像素数量)要小一个数量级。
    2. LPV因为使用了SH压缩替代,所以会假设次级光源都是diffuse的(glossy用sh会产生强烈模糊)
    3. LPV的计算都是实时的,没有预处理,算是一个4pass算法。

三,体素全局光照Voxel Global Illumination (VXGI)

  • 也是一个2pass算法
  • 作为体积渲染方法质量非常好,可与光追媲美,但开销也很大并且有一定预处理需求(层级化),动态实时非常慢。
  • 与RSM(也是2pass)的主要区别:
    1. RSM中的次级光源是每个像素代表的微表面,而VXGI的次级光源是已被离散化的格子(类似我的世界的格子场景),而这些格子会被划分成一个树形结构(hierarchical voxels)(稀疏八叉树划分)。
    2. RSM传播只做一次,而VXGI的第二个pass从相机出发(camera ray)打到任何像素上,再根据像素材质计算间接光贡献,如果是glossy表面会形成圆锥反射,即Cone-Tracing计算。(每个像素计算,比LPV慢很多)

VXGI步骤:

在将场景使用八叉树划分法分级成层级结构后:

pass1:light pass

  • 主要计算被直接光照照亮的体素及其间接光照的反射方向。
  • 虽然都是以体素为单位,但与LPV不同的是,VXGI记录的是入射光线(绿色)和法线(橙色)的分布,再结合材质计算间接光照分布----方向与锥角大小(可以支持glossy)。
  • 在层级结构上,计算完低层级体素后,将八个叶子节点的结果相加就得到高一级的间接光照分布了。
    在这里插入图片描述

pass2:camera pass

  • 对于glossy:通过pass1获得的Ray-Cone Footprint(类似锥截面)在传播过程中扩散变大的截面大小,在八叉树中的相应层级查询(截面越大查询体素越大),就可以得到所有着色点的irradiance了(类似mipmap方法,将纹理查询改为子树遍历)
    在这里插入图片描述

  • 对于diffuse:VXGI会将出射方向看做若干圆锥(忽略间隙),暴力计算(多一层计算),同时效率也低一些
    在这里插入图片描述

(3)屏幕空间方法

屏幕空间实时渲染是指对各pass渲染完之前的各个帧缓存结果用后处理修饰的方法。在延迟渲染下可以在屏幕空间获得更多信息,也就延伸了这些屏幕空间算法。

  • 屏幕空间算法特点:
    1. 便于支持各种滤波
    2. 解除场景复杂度对算法的限制
    3. 由于相机观测视角限制会有信息丢失

这里介绍SSAO,HBAO,SSDO、SSR四种屏幕空间方法。

四,屏幕空间环境光遮蔽 Screen SpaceAmbient Occlusion(SSAO)

  • 学习ssao之前得先知道什么是ao,ao描述了距离较近的物体之间相互遮挡环境光导致变暗的程度(shader里有这个贴图),算法非常简单效果不错。
  • SSAO相当于是全局光照的近似,在一个后处理的camera pass里渲染,没有预处理
  • 原理就是假设间接光照为常数(类似布林冯着色模型中的环境光),但认为只有一些区域能够接收到这个常数光(可见性)(在一些3d建模软件里也有类似设定----天光),同时假设物体都是diffuse的来解AO。

概念理解

物理理解:下图表示AO越大接受的间接光照越少物体就越暗。
在这里插入图片描述
数学理解,从渲染方程入手进行分析:
在这里插入图片描述
根据积分近似公式把V项拆分
在这里插入图片描述
可以得到:
在这里插入图片描述
其中,蓝色框在AO技术中叫做 k A k_A kA,可以理解为当前着色点ao在所有方向上的加权平均值(cos看做权重),而由于我们已经假设间接光照为常数并且BRDF为diffuse,橙色框中内容几乎是一个设定值了。(这个近似是准确的,完全符合近似的小范围、光滑的条件)所以SSAO最后其实就是计算 k A k_A kA

  • 这里可以吧cos和dw一起处理是因为cos·dw是有明确物理意义的,即微分在单位圆上的面积投影
    在这里插入图片描述
  • 冷知识,以前写的dw中的d在公式里都写错了,人家不是d而是“\mathrm{d}”---- d \mathrm{d} d

「这里讲这么细是因为一些资料比如RTR4里对AO这块的内容讲的及其混乱,老师觉得直接从渲染方程推导最好理解了。各类书籍推导irrandience老师认为没必要,」

在屏幕空间计算 k A k_A kA

在屏幕空间没有空间信息,因此无法做ray tracing等操作。所以ssao大胆假设操作如下:

  1. 以屏幕上的任一像素点为中心,R为半径的球体内随机采样n个点;
  2. 通过相机获得的深度信息z-buffer判断采样点与可见平面的前后深度关系,在可见面之后的采样点认为不可见。(会出现误判,如中间球右下红色采样点的情况,但不管)
  3. 计算可见点的概率占比,如果大于0.5,则不应用ao,如果小于0.5,则该值作为visibility值。(ao概念是半球上的遮挡,本方法用的是球形采样,又获取不了法线信息,因此取0.5作为半球假设的值;同时也没办法考虑cos加权的事)
    「有了延迟渲染技术以后呢,就可以获取屏幕坐标的法线等信息,可以更准确的在法线半球里采样以及和cos做加权啦」
    在这里插入图片描述
  • 问题:因为上述遮挡计算错误的问题会导致不该出现遮蔽的地方也产生的阴影,但问题不太大而且不好解决,实际中一般就这样了……
    在这里插入图片描述
  • tips:
    1. 采样点越多越精确,但实际一般就64次以下的采样,得到noisy的图后再去进行降噪(作为阴影叠加后大差不差……)。
    2. 采样半径小了可以缓解错误问题,但效果也随之减弱。

五,基于水平的环境光遮蔽 Horizon-Based Ambient Occlusion(HBAO)

  • HBAO相比SSAO改善了深度错误导致多余阴影的问题,也大大减少了采样频率,是目前手机端最主流的环境光遮蔽算法。
  • 主要思路是在已知法线的前提下,用多次光线step找到着色点切平面与遮挡物采样点形成的最大角度,通过角度计算遮挡程度。

原理

  • 本算法定义的AO公式: A ( p ) = 1 − 1 2 π ∫ Ω V ( ω i ) W ( ω i ) d ω i A(p) = 1- \frac{1}{2π} \int_Ω{V(ω_i)W(ω_i)}\mathrm{d}ω_i A(p)=12π1ΩV(ωi)W(ωi)dωi
    即从着色点p往四周发射射线,在半球Ω的半径R内有遮挡的积分,其中W是一个距离线性衰减函数。
  • 但作者认为计算ao不需要像公式计算整个半球的可见性那么复杂,可以简化为对p点若干方向上进行若干纵向采样,求出这几个方向上的最大遮挡角度,再取平均即为p点的ao。下边左图是纵向采样的示意图,右图是p点选取若干方向的示意图。

在这里插入图片描述在这里插入图片描述
因此公式就变为了 A ( p ) = 1 − 1 2 π ∫ Ω c o s ( α ) W ( ω i ) d ω i A(p) = 1- \frac{1}{2π} \int_Ω{cos(α)W(ω_i)}\mathrm{d}ω_i A(p)=12π1Ωcos(α)W(ωi)dωi
衰减函数为 W ( ω i ) = m a x ( 0 , 1 − r ( S i ) R ) W(ω_i) = max(0, 1-\frac{r(S_i)}{R}) W(ωi)=max(0,1Rr(Si)),其中 r ( S i ) r(S_i) r(Si)是采样点S到p的距离,R为限定采样范围

  • 但α角也不好求,需要点积再反三角,作者提出本算法的“视角空间求解”方法:
    在这里插入图片描述
    图上n-T是p点法线空间,虚线是view空间坐标,由图可知, α = H ( θ ) − t ( θ ) α = H(θ) - t(θ) α=H(θ)t(θ),其中t(θ)为负数。

利用三角函数公式 tan = z x 2 + y 2 \frac{z}{\sqrt{x^2+y^2}} x2+y2 z和sin = t a n 1 + t a n 2 \frac{tan}{\sqrt{1+tan^2}} 1+tan2 tan可以用s点三维坐标和t与法线垂直的性质计算出H(θ)和t(θ)的sin值,再用sin值代替角度即可得出α值。

步骤总结

  1. 求p点切线T
  2. 求 t(θ)的sin
  3. 随机一个方向
  4. 沿着该方向以一定间隔进行采样得到若干S(间隔可以加个随机offset以避免最后ao为带状)
  5. 求每个S的sin,找出最大的
  6. 求出ao
  7. 重复3-6步骤(一般四个方向),求平均ao

六, 屏幕空间方向遮挡Screen Space Directional Occlusion(SSDO)

  • 改良版的SSAO,思路和RSM相似,在屏幕空间计算一些虚拟光源的贡献,结果比SSAO准确,开销稍大一些。
  • SSAO假设所有间接光照时常数,但实际屏幕上被照亮的次级光源我们是知道的。
  • 思路:从p点向各个方向发射随机光线,如果没有遮挡说明是受直接光照;如果有遮挡就是有间接光照。
    「SSAO和SSDO假设是相反的:SSAO假设p点可以接收到四面八方的间接光照—除非被遮挡(意味着间接光从远处来);而SSDO假设只有被遮挡才说明有间接光照(间接光从近处来)」

SSDO计算

  1. 在p点的上半球内随机采样若干点,判断相机(view)视角下的可见性,被遮挡的点则认为会对p点贡献间接光照。如下图左,ABD点都被遮挡,C可见,则仅C点需要计算直接光。「这样用相机判断可见性会有问题,如下右图,A点明明能贡献间接光,但相机认为被挡住,判断错误----但本方法不真正trace一条光线,SSR方法可以做到」
  2. 再通过法线判断ABD三个被遮挡的点提供的间接光是否能贡献到p点,如下中图A点就贡献不到,因此只有BD两点需要计算间接光。
    在这里插入图片描述

SSDO总结

  1. 质量接近离线渲染,且由于计算周围近物的反射贡献可以从像素颜色提取,而不是ssao那样假设为定值,因此ssdo可以有更多颜色表现。
  2. 从view视角判断可见性不准确,并且没有考虑远处间接光照的贡献(理论上应该和ssao结合使用才对)。
  3. 由于屏幕空间的限制会丢失一些信息,比如下图光色面的间接光照到侧面及背面后就无法计算其贡献了。
    在这里插入图片描述

七, 屏幕空间反射Screen Space Reflection(SSR)

  • 老师认为这个方法可以理解为Screen Space Raytracing(也是SSR),因为SSR其实就是在屏幕空间做光线追踪(相机看到的一层模型下的光线追踪)。「之前的方法都是全局光照的近似算法,没有真正的进行光线追踪,在有延迟渲染后屏幕也可以获取法线等必要信息了,SSR也因此产生。」
  • 反射其实就是全局光照,而屏幕上能看到的反射内容绝大部分都是屏幕上已经有了的东西
  • SSR两个步骤:1,光线与相机看到的一层模型求交;2,shading

SSR计算过程

  • 基础镜面计算过程(对fragment来说):
    1. 计算反射光线
    2. 用深度追踪光线找到交点----在视角方向的镜面方向上,步进查找深度,直到相交(步长可调整)
    3. 用交点的颜色作为反射颜色
      在这里插入图片描述

动态步长计算方法(Hierarchical ray trace)

上述计算交点的步进方法太慢了,那有没有一种可以先跨一大步缩短距离然后再一点点步进的办法呢?----动态步长

如左图,预先制作一个“最小值”mipmap金字塔(上层不取平均而取最小–离场景最小—深度学习里的min pooling),这样做相当于在场景中按照深度分了n层深度包围壳,然后就可以在步进的过程中快速定位,实现加速,见右图。「该方法等于在危险的边缘疯狂试探,哈哈哈哈」
在这里插入图片描述在这里插入图片描述

SSR总结

  • 问题:
    1. 屏幕空间上信息会丢失,并且屏幕上没有的东西就不反射了
    2. 硬边问题不自然,需要做软化处理
      在这里插入图片描述在这里插入图片描述
  • 在shading这个步骤上可以实现粗糙、水面拉长、不平、越远越模糊等各种效果,都跟brdf等性质相关,做好shading就可以。
    在这里插入图片描述在这里插入图片描述
  • 优点
    1. 光滑和镜面反射效果很好,diffuse也可以做但效率稍慢
    2. 没有spike(与距离平方有关)和occlusion的问题(实时渲染课上不提了,老师说)

参考资料

1,个人笔记:实时全局光照
2,Light Propagation Volumes
3,【论文复现】Image-Space Horizon-Based Ambient Occlusion
4,【论文复现】Efficient GPU Screen-Space Ray Tracing

猜你喜欢

转载自blog.csdn.net/yx314636922/article/details/126229172