【技术美术图形部分】实时阴影:光栅化与光线追踪

1 实时阴影:光栅化

参考实时阴影技术总结

光栅化算法由于缺少全局信息,每个fragment不清楚全局光照的情况,因此实时阴影大部分是基于Shadow Map实现的。

需要预渲染储存深度信息,从光源渲染场景中每个点的深度值储存在深度纹理中,再从Camera视角出发开始渲染场景,与深度纹理一一比对以判断当前渲染fragment是否在阴影中。

简单的ShadowMap仅仅是硬阴影,实现软阴影就需要进一步对阴影边缘进行处理,按照最后的处理效果分类的话可以分为:

  • 一致性:PCF、CSM、VSM、ESM
  • 距离相关(半影):PCSS

按处理方式可分为,

  • 过滤(filtering)阴影贴图:PCF、PCSS
  • 预过滤(pre-filtering)阴影贴图:VSM、ESM
  • 屏幕空间模糊

我们已知基础ShadowMap的算法表达式:

f(z)=H(z-d)

H(x)=0(x\geq 0),1(x< 0)  

其中,z为渲染时物体在光源空间下的深度,d为物体在Shadowmap采样获得的深度(遮挡物位置深度)。

1.1 PCF

Percentage-Closer Filtering,即百分比渐进过滤,这是一种很朴素的思想。不是要实现阴影边缘模糊吗?好,直接buff拉最大——直接对多重采样,即对f(z)进行滤波处理,阴影的质量通过控制采样数量(sample num)和采样步长(stride)决定。

缺点就很明显了,

  • 硬上多重采样,算法效率低,场景复杂度和滤波核大小十分影响性能(当然如果是PC端的话用PCF就绰绰有余了,对性能不会有太大的限制)
  • 不支持预滤波处理——不能mipmap

但是,性能上的不足目前硬件越来越厉害了,其实是慢慢在优化的,其次PCF与之后提到的CSM、VSM那些相比不需要其他的纹理格式,至今还是最通用的软阴影解决方案。 

1.2 CSM

Convolution Shadow Mapping,即卷积阴影,注意此CSM非彼CSM(Cascaded SM)。

基础Shadowmap记录的深度值要么是0要么是1对吧?0到1的突变就是造成阴影“硬”的原因,实现软阴影本质上就是让0到1突变别那么明显。CSM就是对f(z)的公式做了个fft(快速傅里叶变换),重构了shadowmap(截图自实时渲染中的软阴影技术):

注意:截图中f(d,z)dz跟本文前面提到的H(z-d)中的dz意义是反过来的。

 M要选择大于4的数,且M越大整个曲线将越接近原始样子,效果越好。

CSM与PCF相比优点在于,

  • 由于只是对Shadowmap进行预处理,因此场景复杂度并不影响性能
  • 支持预滤波,即可以在CSM之前对depth map做一个预blur

不足在于,M越大,阴影质量越高,但同时效率也越低。

1.3 VSM

Variance Shadow Map,即结合深度概率分布和切比雪夫不等式的方差阴影贴图,将阴影遮挡看作概率问题,使用单边切比雪夫不等式求得概率作为阴影值。

单边切比雪夫不等式

参考切比雪夫不等式到底是个什么概念?问题中各路大神的回答,简单总结一下:

切比雪夫不等式是刻画事物偏离它本质的偏离程度的大小的概率,将随机变量的期望和方差联系在了一起,不需要知道变量的整个分布,只需要知道标准差就可以估计出结果,其基本形式为,

P(\left |X-E(X) \right |\geq \varepsilon )\leq \frac{D(X)}{\varepsilon ^{2}}

式中,方差

D(X)=\int_{-\infty }^{+\infty }(X-E(X))^{2}dF(X)

E(X)是X的期望,F(X)是X的分布函数。

(单边的切比雪夫不等式) 描述了大于某一常数\varepsilon的概率P

P(X-E(X) \geq \varepsilon )\leq \frac{D(X)}{\varepsilon ^{2}+D(X)}

VSM计算思路

  • Shadowmap中2个通道分别储存dd^{2}:跟ShadowMap思路相同,需要先从光源处做一次光栅化,但不同的是不仅需要储存深度d还要储存深度平方d^{2}
  • 对Shadowmap进行滤波:对dd^{^{2}}通道进行模糊处理(参考文章用的是box filter),获得期望深度和深度平方
  • 采样当前着色点p在Shadowmap中对应的期望深度E(d)和深度平方E(d^{2}),并计算方差, 

