Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

WebGL(贰拾壹) 柔化阴影(Soft Shadow Mapping)

  在拾柒和拾捌篇中已经说过了绘制阴影的原理,但是那个阴影很生硬,视觉效果很差。现在我们要来柔化这个阴影,也就是模糊阴影。这个问题也需要从实际角度出发来考虑,而不是完全想着如果做模糊效果。如果只是单纯的模糊,高斯在两百多年前就已经解决了。
  如果没有光,整个世界都将笼罩在黑暗之中。光的存在驱散了大部分阴影,我们看到的阴影就是光无法到达的地方。为什么光无法到达呢?因为光是直线传播的,被挡住当然就无法到达,于是我们就看到了阴影。那么,为什么我们看到的影子边缘都是模糊的呢!?就这个问题,我查到的有这三种说法:“粉尘说”、“衍射说”、“半影说”。确实,他们都会对影子的边缘造成模糊,但是我们观察太阳光下建筑物的影子会发现,这个模糊程度远远超出了“粉尘说”和“衍射说”能达到的程度,只有的“半影说”可以解释。“半影说”的内容是因为光源很大,它就不是单纯的点光源,而是无数的点光源在一个区域内的集合。由于每个点光源由于位置的不同,它们产生的阴影位置也会不同,这些阴影叠加起来就使得边缘变模糊了。
  以上就是影子边缘模糊的成因,说白了就是光源的位置与数量的问题。之前文章中的阴影使用平行光的例子,这篇也依然用平行光吧。我们的平行光,实际上只是近似的太阳光,可以看做是无穷远处的一个点光源。既然确定是在无穷远,就没有位置的概念了。可是我们的需求是需要光源的位置稍微抖动,那怎么办?其实我们有更便利的办法。我们的平行光会先绘制出一个深度缓冲的吧?这个深度缓冲就是阴影的位置。既然平行光无法抖动光源,那么抖动这个深度缓冲不也一样吗?于是我们在片段着色器中这样写代码 //片段着色器
precision lowp float;
uniform sampler2D fbTexture; //帧缓冲贴图数据
uniform vec3 ambient;
uniform bool work; //操作类型
varying float diffuse;
varying vec4 xPosition;
//根据深度信息,计算某点的漫射亮度,参数为当前点的相对坐标
float getLightWeight(float x,float y){
  //把输入的参数放入一个向量,并把它转换为贴图上的坐标
  vec2 p=vec2(x,y)/512.0;
  //把当前坐标转换成贴图坐标,并附上刚计算出的坐标
  vec2 mp=(xPosition.xy+p*10.0)/xPosition.w*0.5+0.5;
  //从贴图中获取相应坐标的深度信息
  float dp=texture2D(fbTexture,mp).z;
  //如果贴图深度和当前深度接近则返回漫射亮度否则返回最低漫射亮度
  return abs(xPosition.z-dp)<0.01?diffuse:0.2;
}
void main(){
  if(work){
    gl_FragColor=vec4(xPosition.zzz,1.0);
  }else{
    //计算周围两圈光线亮度的平均值
    float s=0.0;
    for(float i=-2.0;i<=2.0;i++)
      for(float j=-2.0;j<=2.0;j++)
        s+=getLightWeight(i,j);
    s/=25.0;
    //正常计算颜色并输出
    gl_FragColor=vec4(vec3(0.6)*s,1.0)+vec4(ambient,1.0);
  };
}

  光线提供给某点的亮度就是所有光源在这个点上的亮度叠加吧?由于我本身没有因为光源的数量增加而降低单个光源的亮度,所以这里就不用叠加而是用平均值。代码中还有个二重循环,它是用来抖动光源的,只有这样我们才能计算出所有光源作用在某点上的强度。getLightWeight函数两个参数,它们代表当前点的相对位置,循环中使用整数的,把它传入函数后,需要对于到贴图上,而贴图上的坐标是[0,1]区间的,所以直接传入整数当然不行,需要除以贴图本身的大小才能得到贴图上的正确坐标。代码中还把p乘以了10,这个是模糊的大小。循环的整数是[-2,2],把它除以贴图的大小512得到的值非常小,也就是两个单位的模糊而已,几乎看不出结果。所以需要把它稍微放大,这里用了10倍原大小。其它地方就没什么难点,我就不说了,最后是这个实例的完整代码。

  WebGL模糊阴影
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^