当前位置:嗨网首页>书籍在线阅读

05-阴影贴图

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

8.4 阴影贴图

阴影贴图是用于投射阴影最实用也最流行的方法之一。虽然它并不总是像阴影体一样准确(且通常伴随着讨厌的伪影),但阴影贴图实现起来更简单,可以在各种情况下使用,并享有强大的硬件支持。

如果我们不在这里澄清前一段中的“更简单”这个词,那将是我们的疏忽。虽然阴影贴图比阴影体(在概念和实践中)更简单,但它绝不“简单”!对学生来说,通常在3D图形课程中最难实现的技术之一就是阴影贴图。着色器程序本质上很难调试,阴影贴图需要几个组件和着色器模块的完美协调。请注意,通过使用前面2.2节中描述的调试工具,可以极大地促进阴影贴图的成功实现。

阴影贴图基于一个非常简明的想法:光线无法看到的任何东西都在阴影中。也就是说,如果对象#1阻挡光到达对象#2,等同于光不能“看到”对象#2。

这个想法的强大之处在于我们已经有了方法来确定物体是否可以被“看到”——使用Z缓冲区的隐藏面消除算法(HSR),如2.1.7节所述。因此,计算阴影的策略是,暂时将摄像机移动到光的位置,应用Z缓冲区HSR算法,然后使用生成的深度信息来计算阴影。

因此,渲染场景需要两轮:第1轮从灯光的角度渲染场景(但实际上没有将其绘制到屏幕上),第2轮从摄像机的角度渲染场景。第1轮的目的是从光的角度生成Z缓冲区。完成第1轮之后,我们需要保留Z缓冲区并使用它来帮助我们在第2轮生成阴影。第2轮实际绘制场景。

我们的策略可以更加精炼。

  • (第1轮)从灯光的位置渲染场景。然后,对于每个像素,深度缓冲区包含光与最近的对象之间的距离。
  • 将深度缓冲区复制到单独的“阴影缓冲区”。
  • (第2轮)正常渲染场景。对于每个像素,在阴影缓冲区中查找相应的位置。如果相机到渲染点的距离大于从阴影缓冲区检索到的值,则在该像素处绘制的对象离光线的距离,比离光线最近的对象更远,因此该像素处于阴影中。

当发现像素处于阴影中时,我们需要使其更暗。一种简单而有效的方法是仅渲染其环境光,忽略其漫反射和镜面反射分量。

上述方法通常被称为“阴影缓冲区”。而当我们在第二步中,将深度缓冲区复制到纹理中,则称为“阴影贴图”。当纹理对象用于储存阴影深度信息时,我们称其为阴影纹理,OpenGL通过sampler2DShadow类型支持阴影纹理(稍后讨论)。这样,我们就可以利用片段着色器中纹理单元和采样器变量(即“纹理贴图”)的硬件支持功能,在第2轮快速执行深度查找。我们现在修改的策略是:

  • (第1轮)与之前相同;
  • 将深度缓冲区的内容复制进纹理对象;
  • (第2轮)与之前相同,不过阴影缓冲区变为阴影纹理。

现在我们来实现这些步骤。