在Per-Fragment Operations & Tests阶段,有一个步骤是模版测试(Stencil Test)。依靠这一步骤,不仅可以实现渲染模型的包围框这样的实用功能,还能创造出一种渲染阴影的算法,即Shadow Volume算法。
用Shadow Mapping方法得到的阴影,在贴近观察时,会看到细微的锯齿。这是因为深度缓存受到分辨率的限制,不可能完全精确地描述贴近观察时的各个Fragment。但Shadow Volume方法得到的阴影是没有这样的锯齿问题的,如下图所示:
对比(左)Shadow Mapping的阴影有锯齿(右)Shadow Volume的阴影更平滑
如图所示,左侧的Shadow Mapping方法得到的阴影在犄角、舌头和下巴部分可以看到比较明显的锯齿,而右侧的Shadow Volume方法得到的阴影则十分平滑。这是由Shadow Volume的实现机制决定的。其机制概括起来就是,根据光源位置(或方向)和模型位置,动态地生成一个不规则的包围盒,将阴影部分包裹起来,保证包围盒内部的Fragment不参与光照计算。上图的包围盒如下图所示:
从6个视角观察包围盒
注意,这个包围盒是实时动态生成的,它会随着光源位置(或方向)的变化而变化。而且,这个包围盒是延伸到无限远的。这样才能正确地渲染出阴影。
那么有2个主要问题:首先,如何动态生成这个包围盒,而且能够覆盖无限远的范围;然后如何根据包围盒判断Fragment是否参与光照计算。
为便于理解问题,这里假设探讨的模型都是由三角形网格拼接组成的。例如对于中国龙模型和Cube模型,其三角形网格结构如下图所示:
三角形网格组成的模型
可以看到,中国龙模型是由非常多的三角形网格拼接而成的,这利于观察光照效果的真实感。Cube模型则仅仅由12个三角形拼接而成,这利于检测程序的正确性。请读者在随书代码中找到任意一个可以渲染中国龙模型的项目,为其添加PolygonModeSwitch开关,近距离观察中国龙模型的三角形网格。
要找到一个模型在光源照射下的包围盒,首先要找到在光源照射下的外围轮廓(Outline)。轮廓的一侧都是能被光源照射到的三角形,另一侧都是不能被光源照射到的三角形(即处于阴影中),例如下图所示: