目录
二、Light Propagation Volumes (LPV)
三、Voxel Global Illumination (VXGI)
四、Screen Space Ambient Occlusion 屏幕空间环境光遮蔽 SSAO
Horizon Based ambient occlusion—-HBAO
五、Screen space Direction Occlusion (SSDO)
六、Screen space Reflection(SSR)
全局光照就是直接光照加上间接光照,通过模拟光线的传播路径,将物体反射的间接光纳入计算,从而提高结果真实感的一种渲染技术。
在实时渲染中,全局光照是比直接光照多一次bounce的间接光照.如图中,光线弹射两次,先打到红色的墙壁上,在达到box面上,最后被camera/eye看到,这就是在rtr中要解决的所谓的"全局光照"。
图右,从camera出发打出一条光线到点P,P点又往场景中不同的方向发射光线,如果打到光源则表示接受的是直接光照,如果没打到光源而是打到了点Q,那么我们认为P点接收到的光照是从Q点反射到P点的Radiance,也就是Q点接收到的直接光照所反射出的光照打到P点上。点Q被当作次级光源(Secondary Light Sourse)用自身反射的光照来照亮其他物体。
要得到p点的光照结果,我们需要知道:
- 哪些东西是次级光源
- 每个次级光源对p点光照的贡献
一、Reflective Shadow Map(RSM)
原理:处理完直接光照以后,在Shadow Map中被照亮的点直接当作次级光源使用,并影响附近的点,当作间接光照照亮它们。
哪些东西是次级光源?
使用shadow map,shadow map上每一个像素可以看成是一个小surface patch,是一个次级光源,我们假设所有的反射物(次级光源)都是diffuse的(对于不同的P点来说出射方向是不知道的,无法计算P点的shading的,为了不依赖于观察方向)。
每个次级光源对p点光照的贡献?
- Radiant Engery:光能–>一个区域内光子能量的总和,用Q来表示,单位是焦耳(J).
- Radiant Flux:光通量–>在单位时间内穿过单位截面积的光能.
- Radiant Intensity:一个单位立体角上对应的能量。(单位立体角上的光通量)
- Irrdiance:在一个单位面积下对应的能量。(单位面积上的光通量)
- Radiance:一个单位立体角下单位面积上的能量。(单位立体角上通过单位投影面积的光通量)
图右,q是一个patch去照亮点P,将其转化成面积的积分。(把立体角的积分变成了对light区域面积的积分),对于每个次级光源点来说,由于我们假设它的brdf是diffuse的,因此次级光源的fr积分后是个常数。v表示次级光源对p点的可见性,选择忽略。
代入fr和li,有:因为在分子中有两个Xp-X,当把这两个放到分母中后,结果与我们推导的结果一致,同为2次方。
由于可见性、方向性以及距离的不同,对于某一个着色点,认为shadow map上所有的pixel不可能都有贡献:因为远处的次级光源贡献很少,通常只要找距离足够近的次级光源就行了。
加速方法:我们认为,对着色点x影响大的间接光源在shadow map中一定也是接近的。
- 先获取着色点x在shadow map中的投影位置
- 在该位置附近采样间接光源,多选取一点离着色点近的VPL,并且为了弥补越往外采样数越少可能会带来的问题,引入了权重,越近了权重越小,越远的权重越大。
数据存储:
优点:好实现。RSM效果通常应用于游戏中手电筒的次级光照.
缺点:
- 性能随着直接光源数的增加而降低(因为需要计算更多的shadow map)
- 对于间接光照,没有做可见性检查,无法判断次级光源和当前Shading Point的可见性关系
- 有许多假设:反射物需要是diffuse等
- 需要在质量和采样率上做一个平衡
二、Light Propagation Volumes (LPV)
把场景分为3D的网格,让所有次级光源进行传播迭代。用直接光源找出所有次级光源以后,将他们的方向,光照等信息记录在格子内,每次迭代将它们传播到周围的格子;迭代若干次以后,每个Shading Point根据当前处于的格子拿到次级光照信息。
优点:快,质量好,解决一部分RSM的问题。
如果我们能获得任何一个Shading point上来自四周的radiance的话,就可以立刻得到其间接光照,我们假设光在传播过程中,radiance是uniform的。
- 找出接收直接光照的点
- 把这些点注入(inject)到3D网格中作为间接光照(虚拟光源)的传播起点.
- 在3D网格中传播radiance
- 传播完后,渲染场景
与RSM一样,首先通过Shadow Map找出接受直接光照的表面或物体(光源数量可以通过采样一些进行简化从而降低次级光源数量,最后获得一系列虚拟光源)
把场景划分为若干个3D网格(体素),把虚拟光源注入到其对应的格子内,一个格子内可能包含许多不同朝向的虚拟光源,把格子内所有虚拟光源的不同朝向的radiance算出来并sum up从而得到一个往四面八方的radiance。
由于是在空间上的分布,也就可以看作是球面函数,自然可以用SH来表示(工业界用两阶SH就可以表示各个方向上的radiance初始值)
3D网格,因此可以向六个面进行传播(上下左右前后),由于radiance是沿直线传播的,我们认为radiance是从网格中心往不同方向进行传播的,穿过哪个表面就往哪个方向传播,每个格子计算收到的radiance,并用SH表示,迭代四五次之后,场景中各voxel的radiance趋于稳定。
对于任意的shading point,找到他所在的网格获得所在网格中所有方向的Radicae渲染。
LPV提供的这种实现全局光照的方法不需要任何的预计算,因此可以支持各种变化的场景,做到真正的”实时“。但体素划分精度不足时,会出现漏光的现象
按理说点P反射的radiance是无法照亮墙壁的背后,但是由于我们的假设,会导致墙壁后面也被间接光照照亮,也就是所谓的漏光现象。房屋的下部本不应该被照亮,但由于使用了LPV导致了light leaking现象。
- 解决漏光现象:需要我们划分的格子足够小,这样会导致存储量增多。
- LPV会假设次级光源是diffuse的吗?一般只要用了SH都会假设diffuse
- 体素划分一般多大比较合适?比场景分辨率少一个数量级
- 这是预计算吗?不是,这是实时的,在任意一帧都要去做这个计算.
- 传播过程中会一直不稳定传播吗?不会,没有外界影响的话最后肯定是会收敛的。
三、Voxel Global Illumination (VXGI)
对场景构建体素网格,在第一个Pass中存储所有次级光源的贡献和法线信息,并更新Hierarchy层级结构;Pass2中对每个次级光源射出一个圆锥形的射线,为其他Shading Point做贡献,diffuse类型的用多个圆锥射线来覆盖亮半球。
优点:效果好。
RSM 中次级光源是像素中所包含的微小表面,这些表面是根据Shadow Map来划分的。VXGI把场景完全离散化成了一系列微小的格子。从camera出发,就像有一个Camera Ray打到每一个pixel上,根据pixel上代表的物体材质做出不同的操作,如果是glossy则打出一个锥形区域,diffuse则打出若干个锥形区域,打出的锥形区域与场景中一些已经存在的voxel相交。
Pass1:Light pass
记录的是直接光源从哪些范围来(绿色部分),记录各个反射表面的法线(橙色部分),通过输入方向和法线范围两个信息然后通过表面的材质,来准确的算出出射的分布。
Pass 2 :Camera pass
对于任何一个像素,知道了Camera Ray的方向。
Glossy:向反射方向追踪出一个锥形(cone)区域:
基于追踪出的圆锥面的大小,对格子的层级进行查询,就是对于场景中的所有体素都要判断是不是与这个锥形相交,如果相交的话就要把对于这个点的间接光照的贡献算出来。(mipmap)
diffuse:VXGI 通常会将出射方向看做若干圆锥,而忽略锥与锥之间的间隙。
LPV是把所有的次级光源发出的Radiance传播到了场景中的所有位置,只需要做一次从而让场景每个Voxel都有自己的radiance,但是由于LPV使用的3D网格特性,并且采用了SH进行表示和压缩,因此结果并不准确,而且由于使用了SH因此只能考虑diffuse的,但是速度是很快的。
VXGI把场景的次级光源记录为一个层次结构,对于一个Shading Point,我们要去通过Corn Tracing找到哪些次级光源能够照亮这个点。
四、Screen Space Ambient Occlusion 屏幕空间环境光遮蔽
Real-Time Global Illumination (screen space)屏幕中的实时全局光照
使用的所有信息都来自“屏幕”,做全局光照之前屏幕上能看到的信息。
AO(环境光遮蔽):在场景中加入AO信息,让物体与物体之间的相对位置表示的更明显,让整个画面更具立体感。AO是一个对于全局光照的近似。
在计算全局光照过程中,由于我们无法在屏幕空间中直接获得间接光照,所以一般会假设间接光照强度为一个定值,但并不是每个方向都可能接收到间接光照(incident lighting),也就是不同位置的Visibility是不同的,假设物体是Diffuse的。
左边是任何一个shading point上来自任何方向的间接光照(incident lighting)是一个常数.右边是我们考虑了任何一个shading point上不同方向的visibility后得到的结果。图中红色部分表示被遮挡,黄色部分表示未被遮挡,我们可以明显的得出一个结论,左边的 Shading point要比右边的亮一点。
把visibility项拆出去, 对蓝色方框,化简为下式。橙色方框,物体是Diffuse的,因此BRDF也是常数最终结果就是漫反射系数×间接光照强度Li。
不是对dwi进行积分,而是对cosθ dw进行积分,采用投影立体角。立体角是单位球上的一个面积,关于cos中的θ,我们认为θ从北极开始到南极是180度,那么立体角 * cosθ 是我们把单位球上的面积投影到了单位圆上.
- 间接光照是常数—Li为常数
- BRDF是Diffuse的—BRDF(fr)是常数ρ/π
- 因此这两项可以直接从积分里面拿出来,最后Rendering Equation就成了下面的形式,也就是算Visibility的积分。
算加权平均的visibility:
我们需要在shading point往不同方向trace判定究竟有多少方向被挡,这样说其实是不准确的,我们以一个极端的例子来看,在一个封闭的屋子里,不管你从哪一个shading point去trace哪个方向,不论trace的光线会不会打到周围的物体,我们这跟光线不会出去这个封闭的屋子,也就是最后的结果只能是被遮挡住,所得到的Ambient Occlusion只会是0.
这是因为,反射光肯定是在有限的距离里反射过来的,也就是间接光照是从一定范围内来的,不可能是从无限远处,因此如果我们做tracing肯定也是在一定范围内的,这样就解决了tracing无限远的话一定会被遮挡住这个问题.
但是出现了新问题,就是超出这个范围的光照就被我们忽略了,也就是我们忽略了那些在距离外的间接光照,如果我们限制范围太大,那么所有东西都有可能遮挡住,如果范围太小,我们会忽略大部分的incident lighting.因此我们限制在一定范围内,这是一个trade off,通常会选一个合适的范围,也就是找一个合适的球的半径-R.
- 首先从相机出发,得到屏幕空间的深度信息,写入z-buffer
- 对屏幕空间的任意一个像素(着色点),在以它为中心、R为半径的球体范围内随机寻找数个采样点,判断其可见性
- 若该采样点的深度大于它在屏幕空间对应的深度,则认为该点不可见,记可见性为0(下图绿点)
- 计算可见性为1的采样点的占比,作为当前像素的visibility值
上图中蓝色区域部分表示的是场景物体,也就是说蓝色区域外的绿点是可以被shading point直接看到的.图的一个红点出现了问题,因为我们从camera看过去,这个点比所圈部分的深度深,因此虽然这个红点是能够被Shading Point看到的,但是由于是从camera出发,这里被判断为了看不到。
我们是知道那一片的地板是不可能被石椅所遮挡的,但是在开启了SSAO,由于我们是从camera出发去判断深度的,所以这一块不可避免的出现了错误的AO.
Horizon Based ambient occlusion—-HBAO
当有了场景normal之后,我们就知道去采样哪半球,就可以只去算半球的情况了,同时也可以对不同的方向来加权(靠近中间大,靠近两边小),使用多次光线步进找到着色点切平面与遮挡物采样点形成的最大角度,再通过这个角度来计算物体与物体间的遮挡程度,从而完成对环境光遮蔽的近似。
五、Screen space Direction Occlusion (SSDO)
对于SSAO的改进算法,,类似于SSAO,在周围随机找点,看Z-Buffer的遮挡关系,与SSAO相反的是,被遮挡的点,从View方向找到深度最小的点,利用那一点对当前点做出贡献;否则,可以利用环境光做出贡献。
AO能够产生变暗的效果使得物体相对感更强烈,DO蓝色面上会接收到一点黄光,黄色面上也会有一点蓝光。SSDO只能解决一个很小范围内的全局光照。
- 在SSDO中,我们要用直接光照的信息,但不是从RSM中获得,而是从screen space中得到.
SSAO和SSDO是完全相反的两个假设:
- 在AO中我们认为红色的框里能接收间接光照,黄色框里无法接收间接光照,然后求出加权平均的visibility值,也就是假设间接光照是从比较远的地方来的。
- 在DO中,我们认为红色框里接收的是直接光照,而黄色框里才是接收到的间接光照.因为间接光照一定要打在某个物体上再反射到P点。假设间接光照是从比较近的反射物来的。
当V=1时是直接光照,而DO的计算是计算间接光照的,因此这个我们完全不用去计算与考虑,当V=0时是间接光照。
考虑点P法线部分的半球,判断从P点往A、B、C、D四个方向看会不会被挡住,这里A/B/D这三个点的深度比从camera看去的最小深度深,也就是说PA,PB,PD方向会被物体挡住,因此会为P点提供间接光照。
右图,A点虽然会被canmera看不到,但是AP之间是不会挡住的,实际上A点需要提供间接光照给P点,但在SSDO算法中则不提供。
六、Screen space Reflection(SSR)
Screen space Raytracing,本质上在屏幕空间做光线追踪,只需要屏幕空间中已有的信息,也就是从camera看去场景的得到的这样一层“壳”。考虑任何光线(不单单是反射光)与场景中这层壳去做求交。找到交点后,算出对shading point的贡献值。
在屏幕空间下,从View方向看去,对每个Shading Point做简单的Ray Tracing,来获得当前点的次级光照信息。
镜面反射:假设场景中已经渲染出来了上面的部分,对于地面还没有进行渲染,如何把反射的信息加进去。对于任何一个像素:
- 知道shading point的观察方向后,可以得出其反射方向
- 从Shading point点沿着反射方向延长找到与屏幕的壳的交点
- 将交点的颜色作为反射的颜色记录到shading point。
specular反射:
- 我们有一个还没有进行反射的场景,如shaded scene上的地面还并没有得到反射的结果
- 得到图中的normal信息和深度信息
- 进行SSR,我们想要的是对于地面的每一个pixel,我们都想计算出其反射到场景中的得到的值是多少
- 得到反射的值后,将结果加到场景中去,也就是在地面上的黄点反射到场景的壳上的绿色,进行求交算到的结果加入到黄点中
- 得到一个镜面反射的效果
求反射光与场景的相交:Linear Raymarch
让光线按一定步长向前迈进,同时判断是否与物体产生相交。沿着反射方向以一个固定的步长逐步前进,并将每次停止时的深度与壳的深度进行比较,如果浅于壳,则继续前进,比壳深,则停止求交,也就是我们用深度来进行可见性判断。质量取决于步长的大小,步长小越精准,同时计算量也越大,因此步长太大太小都不行,在没有SDF的情况下,步长只能是一个定值。
动态决定步长:Hierachical ray trace
类似Mipmap,对深度缓存中的屏幕深度生成一个层级纹理,这个过程并不是像Mipmap那种做双线性插值四个像素的深度平均,而是取四个像素的最小深度直接写入缓冲。
- 在3D空间做光线追踪时,为了加速光线与场景求交,我们通常会做一个加速的层次结构(BVH/KD-tree)
- 如果我们用最小值操作的mip-map会得到一个保守逻辑:如果一根光线与mip-map中的上层结点不相交,那他肯定也不会与这个结点的子节点相交。
走格子(像素)2-4-8等递增,判断有交点之后,退回上一级再判断。但是做不了准确的起点不在2的K次方上的深度的查询。
缺点:SSR仍然有屏幕遮挡的问题,会丢失一些反射中的模型信息(因为只有屏幕中的信息);同样的,因为只有屏幕空间的信息,在边缘外的会被截断(可以利用距离反射点越远,越虚化来做处理)。
计算shading:
SSR计算着色的方法几乎与路径追踪一模一样,对于任何一个shading point,看到的radicance就是对半球进行积分,如果是specular材质则cast一次,相当于光线打到物体的哪里,就用它所发出的radiance就可以。glossy材质就用蒙特卡洛重要性采样多次计算(这里需要假设次级反射物为diffuse)
SSR不用考虑光线的平方衰减,并且可以保证交点的可见性,这是因为SSR的采样对象是brdf本身,而只有在对光源采样的时候才要考虑衰减和遮挡。
暂无评论内容