现在比较普遍的实现方法有三种:Z Pass、Z Fail 和DirectX Samples 里面介绍的那种(其实Z Fail只是Z Pass的改进版)。这里只介绍Z Pass的实现方法。如下图所示,有一个三角形abc和它投到地面的影子三角形def。从摄像机分别看A、B、C三处,明显只有B是处在三角形的阴影中。
那么如何通过程序来判断一个点是否在阴影中呢?在多面体abcdef中,从视点看A点时,视线没有经过多面体;从视点看B点时,视线经过多面体正对视点的一个面abde;从视点看C点,视线首先经过多面体正对视点的面abde,然后经过背对视点的面bcef,然后才到达C点。由此可得,当视线只经过阴影多面体正对面而没经过多面体背对面时,所看到的点就在阴影中。当场景中有多个阴影体时,我们可以认为当视点经过阴影多面体正对面次数大于经过背对面次数时,看到的点就在阴影中。
5) 打开光照,根据所得的模版缓存stencil_1,再次渲染场景。如果stencil_1的值跟这一次渲染场景的模版值相等,则渲染场景;否则,保留表面原色(阴影)。
这样,阴影就渲染出来了。第二步到第五步都涉及到深度测试和模版测试的问题,如果对这两种测试不太熟悉的话,实现起来是一件很头痛的事情。下面附上一段代码,用以说明从第二步到第五步的深度测试和模版测试。
然而,Z Pass 并不是一个完美的解决方案。比如,当摄像机处在一个阴影里面的时候,我们就无法用Z Pass来实现了。Z Fail的出现就是为了弥补Z Pass的不足。