图形渲染——Shadow Mapping(Games202)

Shadow Mapping——阴影

一、SM的数学基础

图形学上经常经常使用不等式的约等式来进行计算(当满足特定条件下不等式几乎取得等号,相当于约等式),其中一个比较常见的约等式:
\int f(x)g(x)dx\approx \frac{\int fxdx}{\int dx}\int g(x)dx

其中的分母可以看做一个归一化常数。

二、影阴影

对于点光源或者方向光,照射到观察点p的方向是恒定的,因此不存在本影和半影,就是硬阴影。

换句话说,在点光源与方向光照射下,只存在能看到和不能看到,并没有中间过渡带。

还记得我们在上一篇介绍的渲染方程吗?

L_{o}(p,w_{o})=\int L_{i}(p,w_{i})f_{r}(p,w_{i},w_{o})n\cdot w_{i}V(p,w_{i})dw_{i}

这是一个很长的积分式,我们解释过V代表是否可见,则其余部分就是实际光照产生的影响,我们不妨将上述公式进行拆解:
L_{o}(p,w_{o})=\frac{\int V(p,w_{i})dw_{i}}{\int dw_{i}}\int L_{i}(p,w_{i})f_{r}(p,w_{i},w_{o})n\cdot w_{i}dw_{i}

拆解开的公式就很明了了,后边表示对于着色点p,实际的光照出射,但同时要考虑前边V(可见项)的值(来源于SM),对于硬阴影而言就是非0即1,表示可见与不可见,由此形成硬阴影。

补充:如何确定0还是1?

SM的基本原理,从光源观察生成深度图1(depth1),从摄像机观察生成深度图2(depth2)。对于p所在像素,如果depth1<depth2(人能看见但光不能看见),即为阴影,V=0;否则V=1;

因此确定V实际就是在光源w_{i}方向上查询对应像素的两张深度图。

能够使用约等吗?

一般满足两个条件约等成立:
1.积分限很小。这里引入unity shader的一个说法,精确光源,换句话说我们积分的方向往往就是一个极小的角度范围,所以第一条满足;

2.g(x)足够光滑,也就是g(x)=L_{i}(p,w_{i})f_{r}(p,w_{i},w_{o})n\cdot w_{i}足够光滑。先看第一项,对于来自小方向w_{i}的光,到达p是逐步平滑衰减的,甚至方向光都没有衰减;然后是BRDF项,对于diffuse的光是非常平滑的,specular比较锐利,但是在小范围,小角度变化也不算太大。

综上,使用约等式是合理的。

三、软阴影

与硬阴影的差别就在于阴影的边缘,软阴影是渐进的,是过渡的。所以回到我们的渲染方程:
 L_{o}(p,w_{o})=\frac{\int V(p,w_{i})dw_{i}}{\int dw_{i}}\int L_{i}(p,w_{i})f_{r}(p,w_{i},w_{o})n\cdot w_{i}dw_{i}

既然硬阴影是由于V的非0即1进行的计算,那么要实现软阴影,得到平滑的过渡,则V\epsilon [0,1],此时的V不再是非0即1的二进制,而是根据周边环境确定的浮点数,根据浮点数的大小确定光照对像素着色的贡献。因此问题转化为浮点数如何得到?

PCF:

很简单的一个思路——卷积!

确实,这是一个很类似于抗锯齿的做法,叫做PCF(Percentage Closer Filtering),核心思想如下图:

 我们首先还是需要SM来标记像素着色的非0即1作为原始数据,然后就是使用一个卷积核(或者叫做模板)基于像素中心固定尺寸采点,加权,计算得到一个0-1的可见性占比值V(Games例子):

 打破了非0即1的限制,也就打破了硬阴影与软阴影之间的界限。But, cost?

是的相比于我们制作硬阴影时只用查询像素对应的SM,使用PCF要取决于卷积核的大小,比如上边就需要查询9次,甚至为了达到更佳的效果需要25,49,81...这个开销是很大的,并且到底使用多大的卷积核对结果也有影响,太大甚至导致场景虚化,范围而不真实(太大就完全没有本影区都是有可能的)。对此,提出了另一个变种PCSS。
PCSS:

所谓PCSS(Percentage Closer Soft Shadow),我把它称为自适应filtering size的PCF。他的自适应逻辑是基于距离的,在Games中提到下图:

可以看出靠近笔尖的地方几乎是硬阴影,远离笔尖的阴影更倾向于软阴影。这里所说的靠近与远离是指阴影投射物(钢笔)与阴影接受物(纸)在光照方向上的距离,距离越大越倾向于软阴影,那么我们的思路就是:

