HTML5画布上有数以千计的移动粒子,我的目标是在每个画布后面绘制一条短的渐弱轨迹。一个很好而快速的方法是不是每帧完全清除画布,而是用半透明颜色覆盖它。这是一个只有一个粒子的例子:
var canvas = document.getElementById('display');
var ctx = canvas.getContext('2d');
var displayHeight = canvas.height;
var backgroundColor = '#000000';
var overlayOpacity = 0.05;
var testParticle = {
pos: 0,
size: 3
};
function render(ctx, particle) {
ctx.globalAlpha = overlayOpacity;
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalAlpha = 1.0;
ctx.fillStyle = '#FFF';
ctx.fillRect(particle.pos, displayHeight / 2, particle.size, particle.size);
}
function update(particle) {
particle.pos += 1;
}
// Fill with initial color
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
function mainLoop() {
update(testParticle);
render(ctx, testParticle);
requestAnimationFrame(mainLoop);
}
mainLoop();

<canvas id="display" width="320" height="240"></canvas>
&#13;
存在一个明显的问题:低不透明度值时,踪迹永远不会完全消失。您可以在我的单粒子示例中看到(几乎)不会消失的水平线。我理解为什么会这样。由半透明ColorB覆盖的ColorA基本上是线性插值,如果我们反复执行以下操作,ColorA永远不会完全收敛到ColorB:
ColorA = lerp(ColorA, ColorB, opacityOfB)
我的问题是,我该怎样做才能使它融合到背景色中,这样小径就不会永远留在那里?手动使用WebGL或绘图轨迹不是有效选项(分别由于兼容性和性能原因)。一种可能性是遍历所有画布像素并手动将低亮度像素设置为背景色,尽管对于大型画布可能会变得昂贵。我想知道是否有更好的解决方案。
答案 0 :(得分:2)
在某些情况下可以使用的解决方法是将overlayOpacity设置为0.1(此值收敛),但是每x次绘制一次,而不是每次渲染调用。 因此,当每隔一段时间绘制它时,它或多或少保持相同的路径长度。
var renderCount = 0;
var overlayOpacity = 0.1;
function render(ctx, particle) {
if((renderCount++)%2 == 0) {
ctx.globalAlpha = overlayOpacity;
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx.globalAlpha = 1.0;
ctx.fillStyle = '#FFF';
ctx.fillRect(particle.pos, displayHeight / 2, particle.size, particle.size);
}
显然,缺点是它看起来更猛烈,或许在你的情况下这可能是不可接受的。
答案 1 :(得分:0)
最佳解决方案是使用复合操作“目标输出”并淡入透明背景。适用于衰落率低至globalAlpha = 0.01且事件略低于0.006,但在此之下可能会很麻烦。然后,如果您需要更慢的淡入淡出,则每隔2帧或3帧进行淡入淡出。
ctx.globalAlpha = 0.01; // fade rate
ctx.globalCompositeOperation = "destination-out" // fade out destination pixels
ctx.fillRect(0,0,w,h)
ctx.globalCompositeOperation = "source-over"
ctx.globalAlpha = 1; // reset alpha
如果您想要彩色背景,则需要在屏幕外的画布上渲染动画,并在每帧的屏幕画布上渲染动画。或者使画布背景成为您想要的颜色。