阴影体
阴影体(阴影锥)是三维计算机图形中所使用的一种技术,始于1977年,用于在绘制的场景中加入阴影。它通常被认为是现代三维图形硬件的能力下的最实用的通用实时阴影系统之一,并已随着毁灭战士3而流行开来。
阴影体将虚拟世界分成两部分;在某光源的阴影中的部分和不在阴影中的部分。
构造
要构造一个阴影体,先从光源投射一条射线穿过产生阴影的物体中的每个顶点到某个点(通常在无穷远点)。这些射线一起组成一个体;每个该体中的点都在阴影中,所有在外部的物体被该光源照亮。
实际的阴影体如下计算:
- 找到所有的轮廓边(将前向面和后向面隔开的边)
- 将所有的轮廓边向远离光源的方向伸展形成一个四边形。
- 加入前盖和后盖到这些表面上形成一个闭合体(不是必要的,是否采用取决于所采用的实现方法)
用法
当前的研究和实现方法侧重于使用硬件的模版缓存(stencil buffer)来优化算法以利用硬件加速 - 参看模版阴影体。
为测试绘制的图像的给定像素是否在阴影中,阴影体本身需要被绘制,但它是绘制到模板缓存,而不是最终的图像中。对于每个阴影体中的前向面,模板缓存中的值是增加的;对于后向面,它是减少的。
一旦所有阴影体中的面被绘制到模版缓存,任何值非零的像素将处于阴影中。
要理解其原因,考虑从像素到屏幕的光线反向回到物体的射线 - 若它穿入阴影体,它将会穿过一个前向面,所以模版缓存对应像素的值会增加。若它又穿出阴影体(通过一个后向面)该值将会再次减少。
但是如果该像素在阴影中则该值只在它从后面离开阴影体时被减少,所以该值非零。
图1显示了一个包含一个镜头,一个光源,一个阴影产生物体(蓝色圆圈)和三个阴影接受物体(绿色的方块),全部用二维示意。粗黑线表示阴影体的轮廓。从相机(笑脸)投射的线表示视线。
该视线首先击中物体a;在该点它没有达到阴影体的任何面,所以帧缓存会有0值 - 不在阴影中。在点1阴影体的一个前向面被穿过因而增加了模版缓存中的值。然后我们击中物体b;在该点我们在缓存中有一个值为1,所以该物体在阴影中。沿着视线继续前进,我们会在点2到达阴影体的后向面,因而把模版缓存中的值减少到0。最后我们击中物体c,模版缓存中的值又是0,所以该物体也不在阴影中。
该算法的一个问题在于若相机(眼睛)本身在阴影体中则该方法會失败 - 视线首先穿过阴影体的后向面,将模版缓存中的值减少1,使得它在到达物体c的时候有非零值,虽然该物体不应该在阴影中。
这个问题的一个解决办法是从无穷远的某点返回到相机。该技术由一些人独立发现,但是由John Carmack推广,并经常被称为Carmack的翻转。
参看
- 模版阴影体,描述了如何使用模版缓存实现阴影体算法
- 轮廓边
- 阴影映射,一个较简单的技术
外部链接
- https://web.archive.org/web/20100531060920/http://www.gamedev.net/reference/articles/article1873.asp - 一篇优秀的介绍文章
- http://www.gamedev.net/reference/articles/article2036.asp%5B%5D - 基本算法的另一解释
- https://web.archive.org/web/20090904173353/http://developer.nvidia.com/object/fast_shadow_volumes.html
- https://web.archive.org/web/20031004133623/http://developer.nvidia.com/object/robust_shadow_volumes.html
- http://www.sgi.com/software/opengl/advanced96/node48.html 页面存档备份,存于