距离与filtering size正相关!

使用如图所示相似三角形解决size的确定问题:

结果w_{Penumbra}就匹配我们的size(必须是奇数个像素大小),此时使用自适应的size对SM进行批量化的处理。可以看出,size与光源大小(影响半影区)还有blocker distance(本体与阴影在光源方向距离)有关。那么问题随之而来,如何确定blocker distance,换句话说也就是公式中的d_{Receiver}或者是d_{Blocker}

最开始我认为一个像素对应一个深度,但是这样做是比较草率的:
我们只能从像素的中心去观察,那么由于像素是离散的,得到的距离也就是离散的,特别是一些法线与光线向量近乎垂直的面,相邻像素的深度变化非常大,导致size可能突变,结果不尽如人意,因此我们不能使用一个像素的深度,而应该基于一种平均深度的思想,使变化趋于平缓。

如果要使用平均深度,基本思路也是卷积核,两种方案:

1.最简单:固定卷积核尺寸,得到中心像素平均深度,代入上式匹配size;

2.二次自适应:通过观察点p与light边界点的连线得到一个在SM上的投射区域,那么这个区域范围得到一个自适应的卷积核,计算得到平均平均深度。

 从上边的过程我们不难发现:频繁操作SM,这都是相比硬阴影增加的开销,这是比较让人头疼的。

对此,一个简单的策略就是随机采样,减少采样数(统计到的0,1值进行平均)。这种人为操作会导致噪声的产生,对于噪声,现在图像空间降噪技术发展得不错,只要是我们可以快速得到一张基本正确的带噪声的渲染图,利用图像空间的后处理也能得到不错的效果。

还有另外一种处理办法那就是Variance Soft Shadow Mapping(VSSM)基于方差的软阴影。

VSSM:

我们提到PCSS的最大问题是采样带来的巨大开销:

Step1:根据SM标记不可见0,可见1,标记原始的V;(SM逐像素采样,判断)

Step2:计算filtering size,并采样SM获得平均深度作为blocker depth;(SM采样,每个像素进行固定次数或者根据光源边界自适应采样次数)

Step3:对Step1标记的0或1进行filtering size次采样,产生最终的V;

我们的目的都是得到V,现将第一步与第三步合起来看,两步都是得到V的数值,有没有办法不采样就得呢?

V=像素可见的概率!

既然提到了概率,那就使用概率论来解决。首先,为了好理解我们以SM在一个范围内的深度值满足正态分布为例(随机分布),要表示正态分布,只需要均值和方差:

x为自光源看过去的SM深度值:

1.均值:MipMap或者SAT;

2.方差:\sigma =E(x^{2})-E^{2}(x)

对于方差,我们需要在存储depth的SM中,使用其他通道存储depth^{2}就能计算得到方差。

有了均值与方差我们就得到一个正态分布:

 他表示的是光源角度下的SM,一定考察范围内深度值的分布规律,那么此时我将对应像素自摄像机看过来的深度放入进行比较,就可以得到在这个范围内,SM中depth小于摄像机中depth的概率P,也就是我们在硬阴影所说的depth1<depth2的概率P,也就是说待着色像素被其他像素挡住的概率P,即像素对光源不可见的概率P:

P=1-V;

由此得到V。我们现在仅仅是在Step2确定范围的时候对SM有采样,就得到了V,直接取消了Step1和Step3的采样过程,实际上Step2也可以不采样(等下再说)。回到我们对Step1和Step3的处理,是基于正态分布进行的,计算正态分布实际是一种查表的方式,很多语言都支持,erf函数正是如此:

double cdf=erf(0.5);

但是,还有更加绝妙的做法:切比雪夫不等式

P(x>t)\leq \frac{\sigma ^{2}}{\sigma ^{2}+(t-\mu )^{2}}

根据方差与均值,直接给出x>t的概率的上届,当我们使用约等式的时候,也就是说估算:

P(x>t)\approx \frac{\sigma ^{2}}{\sigma ^{2}+(t-\mu )^{2}}

将t看做从相机看过来的深度值,方差与均值为SM一定范围的(MipMap)查询结果,则概率表示SM中深度大于摄像机深度t的概率P,也就是depth1>depth2的概率P,即像素可见的概率P:

P=V;

注意切比雪夫与我们假设的正态分布的结果表达上可能不同,但是结果意义完全相同,使用切比雪夫不需要查找正态分布表就能完成计算,但是要求t>\mu才准确。

