Shadow Acne问题

ShadowMap是实时渲染中实现阴影效果一种常用的方法,它的基本思路是创建一个光源视角下的深度图;然后在渲染时,将渲染frag的深度和深度图对应的深度进行比较,若frag的深度比深度图的深度值大,则说明它是在阴影下的(有一个物体在它前面遮挡了光线),否则不需要渲染阴影。
但是在实际的实现中,会有一个问题,如下图所示:
Shadow Acne问题_第1张图片
仔细看上图的地板和方体,可以看到条纹装的阴影,拉近镜头的话如下所示:
Shadow Acne问题_第2张图片
该现象被称作Shadow Acne。其实原因也是不难理解。因为我们创建的深度图终究是离散的数值,对深度图采样只能得到该像素下某一个点的深度值,但实际上同一个像素不同位置的深度值也是有很大差别的,如下图所示:
Shadow Acne问题_第3张图片
图中黄色的一个像素,在渲染时只能将中间的深度值作为该像素的深度值。但在实际渲染场景的时候,像素其他位置的深度值可能会高于或低于深度图存储的值,就会出现这种一部分在阴影中,一部分没有阴影的效果。
那么该如何解决这类问题呢?最简单的做法是为深度图中读取出的深度图加上一个bias,保证该像素内所包含的frag的深度均位于其下,这样就将该问题解决了。
我们还可以设置bias的值根据光线和物体本身的normal动态变化:

float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);

但是利用该方法也有一个缺点,那就是利用bias有可能会导致阴影的偏移,如下图所示:
Shadow Acne问题_第4张图片
尤其是在bias的值选的过大时,该现象更加明显。
其实,想彻底解决该问题只需要一个小小的改动就可以:在渲染深度图时只渲染背面。这样一来,假设该物体实际上被某物体遮挡,那么它的深度值必然高于遮挡物体背面的深度值。反之,假设该物体没有被遮挡,那么它的深度值必然小于它背面的深度值:
Shadow Acne问题_第5张图片
这种方法被称作Peter panning。
当然,该方法也是有自己的问题的:就是它只能处理闭合的模型(比如长方体),对于只有一个面的模型(比如长方形)就无法渲染它的背面了。这就要求在制作模型的时候就要制作闭合的模型。
当然,实际上大部分还是用的bias值来处理该问题。只要比较小心得设置它的值,就可以得到皆大欢喜的结果。

你可能感兴趣的:(Shadow Acne问题)