Shadow Volume (阴影体)

值得注意的几点:

1. Depth pass与depth fail最本质的区别在于前者计算的是眼睛到物体之间经过了多少shadow volume,即shadow volume的计数(shadow volume count);而后者是计算了从眼睛到物体的射线,以物体为起点,然后方向与 眼睛->物体 一致,出了所有shadow volume的计数。

2. Depth pass和depth fail本质上指的就是上述的两条相应的射线,然后根据各自的规则,为与射线相交的front face和back face +1或 -1(eg. depth pass为与其相交的front face +1,为与其相交的back face -1)。

3. 每个occluder形成一个shadow volume。

 

depth pass和depth fail都是根据图来进行直观的了解最简单。从眼睛到物体画条直线,depth pass为front face +1,back face -1;depth fail为back face +1,front face -1。

 

以下转自:http://blog.csdn.net/kongbu0622/article/details/1838317

Shadow volume 的原理:

Shadow volume 这种算法第一次被提出是在Franklin C. Crow 在 1977 年写的一篇论文 “SHADOW ALGORITHMS FOR COMPUTERGRAPHICS ”里。其基本原理是根据光源和遮蔽物的位置关系计算出场景中会产生阴影的区域( shadow volume),然后对所有物体进行检测,以确定其会不会受阴影的影响。


图中的绿色物体就是所谓的遮蔽物,而灰色的区域就是 shadow volume。


只有处于 shadow volume 里面的物体才会受阴影的影响。

shadow volume的算法

现在清楚了 shadow volume 的基本原理,那么如何确定一个物体或者一个物体的某一部分处于 shadow volume 中呢?这就要用到 stencil buffer 的帮助了。

z-pass 算法:

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

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

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

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

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


在这副图里面,视线三进三出 shadow volume, 最后的 stencil 值为零,表示物体在 shadow volume 外,不受阴影的影响。


这副图里面视线三进一出, stencil 值为 2 ,表示物体在 shadow volume 内,有阴影产生。


这副图里面从视点到物体的视线中止于 shadow volume 前,也就是说所有的 z-test 都是 fail, 相应的 stencil 值为零,表示物体在阴影外面。

 

z-pass 算法缺点及补救办法

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

 

这副图里面的视线二进二出,按照 z-pass的算法,最后的 stencil 值为 0,表示物体在阴影外,可实际上物体是处于阴影内的。错误的原因就在于视点进入到阴影内,使得视线失去了一次进入 shadow volume的机会,让原本应该是 1 的 stencil 值变成了 0 。

Z-Pass 这种错误的行为可以从下图中看出 :


注意地下的影子

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, eNABlez-test/stencil-write 。渲染 shadow volume, 对于它的 back face ,如果 z-test 的结果是fail, stencil 值加一,如果 z-test 的结果是 pass, stencil 值不变。对于 front face, 如果z-test 的结果是 fail, stencil 值减 一 ,如果结果是 pass, stencil 值不变。


图中所有的 shadow volume 都处在 z-pass 的位置,因此 stencil 值不会改变。


视点在 shadow volume 内也没有问题,最后 stencil 的值是 2, 表示物体在阴影内。

posted @ 2013-03-19 12:43  qingsun_ny  阅读(1409)  评论(0)    收藏  举报