« Terrain Texture-Array DemoShadow Map阴影贴图技术之探Ⅳ »

Shadow Map阴影贴图技术之探Ⅲ

这里是ZwqXin关于Shadow Map阴影贴图的OpenGL实现记录的第三辑。在启动新动作之前,总结一下这些天关于Shadow Map的一些琐事,问题的存在。——ZwqXin.com  前文见:
Shadow Map阴影贴图技术之探Ⅰ
Shadow Map阴影贴图技术之探Ⅱ

本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
      原文地址:http://www.zwqxin.cn/archives/opengl/shadow-map-3.html

1.图谈光线与视线的那些破事儿

从Nvidia的CSM paper里要来的一张图。因为我觉得这个问题还是图片说话比较好:你看图中,蓝色线内的是光源“眼中”的场景(far和near在这里无关要紧),黑色那个是视锥,蓝色物体被投影到某树上,我们看得到该影子(树在视锥内)。这当然是理想情况。仔细看看这种理想情况是怎么做出来的?灯光足够远,整个视锥在“光的视野”内。如果蓝色框框向上移动一下看怎么样?如果黑色框框向下移呢?我们能够观察到阴影的部分,永远只有光视野与相机视野的交集。

2.反锯齿的动作

既然如此,那么把光有那么远移那么远好么,最好是无限远产生平行光好么?不好。原因之前说过了,就像你人一样,你越远,看的东西越模糊,乃至形状都分不清了——光也一样,这样的影子实在糟糕。怎样取得光源距离在各方面的平衡呢?我觉得应该恰到好处地具体问题具体分析。有时候你得模拟一个照射大地的太阳,你能让它怎么近呢?(下面讲到的CSM技术是解决此类问题的。)但是一些小场景你就得合理控制了——又通常光源位置都不是说变就变的(譬如房间内的蜡烛),这时候可通过近远裁减面等等适当调节光的“视野”。对光源过远而产生的锯齿,衍生出级种着力于解决这类问题的技术(后述)。另外还有传统的反锯齿技术,譬如4X,16X这些。譬如这里我尝试按OpenGL Shading Language(橙书)13.2做的:

  1. float lookup(float x, float y)
  2. {
  3.    float factor = 1.0;
  4.   
  5.    shadowTexcoord = shadowTexcoord  + vec4(x,y,0.0,0.0) * epsilon;   
  6.    float depth = shadow2DProj(shadowmap, shadowTexcoord).r;
  7.    
  8.    depth = clamp(depth, 0.0, 1.0);
  9.         if(depth != 1.0)factor = 0.5;
  10.    return factor;
  11. }
  12.  
  13. void main()
  14. {
  15.        float mass = 0.0;
  16.        mass += lookup( 0.001,  0.001);
  17.        mass += lookup( 0.001, -0.001);
  18.        mass += lookup(-0.001,  0.001);
  19.        mass += lookup(-0.001, -0.001);
  20.  
  21.    if(shadowTexcoord.x >= 0.0 && shadowTexcoord.y >= 0.0 
  22.    && shadowTexcoord.x <= 1.0 && shadowTexcoord.y <= 1.0 )
  23.       {
  24.       gl_FragColor = vec4(gl_Color.rgb* diffuse.rgb * mass*0.25, 1.0);
  25.    }
  26.    else
  27.    {
  28.       gl_FragColor = vec4(gl_Color.rgb* diffuse.rgb, 1.0);
  29.    }

原理就是ping-pong模式的多次采样取均值——让阴影边界模糊。这当然比难看的锯齿好,但一般要搞高精度的效果才略显好。譬如我上面那样仅仅4次采样:

shadow map 3

可能是PICASA的压缩,本来也没这么丑的 - - 。但是你也知道这软阴影不象软阴影,跟人眼睛得了散光看东西一样。

3.穿过透明

我曾经在探Ⅰ讲shadow map好处的时候说过它比Volume有些地方的优势很明显。其中之一就是对待透明物时的问题。其实在Shadow Volume之探系列里我是想实现的,而且初期想以为很简单,谁知道即使拜托Google大神,也没看到有什么内容是关于这个的,可见Volume对这类型的遮光物是先天不足。而Shadow Map,本来以为“接下来努力实现让光线穿过透明物产生真实的阴影吧”,谁知道就那么几分钟就搞好了 - - 。说到底,Volume认真对待每个图元,而Map,管你是人不...不,管你是什么图元模型,一律照杀....其实就是在fragment shader里做alpha test,剔除背景色。

  1. void main()
  2. {
  3.   vec4 alphatexcolor = tex2D(alphatex, gl_TexCoord[0].xy);
  4.   if( alphatexcolor.x < 0.05 && alphatexcolor.y < 0.05 && alphatexcolor.z < 0.05)
  5.          discard;
  6.  
  7.    gl_FragColor = gl_Color * diffuse * alphatexcolor;
  8. }

譬如这里是黑色背景的树,于是把接近黑色的的像素剔除,把此shader应用于画树的那部分函数,直接可得结果。怎么样,图元是矩形,阴影不是吧?

shadow map 3

shadow map 3
对其他背景色也是一样的。但是最好还是在photoshop里把所有图片背景色转为一样的吧(建议与清屏时那颜色一致,我用的是黑色来glClear)。另外纹理图上多少会残留一点点因颜色容差造成的“碎块”,这时候与屏幕背景色一致的话,用透明就可以消除它们了(这里我没做)。

4. Shadow Map延伸技术

1.PSM():不太了解(事实上所有的都不太了解 - -),不过大概来说,就是为了解决上面提到的“光视野”与“相机视野”的矛盾,通过另类的光源版本投影矩阵“配合”好这两个视锥(硬来,改变光路),让“眼所见即光所见”。副作用当然是光源移动的时候的不连续啦。

2.LiPSM (Light Space Perspective Shadow Map)不同于PSM之处在于它不会“硬来”,而是在光源空间“新建”一个光源视锥(平行于原光路)。这通常是比较直观的图形学解决之道:神不知鬼不觉地偷偷弄一个适合的光源视锥,原来都不影响。影子是根据这个新光源视锥来的——但是在外面,观看场景的我们只看到原来的一个光源,还有物体还有影子——自然而然地被骗了。(有点像Shadow Volume里乱走空间的光源呵呵)

3.TSM(Trapezoidal Shadow Maps )你可以看看这个网址:Anti-aliasing and Continuity with Trapezoidal Shadow Maps,该介绍的都有了,比PSM,比Bounding Box (旧的SM技术),优势从一个视频明显体现!但是......那个,看看算法:Trapezoidal Shadow Maps (TSM) - Recipe, 那个真◆视觉梯形的弄法真是.....囧。世界太可怕了TAT。极高的反锯齿性能,视觉。关键在于把光源投影矩阵替换成那个复杂扭曲的梯形(发现优化技术很多都在于对光源投影矩阵动手脚啊)。

4.CSM(Cascaded Shadow Maps)Cascaded是级联的意思。此方式与前不同,相当于给阴影做LOD。前面说过,这是针对大规模场景光照的阴影技术(太阳普照~),从另一个角度来解决锯齿:通过不同的阴影深度图。你这么理解吧,太阳光下的树的影子,你离它越近,场景应用的深度图越清晰(因为移近平行的太阳光对阴影生成影响不大,而在此距离下“截频”出来的深度图是高精的),你离它越远,当然,场景变大,物体变多,但是这时候用的深度图有必要那么精确吗?于是就换了。这样,控制得好的话,近看远看都不成问题。当然,细节问题有待探讨。

shadow map 3
(最后用一张恶搞图结束)

下篇预告:Shadow Map阴影贴图技术之探Ⅳ [CSM]

本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
      原文地址:http://www.zwqxin.cn/archives/opengl/shadow-map-3.html

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2024 ZwqXin. All Rights Reserved. Theme edited from ipati.