D(d)=E(d^{2})-E(d)

  •  求出光源空间下p的深度z:比较zE(d),如果z更小,那么无遮挡,直接返回1,如果z更大,进行下一步
  • 对应P(X-E(X) \geq \varepsilon )\leq \frac{D(X)}{\varepsilon ^{2}+D(X)}式中就是求出深度z偏移期望深度E(d)的概率,令\varepsilon =z-E(d),则

P(X \geq z)\leq \frac{D(X)}{(z-E(d)) ^{2}+D(X)}

优点:效率高

与PCF相比,但效率更高(通过方差避免暴力采样

与CSM相比,VSM开销更小

问题:漏光、内存大

关于这个漏光问题,参考影子传说——三种Shadowmap改进算法的原理与在Unity中的实现,解决方案是重映射,然而映射越厉害,阴影就越硬,相反漏光减少。

由于VSM需要真用更多的内存——需要MRT额外储存d^{2},需要两个float通道储存数据,移动端应该吃不消

补充:

1.4 ESM

Exponental Shadow Mapping,即用指数函数替换掉原表达式中简单的相减,实现方法如下(截图自参考):

与CSM相比ESM表达式更加简洁,效率也更高,如下图(截图自参考),该作者验证了32位float下ESM的c取80效果最佳,且生成阴影比M=16的CSM生成的阴影更好:

pre-filtering

基础的ESM仅仅解决了软硬问题,,而边缘锯齿依然存在!因此肯定要额外进行滤波的,那么到底是pre-filtering还是filtering?该参考文章的作者又进行如下证明:

对于使用指数表达式的ESM来说,ESM处理后再对结果进行filtering和pre-filtering完全是等价的,而pre-filtering(MSAA、高斯模糊效果都不错)当然比filtering要好得多!

优点

支持pre-filtering,与VSM相比ESM只需要一个float通道,无需MRT。

问题

ESM的不足在于,虽然锯齿问题完全可以pre-filtering解决,但软阴影质量极大受到c值影响:c值小了会漏光,c值太大“软”得不明显。PC端完全可以直接PCF,而移动端32位float精度又不够,具体可以看看这篇文章有带图片分析。

1.5 EVSM*

Exponential Variance Shadow Mapping,EVSM是对VSM的一种改进,具体可以看影子传说——三种Shadowmap改进算法的原理与在Unity中的实现

1.6 动态阴影:PCSS 

Percentage-Closer Soft Shadow,即百分比接近软阴影。这个与上面几种方法解决的问题不一样,这个解决的是阴影的一致性问题,即实现动态阴影

具体实现方法可以参考之前我的202作业记录:

GAMES202作业1-实现过程详细步骤,放上一张最后的效果:

2 实时阴影:光线追踪

2.1 ShadowMap的不足

我发现很多人在比较ShadowMap和光追阴影的时候总喜欢拿软阴影来说事,虽然传统的ShadowMap无法实现软阴影,但PCF、PCSS可以呀!感觉硬伤其实是在精度问题:无论用何种算法,只要是基于ShadowMap思想的一定逃不过需要图来储存深度信息(VSM甚至需要两张),而图,就一定会涉及到分辨率问题——低了看不清,高了性能上不去;还有抗锯齿问题。

随着场景越来越大,ShadowMap这种问题一定会越来越明显。

2.2 考虑遮挡

光线追踪算法的单一代码路径可以处理所有的阴影场景,只需在视线发出光线与场景中物体求交时,做一个距离上的对比,挡住则不计算光强,拿101光追框架看,光追代码中如何考虑遮挡:

实时光线追踪技术:业界发展近况与未来挑战文中的3.4就介绍了Ray Tracing Shadow。

关于rtShadow就先谈到这里,后面有机会会继续补充。

参考

 实时渲染中的软阴影技术 - 知乎 (zhihu.com)

 影子传说——三种Shadowmap改进算法的原理与在Unity中的实现 - 知乎 (zhihu.com)

【论文复现】Variance Shadow Maps - 知乎 (zhihu.com)

单边切比雪夫不等式的总结 - 知乎 (zhihu.com)

实时光线追踪技术:业界发展近况与未来挑战 - 知乎 (zhihu.com)

RayTracingShadow/ScreenSpaceDenoiser 实现概述 - 知乎 (zhihu.com)

猜你喜欢

转载自blog.csdn.net/qq_41835314/article/details/128890565