HTML5画布 - 保存路径或剪切区域以便重复使用

10

我目前正在游戏中实现一个可变形的2D地形效果,做得还不错,但随着我开始添加更多的层次到效果中,我可以想象它会变得非常占用性能。

现在我正在寻找一种可能的方法,可以保存路径、剪切蒙版或类似的东西,而不是要在每一帧中都存储绘制路径中的每个点。当我添加更多的层次时,我将不得不越来越多地迭代路径,这可能包含成千上万个点。

这里有一些非常简单的代码,以展示我目前在做什么。

for (var i = 0; i < aMousePoints.length; i++)
{
    cRenderContext.save();
    cRenderContext.beginPath();
    var cMousePoint = aMousePoints[i];
    cRenderContext.arc(cMousePoint.x, cMousePoint.y, 30, 0, 2 * Math.PI, false);
    cRenderContext.clip();
    cRenderContext.drawImage(cImg, 0, 0);
    cRenderContext.closePath();
    cRenderContext.restore();
}

基本上,我需要一种有效的方法来在每一帧上反复绘制我的图像裁剪掩模。

3个回答

15
注意,剪裁区域除了其x/y位置外保持完全相同。这是一个很大的优点。
剪切区域是使用context.save()context.restore()保存和恢复的内容之一,因此可以通过这种方式保存它(换句话说,仅定义一次)。当您想要放置它时,将使用ctx.translate()而不是arc的x,y。
但是,可能更有效的方法是:
  1. 拥有一个内存画布(从未添加到DOM或显示在页面上),仅用于包含剪切区域,并且大小与剪切区域相同
  2. 将剪切区域应用于此内存画布,然后将图像绘制到此画布上。
  3. 然后使用drawImage将内存画布与游戏上下文一起绘制。换句话说:cRenderContext.drawImage(in-memory-canvas, x, y);其中x和y是适当的位置。
因此,这种方式剪切区域始终保持在同一位置,只绘制一次。图像在剪切画布上移动,然后绘制以正确显示,然后将内存画布绘制到主画布上。这样应该更快,因为调用drawImage比创建和绘制路径要快得多。 作为单独的性能考虑,请勿调用saverestore,除非必须这样做。它们需要时间,在上面的循环中是不必要的。
如果您的代码是开源的,请告诉我,如果您希望,我会就它的绩效整体进行查看。

第二种方法听起来很不错!所以我猜掩模画布的透明度会自动工作?如果我只在掩模画布中画一个路径,那么只有这条路径会被画到第二个画布上,只要我在画布上没有其他东西就可以了?非常感谢你的帮助! - Tristan
好的。如果您需要帮助使示例正常工作,请告诉我,我会为您创建一个示例。 - Simon Sarris
我在优化方面遇到了严重的困难。我现在的情况是必须要对图像或视频进行裁剪。似乎无法创建Path2d()来保存剪辑路径。我已经尝试了您建议的,在内存中创建一个单独的画布进行裁剪,但是好像这样并不起作用。您能告诉我错在哪里吗?http://codepen.io/paceaux/pen/egLOeR - paceaux

11
为什么不给前景和背景各一个画布呢?就像下面的演示一样。 前景/背景演示(可能有点过头了,我喜欢玩JS/画布)。 但基本上,前景画布除内容外是透明的,因此它会像遮罩层一样覆盖在背景画布上。

6

看起来现在可以使用新的path2D对象实现。

新的Path2D API(从Firefox 31+可用)允许您存储路径,简化画布绘制代码并使其运行更快。构造函数提供了三种创建Path2D对象的方式:

new Path2D();     // empty path object
new Path2D(path); // copy from another path
new Path2D(d);    // path from from SVG path data

第三个版本特别方便,它使用SVG路径数据进行构建。现在,您可以重复使用SVG路径,直接在画布上绘制相同的形状:
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");

信息取自Mozilla官网


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接