关于ShadowMap中Shadow acne现象的解释

关于ShadowMap中Shadow acne现象的解释

什么是Shadow acne

先看一张图:

这张图是我在GAMES202的作业1中,将光源高度调低,从而使得光线入射方向和地面之间夹角比较小,并且不做任何bias处理,从而得到比较明显的shadow acne现象。即左边地面上奇怪的花纹。而我们把acne放大看(camera拉近了),是间隔的条纹:


产生Shadow ance的原因

原因其实很简单,简单说,shadow map对于光源空间的深度的采样是离散的,shadow map上每个texel只能记录一个深度值。而计算阴影的平面,比如地面本身是连续的。在传统shadow map的第二个pass中,将任意片段所对应的深度值变换到光源空间后和shadow map中存储的深度值比较时,就会发现同一个片段,有可能计算出来的深度值大于shadow map对应的texel中存储的深度值,也就是发生了自我遮挡,从而被判断为在阴影中。

看图更能说明问题:

上图中左边的shadow map中每个texel记录了一个深度值,对应了下面Plane上的一个区域,由于shadow map的精度肯定是有限的,其记录的深度值必然是离散化的,而Plane本身是连续的,这就造成平面上一段连续的不同的深度,记录在Shadow map上是一个相同的深度值。图中紫色的锯齿状折现,演示了shadow map上深度值的变化。而shadow map算法第2个pass,计算片段在光源空间的深度值时,此时计算得到的是一个浮点数的比较精确的深度值,例如在图中,我用红色粗线标出的区域,这个区域中每个片段到光源的深度值都是不同的,但是由于这个区域对应的shadow map上的texel记录的深度比这个区域计算出来的深度要小,所以这个区域的片段都被遮挡了,产生了阴影。由于其实是被自己在shadow map中记录的深度值所遮挡,也叫self occlusion。那么为啥shadow ance是相隔的条纹呢?因为同一个离散化深度值对应的区域,有一半的真实深度值是小于这个离散深度值的,因此不会被遮挡。例如红粗线这个区域左边的一个区域。

解决方法:使用bias

针对上面分析出的产生shadow acne的原因,很容易想到一个解决方案。即在和shadow map中离散化的深度比较时,将这个深度加大一点点,这样只有当shadow map中的深度显著大于计算出来的深度时,才判断为产生阴影。例如下图:

让texel所存储的深度值再远离光源一点点,从而在比较的时候,不那么容易产生自遮挡。

下图为添加了0.01的bias后的效果,已经几乎看不到acne了:

Bias过大的问题:分离的阴影(Peter Panning)

还是上面的例子,将bias设置为0.02后得到:

很明显,阴影和脚分离了。这说明有一部分本该在阴影中的片段,被判断为不在阴影中。显然这是因为我们设定的offset值bias太大了。所以设定bias的大小很重要。

根据斜率设置bias

其实shadow acne现象是否明显,和光线与片段的夹角有关,当夹角小到接近平行时,最为明显。而当光线完全垂直于地面时,就不会产生了,因为此时所有的片段的深度几乎一样了。基于这个观察,有人提出了根据斜率来设置bias,当斜率小时(极限情况是平行),bias大一些;当斜率大时(极限是垂直),bias小一些。这样就比较科学一些。

发布于 2021-04-21 10:47