【发布时间】:2016-07-08 12:23:06
【问题描述】:
我正在尝试复制here on stackoverflow 中描述的方法。 但是我遇到了一些我不知道如何解决的问题。
我设置了jsfiddle 来演示一切。 这是second jsfiddle,只有粒子在移动和被绘制。
我的问题在于绘图,分析器显示大约 10000 个粒子 drawImage 占用了总循环时间的 40%。不直接画图,只做计算,不妨碍代码执行,所以问题出在画图上。
有没有办法在没有这些副作用的情况下使用这种技术?目前,我向您展示了如何使用圆弧创建圆形区域,但我也将 png 文件用于其他一些对象,它们表现出完全相同的行为。
(问题:黑色重叠区域而不是透明区域,通过上面的圆圈可以看到底部圆圈的边缘)
我希望我尽可能清楚地表达自己(上图非常清楚地显示了我的问题),感谢您的帮助。
绘图功能 - 最终绘制到可见画布。
Game.prototype.draw2 = function(interpolation, canvas, ctx, group)
{
var canvasData = ctx.createImageData(canvas.width, canvas.height),
cData = canvasData.data;
for (var i = 0; i < group.length; i++)
{
var obj = group[i];
if(!obj.draw)
{
continue;
}
var imagePixelData = obj.imagePixelData;
var x = obj.previous.x + (obj.x - obj.previous.x) * interpolation;
var y = obj.previous.y + (obj.y - obj.previous.y) * interpolation;
for (var w = 0; w < obj.width; w++)
{
for (var h = 0; h < obj.height; h++)
{
if (x + w < canvas.width && obj.x + w > 0 &&
y + h > 0 && y + h < canvas.height)
{
var iData = (h * obj.width + w) * 4;
var pData = (~~ (x + w) + ~~ (y + h) * canvas.width) * 4;
cData[pData] = imagePixelData[iData];
cData[pData + 1] = imagePixelData[iData + 1];
cData[pData + 2] = imagePixelData[iData + 2];
if (cData[pData + 3] < 100)
{
cData[pData + 3] = imagePixelData[iData + 3];
}
}
}
}
}
ctx.putImageData(canvasData, 0, 0);
};
这就是我如何在其他不可见的画布上准备粉红色的圆形区域。
Game.prototype.constructors.Attractor.prototype.getImageData = function(context)
{
this.separateScene = new context.constructors.Graphics(this.width, this.height, false);
this.image = this.separateScene.canvas;
this.separateScene.ctx.beginPath();
this.separateScene.ctx.arc(this.radius, this.radius, this.radius, 0, 2 * Math.PI, false);
this.separateScene.ctx.fillStyle = '#ff9b9b';
this.separateScene.ctx.fill();
this.separateScene.ctx.beginPath();
this.separateScene.ctx.arc(this.radius, this.radius, this.radiusCut, 0, 2 * Math.PI, false);
this.separateScene.ctx.fillStyle = 'rgba(255, 255, 255, 0.27)';
this.separateScene.ctx.fill();
this.separateScene.ctx.beginPath();
this.separateScene.ctx.arc(this.radius, this.radius, this.coreRadius, 0, 2 * Math.PI, false);
this.separateScene.ctx.fillStyle = '#ff64b2';
this.separateScene.ctx.fill();
this.imageData = this.separateScene.ctx.getImageData(0, 0, this.width, this.height);
this.imagePixelData = this.imageData.data;
};
【问题讨论】:
-
您的问题太大,任何人都无法回答。我们无法通过您的 500 行代码来查看您做错了什么,最好在每个帖子中问一个问题。当您有 10000 多个要绘制的对象时,您链接的帖子非常适合。在 5000 以下,
drawImage在我测试过的大多数机器上都更快,所以我什至不确定你是否需要它。你的原始图像越大,这个解决方案就会变得越慢。<100用于检查像素是否透明。超过这个阈值,我们可以认为它是一个抗锯齿伪影,我们不想要它。 -
我删除了额外的信息,只保留了主要问题。谢谢你。顺便说一句,我正在使用更多数量的粒子(屏幕上大约 10k)。使用 chrome profiler,我将问题减少到 drawImage() 函数,它在运行整个代码时占用了总时间的 40%。我的绘图功能没有 500 行,其余的与问题本身并没有真正的联系。
-
我又添加了一个只有粒子的小提琴。我添加了一种停止循环并启动它的方法。第二个小提琴显示了与加载的 png 图像相同的问题,该图像首先被绘制到单独的画布中,然后来自该画布的 imageData 用于绘制到可见画布上。除了我已经在 jsfiddle 中所做的之外,我无法提供任何其他行,因为我已经注释掉了其他所有内容然后只画。我在单独的画布上绘制 FPS (...)。
-
就在一分钟前,我设法通过在每次绘制期间手动过滤像素来消除黑色效果,但对于程序生成的动态图形,我显然无法做到这一点。如果需要任何更改,我希望我以正确的方式为您调整了 jsfiddle,请让我知道我正在尽力调整一切以使其更友好。
-
好的,找到了,因为 Loktar 只检查黑色像素,所以仅 alpha 检查就足够了。您需要将整个像素操作块包装在
if(imagePixelData[iData]+imagePixelData[iData + 1]+imagePixelData[iData + 2]+imagePixelData[iData + 3]>0)中并删除if (cData[pData + 3] < 100)行。正如在另一个答案中一样,它仍然会将 r、g 和 b 值更改为我们所在的像素。这不是黑色的问题。更新小提琴:jsfiddle.net/3tLzpLyd/7 很抱歉之前误导了 cmets。
标签: javascript html canvas putimagedata