Web 技术研究所

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

使用透明通道实现渐隐效果的问题

  在Canvas2D中,如果要改变一块画布的亮度,一个最简单的方法是对整张画布进行一次fillRect,填充一个具有适当Alpha通道值的颜色。根据Canvas2D自带的叠加机制,这个半透明的颜色会被混合到现有的颜色上。这种方法虽然简单,但实际上效果并不好。
  背景本身也会受到透明通道叠加的影响,因此使用这个方法来多次叠加透明通道,实现渐隐效果的话,背景的颜色会出问题。在规范自带的Example中就使用了这个方法来简单处理,所以在绘制后,背景会逐渐变灰。
  这个问题可以通过手动处理颜色叠加来解决,也就是取出画布的RGBA数据,处理后再放回去。下面是我把规范自带的Example重写了一遍,并加上了解决方案的Example。
<!DOCTYPE html>
<canvas></canvas><br/>
Darkening Manually: <input id="dkm" type="checkbox" /><br/>
<span id="fps">fps: ?</span>
<script>
//Initialize the Canvas and its context.
var canvas=document.querySelector("canvas");
var width=canvas.width=canvas.offsetWidth;
var height=canvas.height=canvas.offsetWidth;
var g=canvas.getContext("2d");
g.fillRect(0,0,width,height);
var random=Math.random;
var lastX=random()*width,lastY=random()*height;
var hue=0;
//Bind the darkeningManualy to a checkbox.
var darkeningManualy;
dkm.onclick=function(){
  darkeningManualy=dkm.checked;
},dkm.onclick();
//Display the fps.
var text=fps.childNodes[0];
var frames=0;
setInterval(function(){
  text.data="fps: "+frames;
  frames=0;
},1000);
(function callee(){
  //Darken the background.
  if(darkeningManualy){
    var img=g.getImageData(0,0,width,height);
    var data=img.data;
    for(var i=0;i<data.length;i+=4)
      data[i]=data[i]/1.02|0,
      data[i+1]=data[i+1]/1.02|0,
      data[i+2]=data[i+2]/1.02|0;
    g.putImageData(img,0,0);
  }else{
    g.fillStyle="rgba(0,0,0,0.02)";
    g.fillRect(0,0,width,height);
  };
  //Draw a curve.
  g.save();
  g.lineWidth=random()*4+2;
  g.strokeStyle="hsl("+(hue+=8)+",50%,50%)";
  g.shadowColor="#FFF";
  g.shadowBlur=10;
  g.beginPath();
  g.moveTo(lastX,lastY);
  g.bezierCurveTo(
    random()*width,random()*height,
    random()*width,random()*height,
    lastX=random()*width,lastY=random()*height
  );
  g.stroke();
  g.restore();
  //Request next frame.
  requestAnimationFrame(callee);
  frames++;
})();
</script>
  这个是使用fillRect的效果

  下面这个是手动处理叠加的效果

  虽然问题可以这么解决,但其实我很不喜欢这个方法。也许我这PC端上测试300*300的画布完全没有性能问题,因为每一帧也就9E4个像素要处理。但要是在移动端或更大的画布上,比如1024*768的画布上这么做,每帧要处理786432个像素,性能上可能就会出问题。
  这大概也是我不太爱Canvas2D的原因吧,这个处理分明是片段着色器的工作,要是WebGL里面只要交给片段着色器,在GPU上处理就好了。我们这样用CPU去做本应该由GPU来做的事真的好吗?算了,我也只是浅浅地摸一摸Canvas2D罢了。。
网名:
34.203.213.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^