阴影(Shadows)
在开始下一部分之前,先回头解决光栅化中的一个问题,那就是如何在光栅化渲染过程中绘制阴影。之前在纹理映射部分讲到了环境光遮蔽的基本原理,就是利用了贴图提前计算环境光遮蔽,那么绘制阴影同样如此,这一节就来简单介绍阴影贴图或者叫阴影映射(Shadow mapping)。
阴影映射是一个在图像空间执行的算法,因此在计算阴影的时候无需知道场景的几何关系,计算成本低,但会产生走样现象,并且阴影映射只适用于点光源。
简单来说,阴影映射的核心思想就是:不在阴影中的点一定是既能被相机看到也能被光源看到的点。按照这个核心思想我们来看阴影映射的步骤。
阴影映射过程
首先我们在光源处放一个虚拟相机,去看向整个场景,然后我们记录这个虚拟相机看到的整个场景的深度形成一张深度图,比如下面的图,没有被遮挡的物体的深度自然就是物体到光源的距离,而存在遮挡关系的物体肯定只能记录离光源最近的物体的距离。
然后我们再用真正的相机看向整个场景,此时看到的每一个点我们都计算它到光源的距离,然后把这个点映射到用光源生成的深度图上,找到光源看到的这个点的深度,如果计算出来的深度和光源看到的深度是一致的,那就说明这个点没有被遮挡,也就是既能被相机看到也能被光源看到,那么这个点就不处在阴影中:
而如果计算出来的深度和光源看到的深度不一致,那显然这个点被遮挡了,相机能看到但光源看不到,这也就是阴影,于是我们把这个点涂上阴影的颜色,这样就完成了阴影映射,得到了场景中在点光源下物体的阴影:
我们用一个例子来看这个过程,下图是一个场景,左上角有一个点光源:
首先从光源的视角看向整个场景:
得到一张深度图:
然后再从相机的视角去计算哪些是阴影:
最后就得到了场景阴影:
阴影映射的缺陷
阴影映射可以得到场景的阴影关系,但存在很多问题。
阴影映射的质量取决于阴影贴图的分辨率,分辨率越高自然阴影质量越好
由于深度都是浮点数,计算机中是无法判断两个浮点数完全相等的,因此会存在一定的误差,这也会影响阴影的效果
阴影映射只能得到“硬阴影”,因为我们的阴影映射是逐像素进行的,因此对于每一个像素只有被遮挡和没被遮挡两种情况,因此我们得到的阴影边界非常清晰,如下图:
但实际我们看到的阴影是存在半影(Penumbra)现象的,半影就是指能看到部分光源的地方,比如日全食的时候,我们在全影(Umbra)区完全看不到太阳,就产生了日全食,而在半影区我们可以看到一部分太阳,如下图:
半影表现在阴影上就像下面的效果:
这样的阴影边界不那么清晰,是“软阴影”,显得更加真实。
对于这样的软阴影该如何渲染,我们从下一节开始讨论光线追踪后,就会了解。