对于Step1和Step3的改进到此为止,我们没有多次采样SM却得到了V。现在来看看Step2,需要通过采样SM,通过遮挡物的平均深度表示blocker depth,确定filtering size。这里要强调遮挡物这个概念,比如,我们在摄像机视角看到的深度是8,而从SM看过来的范围内的depth^{2}值采样值如图:

那么我们就任务只有小于8的位置才是遮挡物,是要求解遮挡物的平均而不是整个的平均。对于整个的平均值可以使用MipMap或者SAT获得,但是不能直接用。同样我们也可以获得其方差,只要我们存储了depth^{2},那么能获得均值与方差有什么用呢?还是切比雪夫不等式当做约等式使用:

P(x>t)\approx \frac{\sigma ^{2}}{\sigma ^{2}+(t-\mu )^{2}}

是否意味着t=8取得的概率为P(x>8),对应的就会有P(x<8)=1-P(x>8)

那么我们基于加权的思想:
P(x>8)\bar{}\bar{Z}_{unocc}+P(x<8)\bar{}\bar{Z}_{occ}=\bar{Z}

这中间P(x>8)P(x<8)以及\bar{Z}(整体均值)都是已知的,我们要求解的是\bar{Z}_{occ}。二元一次方程。有一个大胆的假设\bar{Z}_{unocc}=t(8)。将未遮挡的平均深度假设为我们比较的初始值,这样做的基本思路源于观察:我们的投影面是一个平行于摄像机的平面(或者小范围连续光滑面)。那么就能如愿以偿的得到遮挡物平均深度,带入相似三角形,结合光源大小得到filtering size。

看看,我们从待着色点对应像素出发(使用固定范围或者基于光源大小确定一个在SM上求解平均遮挡深度的范围),并不需要逐像素采样,而是根据MipMap或者SAT得到均值与方差,结合切比雪夫估算概率,假设非遮挡平均深度就得到了遮挡平均深度,进而得到blocker depth。没有一次采样就解决了这个问题。

归纳一下,VSSM的基本过程:
1.从shading point出发,在SM圈定一个对深度的查找范围,并获得这个范围的均值,方差,结合切比雪夫得到平均blocker depth,然后得到filtering size;

2.根据filtering size在SM上估算depth的分布情况,引入摄像机观察到的深度depth2,确定像素可见的概率V;

事到如今,没有采样,通过不断地假设与估算,我们获得了V,带入渲染方程就可以得到软阴影。但是这个方法查询均值与方差,必定需要增加存储空间。由于动态物体阴影也要动态,对应的SM及其MipMap或者SAT都要动态生成,开始会有一定的开销。

最后,在VSSM这里还要解决一个问题,就是我们获得均值的办法(隐含获得方差的方法(计算式基于均值))。

MipMap:

这个方法大家都比较熟悉,特点就是:快速,近似,方形,如果要得到非方形(毕竟基于光源边界确定blocker depth的取样空间,可能出现非方向),就需要各向异性的MipMap,但还是近似的。对此就有了另一个方式:SAT。

SAT:

所谓SAT(Summed Area Table),是一种数据结构,是基于前缀和(记录自输入开始到当前位置的总和):

 这有什么作用呢?如果我们知道几项的和,难道还不知道他们的均值吗?通过上述1D的结构我们可以迅速拓展处2D的SAT结构:

从输入开始到当前位置的所有总和。

一个用他查询一个小范围总和的例子如图:

每个方格右下角点记录的数值就是自左上角点到此的前缀和,这样可以立马得到待求区域总和15,而不需要进行逐像素采样(还是有4次SAT空间的采样) 。

MSM:

最后一个话题MSM(Moment Shadow Mapping),这个方法诞生的根本目的就是为了解决VSSM中采样大多近似,概率估计的不准确问题。但是它本身也是近似的概率估计,所不同的是,他的估计更准。

在VSSM中,我们使用均值E(x),平方的均值E(x^{2}),这叫做二阶矩。有大佬就发现如果使用高阶矩会得到更好的估计结果,由此诞生了MSM,比如下图是使用不同的矩得到的对概率估计CDF的拟合效果:m阶矩就有0.5*m个台阶。

 可以看出PCF是有很多台阶的,当m=4,使用4阶矩的时候就已经可以获得一个比较可观的结果了。但是这个高阶矩的函数比较复杂,等我以后真的有机会搞清楚再来续写吧。

OK,Have a good time!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值