《Approximate Soft Shadows on Arbitrary Surfaces using Penumbra Wedges》
Tomas Akenine-Moller and Ulf Assarsson
Eurographics Workshop on Rendering(2002)
这是一个基于标准shadow volume和Haines的《Soft Planar Shadows using Plateaus》改进的算法。算法核心在于在多边形silhouette边的基础上建立一种新的图元-penumbra wedge,根据阴影接受表面上的点在在penumbra wedges中的位置进行插值,得到改点的阴影级别。
下面对该算法进行更详细的介绍。假设:光源为球形光源,LI=light intensity光照强度在公式中用s表示。
penumbra wedges如下图所示。
从图中可以看出来,PW方法并不是在本影外边模拟出柔和的过渡,因此相对于Haines的方法在物理上更加真实。
在PW中的LI-s在[0,1]之间计算,表示阴影级别,s=0表示不在阴影范围内,s=1表示位于本影内。
算法使用一个16bits的buffer作为LI-buffer,就如同是一个更高精度的stencil buffer,可以通过绘制一个HILO的纹理来实现。
一般硬件都具有8-bit的颜色缓存,因此我们使用一个k=255来乘以LI值,然后用color buffer中的值减去255s就得到了改点的颜色值。算法的步骤如下:
1,LI-buffer预置255
2,用spacular+diffuse绘制场景,得到color buffer值
3,绘制所有PW,将PW绘制到LI-buffer中
4,将LI-buffer中的值调制到[0,255]之间并合并到color buffer(我理解是cb-lb)
5,绘制ambient光
其中第3步的伪代码和对应的图如下:
1 : rasterizeWedge(){
2 : for each visible fragment(x,y) on front facing triangles of wedge
3 : pf = computeEntryPointOnWedge(x; y);
4 : pb = computeExitPointOnWedge(x; y);
5 : p = point(x; y; z); //z is the Z-buffer value at (x; y)
6 : pi = choosePointClosestToEye(p;pb);
7 : sf = computeLightIntensity(pf );
8 : si = computeLightIntensity(pi);
9 : addToLIBuffer(round(255(si-sf)));
10 : end;}
其中第4步调制的目的是为了把因为位于不同PW中而值大于255的值归整到0到255之间,以便能够正确的体现阴影柔和程度。
构造原理如下图所示:
每个PW分成前后左右四个面,其中前后面的构造分别是:b=c+rn 和 f=c-rn ,r是光源球半径,n是shadow volume的法线。左右面的构造如下图所示,是由相邻PW的两个前面交点和两个后面交点以及sil的交点构成。
文章中对于r=0可以直接绘制硬阴影以及邻sil边是锐角的情况也给以讨论。
- 光照强度插值(Light Intensity Interpolation)
插值的关键是在相邻的PW之间插值要连续,这样在穿过两个不同的PW的时候才会保持阴影的光滑。其计算如下图所示:
文章后边详细介绍了优化算法和实现结果,以及与其他算法的比较,这里就不说了。
我对此算法的认识是:
- 相对于以前的算法可以较好的生成软阴影,同时基于shadow volume,可以有效的避免前边算法出现的问题。
- 存在着较多的局限性。比如球面光源,比如SV能够处理的非多边形体和半透明物体的阴影,比如顶点具有两个以上sil边的情况,等等。
- 虽然作者宣称可以在明年的显卡上获得实时的性能,但是没有硬件的加速完全无法达到很好的性能,这可能就是其没有上siggraph的原因吧。
- 很多的问题对于我来说,既是机遇也是挑战。
- 具体怎么实现,还得跟WJ大牛学习学习。