Global Illumination
比直接光照多一个bounce的间接光照
直接光照的物体-次级光源
计算间接光照
Reflective Shadow Maps (RSM)
shadowmap上每个像素对应的小片都是次级光源
shadowmap可以解决哪些物体会被光源照到,把shadowmap的每个像素对应的小片作为次级光源。要用次级光照照亮某个点p,就等于从点p观察这些次级光源
review:辐射度量学.一个单位立体角下对应的能量就是Radiant Intensity,单位面积下的就是Irradiance,在单位立体角又单位面积就是Radiance.
Ques1: 哪些表面会被直接照到
Sol: 使用shadow map,shadow map上每一个像素可以看成是一个小surface patch
Ques2: 对于不同点p 出射方向不知道,没法shadering
Sol: 假设次级光源都是diffuse的(不好确定光线方向) 不依赖观察的方向
Ques3: 计算每个surface patch对着色点p的贡献
Sol: 如上图q就是RSM中一个Texel所对应的patch去照亮点P
计算q对p点的贡献,要对整个立体角进行采样,浪费很多的sample,直接在light处采样然后计算p点的shading值 即把立体角的积分变成了对light区域面积的积分
小片q的brdf是一个常数(diffuse) q出射的radiance就等于brdf乘以入射的irradiance irrandance就等于flux除以点q的面积 然后把这个式子带到点p的式子Li中,就把点p的面积消掉了 就不需要计算点p的面积 将积分域中所有的结果加在一起,就是着色点最后被间接光照照亮所得到的shading值
4次方是对的 上面的$x-x_p$没有标准化
加速: 只找距离比较近的次级光源 假设把shader point投影到shadowmap上,在shadowmap离的比较近,那么就认为在世界距离上比较近 大大减少计算量
RSM 即shadowmap多存了世界坐标计算距离 多存了法线方向计算cos 多存了flux光源光强
Pros:易于实现 对于手电筒很适合
Cons:
- 有几个直接光源就得有几个shadowmap
- V项没有做(可见性)
- 太多假设diffuse reflectors, depth as distance
- sampling 采样率会导致存在一个效率与质量的trade off
RSM就是光栅化版本的离线渲染VPL方法
RSM和shadowmap一样属于 图像空间(不是屏幕) 的方法,在这里当成3D空间的方法是不会像图像空间记录不下丢失信息受到影响,且LPV方法会基于RSM
Light Propagation Volumes(LPV)
LPV就是在三维空间传播光线
间接光照最核心的问题是shadinng point接受各个方向间接光的radiance有多少 radiance在光线传播过程中不变
体素化 把场景分成格子Voxel,把格子中的点受到的直接光照注入到格子中,把格子作为次级光源传播到其它格子,实现全局光照
(体素划分一般至少比场景分辨率少一个数量级)
- Generation 用RSM找到哪些点会被直接光照照亮,得到一系列次级光源 (可以降低数量)
- Injection 先把场景分成3D网格 任意一个格子就包含一些次级光源,把这些的光源往四周的radiance加起来 使用3D纹理 用SH压缩radiance
- Propagation 传播 格子有六个面 radiance通过每个面往周围六个格子传播 看穿过各个面的radiance 不断传播最终达到一个稳态 最后得到次级光源的radiance传播过的格子
- Rendering 每个shading point 都有一个对应的格子,已经得到了每个格子的incident radiance,就能直接进行渲染
Cons: Light leaking 格子里的都会被照亮 几何比格子小 会照亮不该照亮的
Sol: 用不同大小的格子 也就是Cascade层级加速结构
假设不考虑V项
只要是用SH压缩,渲染glossy表面都会造成强烈模糊,所以一般只要用了SH都会假设diffuse
不需要任何的预计算
Voxel Global Illumination (VXGI)
2pass 场景完全离散成格子
RSM次级光源是像素中所包含的接受直接光照的微小表面,VXGI把整个场景离散成体素变成网格 可以在最小的格子基础上建立一层大格子 Hierachical树形结构
RSM和LPV计算radiance都是从次级光源出发传播一次,从而得到全局光照的结果,而VXGI是从camera出发,像有一个Camera Ray打到每一个pixel上 根据打到的像素的材质反射出一个圆锥,相交到之前计算好的voxel(即cones shading),即每个shading point 都要进行 cone tracing 的计算 光线从传播变为了追踪
- pass 1 从光源看 计算直接光照的结果 格子记录体素表面的法线分布和接受的入射光分布信息 不再像LPV一样将所有的radiance加在一起求各方向的初始值 可计算出射 (可以是glossy) 一个个体素格子考虑在一块 建立hierarchy层级
记录的是直接光源从哪些范围来(绿色部分),记录各个反射表面的法线(橙色部分),通过输入方向和法线范围两个信息然后通过表面的材质,来准确的算出出射的分布 比LPV认为格子表面是diffuse再用SH来压缩的方法要准确
pass 2 从camera看 对于glossy表面 从shading point的拉出反射的锥体和哪些voxel体素相交再计算 (有之前得到的体素的法线分布和入射光分布 可以算出其输出的radiance,将cone区域内所有体素的radiance都算出,就能得到shading point的间接光照)
不用全计算 计算圆锥内一定层级(pass1建立)即可(根据传播出的距离远近找对应层级的体素,然后找覆盖的范围) cone tracing
对于diffuse使用若干圆锥覆盖一个半球
LPV把所有的次级光源发出的Radiance传播到了场景中的所有位置,只做一次让场景每个Voxel都有自己的radiance,由于LPV使用的3D网格特性,并且采用了SH进行表示和压缩, 只能考虑diffuse, 结果并不准确, 但是速度很快。
VXGI把场景的次级光源记录为一个层次结构,对于一个Shading Point,我们要去通过Corn Tracing找到哪些次级光源能够照亮这个点。
cons: 体素化比较慢 计算量大 需要预处理 物体移动,就得重新体素化
screen
只知道camera的视角 信息只来源于当前屏幕 相当于图做一个后期处理,从而来弄出全局光照
Screen Space Ambient Occlusion (SSAO)
AO 环境光遮蔽 通过相对位置来制作阴影,通过一系列的contact shadow(接触阴影)让物体相对位置感和立体感更强,是对全局光照的近似
SSAO 就是在屏幕空间对全局光照的近似
假设:
- 间接光照为常数 (blinnphong的ambient项)
- 来自四面八方的间接光照都相同 但shadingpoint不一定都能接收到(考虑遮蔽)
- 假设物体是Diffuse的,即使是一个glossy物体也以diffuse去渲染
原理:
渲染方程将Visbility项拆开 拆出$k_A$(按cos加权平均visibility) 近似成kA和间接光照两个项 间接光照为常数 diffuse的brdf也为常数 只用计算kA
deep understanding: RTR常用不等式把一个product integral拆出一个项进行归一化 可以看作fx在gx覆盖范围内的平均 AO中 gx->间接光照和brdf 满足近似条件
$\cos\theta_i d\omega_i$就是立体角在微元面积上的投影
求$k_A$项:
在世界空间直接trace光线出去获取visibility再加权平均就能得到
屏幕空间:
- 首先从相机出发,得到屏幕空间的深度信息,写入z-buffer
- 对屏幕空间的任意一个像素(着色点),在以它为中心、R为半径的球体范围内随机寻找数个采样点,判断其可见性
- 若该采样点的深度大于它在屏幕空间对应的深度,则认为该点不可见,记可见性为0(下图绿点)
- 计算可见性为1的采样点的占比,作为当前像素的visibility值
早期camera没法又存法线又存深度时,不能通过法线判断用一个半圆来分布点,就只能靠在撒下去的点在物体内部超过半数时才计算ao,而低于半数,就视为不会被遮蔽
有可能发生如上图二所示camera认为看不到而point实际看的到的情况 但影响不大
cons:实际离得远的物体在camera视角下认为产生遮挡 false occlusions
采样周围一个圆的点数量越多效果越好,速度也越慢。那么就可以先用数量少的点数获取AO再模糊处理
Horizon based ambient occlusion (HBAO)
知道法线的情况 只考虑了一个半球 可以做cos衰减 更准确 改善冗余阴影,大大减少采样率的需求
手机端最主流的环境光遮蔽算法
使用多次光线步进找到着色点切平面与遮挡物采样点形成的最大角度,再通过这个角度来计算物体与物体间的遮挡程度,从而完成对环境光遮蔽的近似
Screen Space Directional Occlusion (SSDO)
不假设接收到的间接光照都相同 把屏幕空间被直接光照照亮的物体视为次级光源
AO能够产生变暗的效果使得物体相对感更强烈,但AO并不能做到Color Blending(不同颜色的Diffuse会互相照亮 这个颜色的表面上有旁边其它颜色的反射 而不是如AO直接整体变暗)
类似于path tracing 从shadingpoint发出随机光线看交点
DO是从遮挡(光线打到)的物体产生间接光照(来自近的地方)
AO则是从没有遮挡的方向产生间接光照 相反 (来自远的地方)
从shadingpoint打出光线,不会被挡住那么就受到直接光照,会被挡住则算出Q点接受的直接光照打到P点的贡献,从而求出P点的间接光照 也就是假设间接光照是从比较近的反射物来的 把直接光照和间接光照的贡献加起来就是全局光照
判断遮挡: 方法类似于HBAO 在点的上半球撒点,把点连接到camera,用深度图判断会不会被挡住来近似地得到shading point的遮挡情况
cons: screen space 丢失信息 只能解决小范围的间接光照(计算附近遮挡物的反射)
Screen Space Reflection (SSR)
在屏幕空间做光线追踪 不仅仅能做反射,可以做任何光线追踪
反射的绝大多数信息是屏幕内已有的信息 并不需要3D场景的什么信息
先获得直接光照,获得法线和深度,得到反射的结果,最终结果就是全局光照
得到反射的结果:
- 求交 Intersection: between any ray and the scene 反射光会和屏幕内的场景哪些像素相交
Linear Raymarch 反射光每次都往前走一定步长,直到打到场景最浅的深度,就说明和物体接触,得到相交的像素
获取步长:
Hierachical ray trace 获取动态步长 对深度图mipmap 但用最小值而不是平均值(最小池化) 和最小值不相交则不可能相交 可以跳过很多格子
1
2
3
4
5mip = 0;
while (level > -1)
step through current cell;
if (above Z plane) ++level;
if (below Z plane) --level; - 着色 Shading: contribution from intersected pixels to the shading point
SSR是对光追的简化,仅用屏幕内的物体的壳来进行光追
可以直接用path tracing算法 是specular材质则cast一次,是glossy材质就用蒙特卡洛重要性采样多次计算 但必须假设次级反射物都是diffuse 才能假设反射物反射到任何方向的radiance都是一样的
SSR不用考虑光线的平方衰减,并且可以保证交点的可见性,这是因为SSR的采样对象是brdf本身,而只有在对光源采样的时候才要考虑衰减和遮挡
SSR可以做镜面反射和glossy
cons:
- SSR受限于屏幕空间 无法反射屏幕外的物体 会导致出现明显的断点 但可以把距离远的反射结果虚化来缓解
- 不在屏幕中这层“壳”的信息是不会被反射的(是screen space算法的通病)
pros:
- Sharp and blurry reflections 光滑或者模糊的结果都能得到
- Contact hardening 反射的结果距离越近也会越清晰
- Specular elongation 镜面伸长
- Per-pixel roughness and normal 粗糙物反射体表面不影响
Ext:
- 反射可以重点采样,如果是diffuse的话还是得大量采样,但diffuse是低频的,可以SH等近似的方式获得,diffuse是最难的也是最简单
- 可以用时间和空间上的复用,时间上的复用就是一系列的预计算,空间的复用就是借鉴shading point旁边的shading结果
- 可以在先把屏幕空间的反射结果先filter
Probe-Based Global Illumination
探针(Probe) 或者说 光照探针(Light Probe),简单理解就是场景中的一个点然后给予这个点去往四面八方收集光照或者说探测光照的能力,并把往四面八方的入射光 radiance 记录下来(其实就是记录环境光
在对某个 shading point 渲染的时候就可以利用它附近 probes 的环境光信息粗略估计出它所受到的环境光信息
https://zhuanlan.zhihu.com/p/350753497
https://www.cnblogs.com/KillerAery/archive/2022/10/26/16828304.html