首页 > 代码库 > ShadowMap & ShadowVolume

ShadowMap & ShadowVolume

ShadowMap

  一个物体之所以会处在阴影当中,是由于在它和光源之间存在着遮蔽物,或者说遮蔽物离光源的距离比物体要近,这就是 shadow mapping 算法的基本原理。

  Pass1: 以光源为视点,或者说在光源坐标系下面对整个场景进行渲染,目的是要得到一副所有物体相对于光源的 depth map (也就是我们所说的shadow map),也就是这副图像中每个象素的值代表着场景里面离光源最近的 fragment 的深度值。由于这个pass中我们感兴趣的只是象素的深度值,所以可以把所有的光照计算关掉,打开 z-test 和 z-write 的 render state 。

  Pass2: 将视点恢复到原来的正常位置,渲染整个场景,对每个象素计算它和光源的距离,然后将这个值和 depth map中相应的值比较,以确定这个象素点是否处在阴影当中。然后根据比较的结果,对 shadowed fragment 和 lighted fragment 分别进行不同的光照计算,这样就可以得到阴影的效果了。 

  从上面的分析可以看出来,depth map的渲染只和光源的位置以及场景中物体的位置有关,无论视点怎么运动,只要光源和物体的相互位置关系不变,shadow map就可以被重复使用,因此对于没有动态光源的场景,shadow mapping 是很明智的一种选择。

ShadowVolume

1、z-pass 算法。

  z-pass 是 shadow volume 一开始的标准算法,用来确定某一个象素是否处于阴影当中。其原理是:

  Pass1:enable z-buffer write ,渲染整个场景,得到关于所有物体的 depth map 。注意这里的 depth map 和 shadowmapping 里面的区别是 shadow volume 里面的 depth map 是以真实视点作为视点得到的,而 shadowmapping 里面的 depth map 是以光源为视点得到的。

  Pass2:disable z-buffer write ,enable stencil buffer write,然后渲染所有的 shadow volume 。对于 shadow volume 的 front face( 既面对视点的这一面 ) ,如果 depth test 的结果是 pass,那么和这个象素对应的 stencil 值加1,否则stencil 值不变。而对于 shadow volume 的 back face(远离视点的一侧 ) ,如果 depth test 的结果是 pass,stencil 值减1,否则保持不变。

  用一句简单的话来概括 z-pass的算法就是从视点向物体引一条视线,当这条射线进入 shadow volume 的时候, stencil 值加1,而当这条射线离开 shadowvolume 的时候,stencil 值减1。如果 stencil 值为零,则表示实现进入和离开 shadow volume的次数相等,自然就表示物体不在 shadow volume 内了。

  

  Pass3:第二步完成以后,根据每个象素的 stencil 值判断其是否处于阴影当中(如果 stencil 的值大于零,则这个象素在 shadow volume 内,否则在 shadow volume 的外面),然后据此绘制阴影效果。

2、Z-Pass的问题。

  以上的讨论都是基于视点在 shadow volume 外面的情况。在这个条件可以得到满足的情况下,z-pass 算法工作的很好,不过一旦视点进入到了 shadow volume 里面,z-pass 算法就会立即失效。   

  

3、Z-Fail算法。

  Z-Fail 算法是 John Carmack,Bill Bilodeau 和 Mike Songy 各自独立发明的,其目的就是解决视点进入 shadow volume 后 z-pass 算法失效的问题。

  Pass1:enable z-write/z-test, 渲染整个场景,得到 depth map 。 ( 这一步和 z-pass 的完全一样 )

  Pass2:disable z-write, enable z-test/stencil-write 。渲染 shadow volume, 对于它的 back face ,如果 z-test 的结果是fail, stencil 值加1,如果 z-test 的结果是 pass,stencil 值不变。对于 front face,如果z-test 的结果是 fail,stencil 值减1 ,如果结果是 pass,stencil 值不变。

  

  Z-Fail算法其目的就是解决视点进入 shadow volume 后 z-pass 算法失效的问题。

参考:http://blog.163.com/wmk_2000_ren/blog/static/138846192201019114117466/