画布径向渐变与.png性能



我正在尝试用HTMLcanvas元素模拟画笔。为了获得笔刷硬度,我使用了径向梯度,但我不完全确定是为每个点创建新的径向梯度更快,还是将径向梯度保存为图像并使用drawImage()

当前代码:

var gradient = context.createRadialGradient(x, y, hardness * brushSize, x, y, brushSize);
gradient.addColorStop(0, color);
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
context.fillStyle = gradient;
context.fillRect(x - halfBrushSize, y - halfBrushSize, brushSize, brushSize);

drawImage(除了创建图像):

context.drawImage(img, x, y);

Gradients的生成成本与基本上是副本的图像相反。不过,它们都需要经过变换矩阵和抗锯齿处理,但除此之外,还没有涉及图像的计算。

更新从下面的评论来看,根据浏览器和硬件的不同,人们似乎得到了极其多变的测试结果。嵌入式测试不是很准确,只是一个指针,所以出于这个原因,我在这里创建了一个更准确的测试。欢迎在下面的评论中发布结果
-更新结束--

以下不是世界上最准确的测试,但差异如此之大,以至于你在任何情况下都能得到一个很好的指针,指向哪个更快:

window.performance = window.performance || Date;
setTimeout(go, 250);
function go() {
var ctx = c.getContext("2d");
// create radial gradient
var gr = ctx.createRadialGradient(300, 300, 300, 300, 300, 0);
gr.addColorStop(0, "#000");
gr.addColorStop(1, "#f00");
ctx.fillStyle = gr;
// test gradient fill style
var time1 = performance.now();
for (var i = 1000; i--;) ctx.fillRect(0, 0, c.width, c.height);
var time2 = performance.now() - time1;
o.innerHTML = "Gradient: " + time2.toFixed(4) + "<br>";
// test cached gradient (canvas = image source)
ctx = c2.getContext("2d");
time1 = performance.now();
for (i = 1000; i--;) ctx.drawImage(c, 0, 0);
time2 = performance.now() - time1;
o.innerHTML += "drawImage: " + time2.toFixed(4);
}
<output id=o>Running... please wait</output><br>
<canvas id=c width=600 height=600></canvas><br>
<canvas id=c2 width=600 height=600></canvas>

当渲染径向渐变时,您可以动态构建渐变,或者使用引用的png,但还有第三种可能性:您可以使用一次构建的归一化渐变,然后使用上下文转换在任何位置/大小随意使用。

用于为给定硬度创建归一化梯度的代码如下所示:

var mySingleGradient =  ctx.createRadialGradient(0.5, 0.5, 0.5*hardness, 0.5, 0.5, 0.5);
mySingleGradient.addColorStop(0, color);
mySingleGradient.addColorStop(1, '#000');

就像使用png时一样,您会遇到缓存任何基色+硬度的渐变的问题。但是你不会有任何png分辨率的问题,而且很可能渐变的大小会比png的小得多。

你使用这样一个归一化的梯度:

function drawThatGradientHere(ctx, x, y, gradient, brushSize) {
ctx.save();
ctx.translate(x,y);
ctx.scale(brushSize,brushSize);
ctx.fillStyle = gradient;
ctx.fillRect(0,0,1,1);
ctx.restore();
}

我不会讨论基准测试,因为在不了解更多用途的情况下,有太多机会比较苹果和橙子。因为例如,如果使用缩放版本,drawImage的性能可能会非常不同。还要注意,使用图像时,可能会遇到分辨率问题(太高:性能,太低:混叠),而如果使用渐变,则不会遇到这些问题。因此,即使梯度被证明较慢,你也可能更喜欢它,因为它看起来始终如一。

几个问题:你经常改变硬度吗?你经常改变画笔的大小吗?你改变渐变的开始/结束颜色了吗?

只有回答这些问题,并拥有一组随机的rect/硬度,与真实用例的平均分布相同,你才能对任何东西进行基准测试/比较。

最后一句话:如果很难说哪个解决方案更快,那么是时候根据…其他一些好的原因来选择解决方案了…:-)

最新更新