我正在研究一个基于HTML5的游戏,我希望在网格中混合绘制成数百个方格的单元格的不同颜色的半圆形区域。效果就像热图。经过一番研究,我发现了Simon Sarris上面记录的“阴影”技术。
实现这种技术实现了我想要的外观。我喜欢这很容易理解。然而,在实践中,我发现即使是少数(〜150)的阴影渲染,也比我之前用于绘制数千个填充矩形的技术(不过没有吸引力)慢得多。
所以我决定做一些分析。我写了一些基本的JavaScript(可在https://jsfiddle.net/Flatfingers/4vd22rgg/上看到一个修改版本),将5种不同形状类型的2000个副本绘制到1250x600画布的非重叠部分上,最后记录这五个操作中每一个的运行时间五种主流桌面浏览器以及移动Safari的版本。 (对不起,桌面Safari,我也没有Android的方便测试。)然后我尝试了不同的效果组合,并记录了经过的时间。
下面是如何我绘制两个梯度具有相似的外观,以阴影填充弧一个简化的例子:
var gradient1 = context.createRadialGradient(75,100,2,75,100,80);
gradient1.addColorStop(0,"yellow");
gradient1.addColorStop(1,"black");
var gradient2 = context.createRadialGradient(125,100,2,125,100,80);
gradient2.addColorStop(0,"blue");
gradient2.addColorStop(1,"black");
context.beginPath();
context.globalCompositeOperation = "lighter";
context.globalAlpha = 0.5;
context.fillStyle = gradient1;
context.fillRect(0,0,200,200);
context.fillStyle = gradient2;
context.fillRect(0,0,200,200);
context.globalAlpha = 1.0;
context.closePath();
的时间设置
(2000不相重叠的形状,集globalAlpha的,的drawImage()被用于梯度而不是阴影)
IE 11 (64-bit Windows 10)
Rects = 4 ms
Arcs = 35 ms
Gradients = 57 ms
Images = 8 ms
Shadows = 160 ms
Edge (64-bit Windows 10)
Rects = 3 ms
Arcs = 47 ms
Gradients = 52 ms
Images = 7 ms
Shadows = 171 ms
Chrome 48 (64-bit Windows 10)
Rects = 4 ms
Arcs = 10 ms
Gradients = 8 ms
Images = 8 ms
Shadows = 203 ms
Firefox 44 (64-bit Windows 10)
Rects = 4 ms
Arcs = 21 ms
Gradients = 7 ms
Images = 8 ms
Shadows = 468 ms
Opera 34 (64-bit Windows 10)
Rects = 4 ms
Arcs = 9 ms
Gradients = 8 ms
Images = 8 ms
Shadows = 202 ms
Mobile Safari (iPhone5, iOS 9)
Rects = 12 ms
Arcs = 31 ms
Gradients = 67 ms
Images = 82 ms
Shadows = 32 ms
观测
- 其中填充图案,充满rects一贯在所有测试的浏览器和环境的最快运行。
- 在IE 11和Edge中填满的圆弧(圆圈)比填充的矩形慢10倍,而其他主流浏览器中的慢了大约3.5倍。
- 渐变的速度比IE 11,Chrome 48和Opera 34中的反应速度慢大约3倍,但是在Firefox 44中速度要慢100倍(请参阅Bugzilla report 728453)。
- 通过drawImage()处理的图像大约是所有桌面浏览器中填充矩形的1.5倍。
- 带阴影的实心圆弧是最慢的,范围从IE,Edge,Chrome和Opera中的实际直径的50倍慢到Firefox的100倍。
- Chrome 48和Opera 34在除阴影填充圆弧之外的每种形状都非常迅速,但它们并没有比其他浏览器差。
- 当drawImage()绘制1000个形状,其中shadowOffsetX或shadowOffsetY被赋予一个超出物理屏幕分辨率的值时,Chrome和Opera崩溃。
- IE 11和Edge比其他桌面浏览器绘制弧线和渐变要慢。
- drawImage()在移动Safari上很慢。绘制多个渐变和阴影弧比用drawImage()多次绘制一个副本更快。
- Firefox中的绘制对以前的操作非常敏感:绘制阴影和渐变使绘制弧线变慢。显示最快的时间。
- Mobile Safari中的绘图对以前的操作非常敏感:阴影会使渐变变慢;渐变和弧使drawImage()甚至比通常慢。显示最快的时间。
分析
虽然shadowOffset特征是混合形状的简单和直观有效的方式,它是比所有其他技术显著慢。这限制了其仅适用于绘制一些阴影的应用程序,并且不需要快速反复绘制多个阴影。此外,当使用drawImage()加快速度时,给shadowOffsetX或shadowOffsetY一个大于3000的值会导致Chrome 48和Opera 34挂起将近一分钟,消耗CPU周期,然后崩溃我的nVidia显示驱动程序,即使在更新之后到最新版本。 (谷歌搜索没有发现有关Chromium的错误报告,当大型shadowOffset和drawImage()一起使用时,它会描述此错误。)
对于需要混合模糊形状的应用程序,最直观的方法是将globalCompositeOperation “更轻”,并使用带有globalAlpha值的drawImage()重复绘制预制的径向渐变,或者在需要使用不同颜色时绘制单独的渐变。这不是重叠阴影的完美匹配,但它很接近,避免了按像素计算。 (但是,请注意,在移动Safari中,直接绘制阴影填充弧实际上比渐变和drawImage()更快)。将globalCompositeOperation设置为“更浅”会导致IE 11和Edge在绘制弧中速度减慢大约10倍,并使用径向渐变仍然比在所有主要桌面浏览器中使用阴影填充弧更快,并且只比移动Safari中的阴影填充弧要慢两倍。
结论
如果你唯一的目标平台是iPad/iPhone的,对于好看的混合形状的阴影充满弧线的最快方法。否则,迄今为止我发现的所有主要桌面浏览器都具有可比较外观的最快方法是绘制放射状渐变,并将globalCompositeOperation设置为“更轻”,并使用globalAlpha控制不透明度。
注:在我进行的绘图测试中,有一些明显的方法可以提高性能。特别是,将每个形状的每个实例绘制到屏幕外缓冲区,然后将该整个缓冲区绘制到可见画布上会显着提高性能。但是这会否定这个测试的目标,即比较在可见画布上绘制各种形状的相对速度。
两个渐变的重叠区域合并但不合并。 - 你能不能逐像素地描述合并? – 2012-04-12 09:11:46