Javascript 减去不透明度而不是相乘
我试图让它看起来好像我的Javascript 减去不透明度而不是相乘,javascript,html,canvas,alpha,alphablending,Javascript,Html,Canvas,Alpha,Alphablending,我试图让它看起来好像我的上的运动创建了运动轨迹。为了做到这一点,我没有清除帧之间的画布,而是通过将clearRect调用替换为如下内容来降低现有内容的不透明度: // Redraw the canvas's contents at lower opacity. The 'copy' blend // mode keeps only the new content, discarding what was previously // there. That way we don't have to
上的运动创建了运动轨迹。为了做到这一点,我没有清除帧之间的画布,而是通过将clearRect
调用替换为如下内容来降低现有内容的不透明度:
// Redraw the canvas's contents at lower opacity. The 'copy' blend
// mode keeps only the new content, discarding what was previously
// there. That way we don't have to use a second canvas when copying
// data
ctx.globalCompositeOperation = 'copy';
ctx.globalAlpha = 0.98;
ctx.drawImage(canvas, 0, 0);
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
但是,由于设置globalAlpha
乘以alpha值,因此轨迹的alpha值可能接近零,但实际上永远不会达到。这意味着图形永远不会完全褪色,在画布上留下这样的痕迹,即使在数千帧经过几分钟后也不会褪色:
为了解决这个问题,我一直在逐像素减去alpha值,而不是使用globalAlpha。减法保证像素不透明度将达到零
// Reduce opacity of each pixel in canvas
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// Iterates, hitting only the alpha values of each pixel.
for (let i = 3; i < data.length; i += 4) {
// Use 0 if the result of subtraction would be less than zero.
data[i] = Math.max(data[i] - (0.02 * 255), 0);
}
ctx.putImageData(imageData, 0, 0);
//减少画布中每个像素的不透明度
const imageData=ctx.getImageData(0,0,canvas.width,canvas.height);
常量数据=imageData.data;
//迭代,仅命中每个像素的alpha值。
对于(设i=3;i
这解决了问题,但速度非常慢,因为我手动更改每个像素值,然后使用昂贵的putImageData()
方法
是否有一种更有效的方法来减去而不是乘以画布上绘制的像素的不透明度?不幸的是,除了手动迭代像素以清除低值alpha像素之外,我们无能为力 该问题与(更多详细信息,请参阅答案) 有一些混合模式,例如“亮度”(在某种程度上是“倍增”)可以用来减去亮度,问题是它在整个曲面上都起作用,而复合模式只在alpha上起作用-复合操作中没有等效模式。所以这在这里没用 还有一个新的通过CSS的luma遮罩,但问题是图像源(理论上可以使用例如对比度进行操作)必须每帧更新,基本上,性能会非常差 变通办法 一种解决方法是使用“粒子”。也就是说,不是使用反馈循环,而是记录和存储路径点,然后每帧重新绘制所有记录的点。在许多情况下,使用max值并重用它来设置alpha可以很好地工作 这个简单的例子只是一个概念证明,可以通过各种方式实现,例如预填充数组、绘图顺序、alpha值计算等等。但我想你会明白的
var ctx=c.getContext(“2d”);
变量cx=c.width>>1,cy=c.height>>1,r=c.width>>2,o=c.width>>3;
变量粒子=[],最大值=50;
ctx.fillStyle=“#fff”;
(功能动画(t){
变量d=t*0.002,x=cx+r*Math.cos(d),y=cy+r*Math.sin(d);
//达到最大值时存储点和修剪阵列
粒子推动({x:x,y:y});
如果(particles.length>max)particles.shift();
//像往常一样清除框架
ctx.clearRect(0,0,c.宽度,c.高度);
//以log.alpha重新绘制所有粒子,但最后一个粒子已绘制满
对于(var i=0,p,a;p=particles[i++];){
a=i/max*0.6;
ctx.globalAlpha=i==max?1:a*a*a;
ctx.fillRect(p.x-o,p.y-o,r,r);//或图像等。
}
请求动画帧(anim);
})();代码>
body{背景:#037}
如果你把0.98,那么你可能还可以检查它是否接近1左右,并将其设置为0?@EricG图像不同部分的不透明度不同,整个东西一次就画出来了。该效果是通过以较低的不透明度绘制整个最后一帧来实现的,这意味着之前的帧也是可见的,但不透明度进一步降低。我没有检查单个像素的不透明度;那太贵了。维护你画的像素,只更新它们怎么样?然后你不必去看每一个像素,当有重叠时,你会替换像素/值。灵感来源于可能复制的