绘制HTML 5画布的最快方法是什么?

时间:2012-01-18 21:03:49

标签: javascript performance html5-canvas

我正在研究仅使用HTML画布作为显示媒体制作游戏的可能性。为了完成我需要做的示例任务,我需要从多个等距区块构建游戏环境。当然,在2D工作意味着他们必然会采用矩形包装,因此瓷砖之间会有很大的重叠。

我已经够老了,这个问题的自然解决方法是调用BitBltMasked。哦等等,不,HTML画布没有像BitBlt那样简单和令人愉悦的东西。似乎将像素数据转储到画布的唯一方法是使用drawImage(),它没有用于忽略alpha通道的有用绘图模式,或者使用具有数组中图像数据的ImageData对象。访问。是。界限。检查。和。因此。狗。慢。

好吧,这更像是一个咆哮而不是一个问题(W3C喜欢的事情往往会引起我的注意),但我真正想知道的是如何快速画到画布上?我发现很难放弃做100s drawImages()的感觉,每次抽奖都尊重alpha通道,这本身就是有罪的,并且可能使我的应用程序在许多浏览器中表现得像屁股。另一方面,实现BitBlt的唯一方法在很大程度上依赖于浏览器使用类似热点的执行技术来使其快速运行。

有没有办法快速划分每个可能的实现,或者我只是忘记性能?

3 个答案:

答案 0 :(得分:3)

这是一个非常有趣的问题,你可以做一些有趣的事情来解决它。

首先,您应该知道drawImage可以接受画布,而不仅仅是图像。 " sub-Canvas甚至不需要在DOM中。这意味着您可以在一个画布上进行一些合成,然后将其绘制到另一个画布上。这开启了整个世界的优化机会,特别是在等距瓷砖的背景下。

让我们假设你的区域有50块瓷砖长50平方米(为了我自己的理智,我会说米)。您可以将区域划分为10x10m块。每个块都由自己的Canvas表示。要绘制完整场景,您只需绘制每个块即可。 Canvas对象显示给用户的主画布。如果只有四个块(20x20m区域),则只执行四次drawImage操作。

当然,每个单独的块都需要渲染自己的Canvas。在大块没有任何反应的游戏标记中,你根本不做任何事情:画布将保持不变,并且会按照你的预期绘制。当某些事情发生变化时,你可以根据自己的游戏做一些事情:

  1. 如果您的瓷砖延伸到第三维(即:您有一个Z轴),您可以绘制每个"层"将块放入其自己的Canvas中,仅更新需要更新的层。例如,如果每个块包含十层深度,则您有十个Canvas对象。如果更新了第6层上的某些内容,您只需要重新绘制第6层的画布(每平方米可能只有一个drawImage,这将是100),然后执行一次drawImage操作块中的每一层(十)重新绘制块的画布。减少或增加块大小可能会增加或减少性能,具体取决于您对游戏环境所做的更新次数。可以进一步优化以消除对隐藏的图块等的drawImage调用。
  2. 如果您没有第三维,则只需每平方米一块drawImage执行一次。如果更新了两个块,那么每个滴答只能进行200次drawImage次呼叫(加上屏幕上可见的每个块一次呼叫)。如果您的游戏只涉及很少的更新,减少块大小将进一步减少通话次数。
  3. 您可以在自己的游戏循环中对块进行更新。如果你正在使用requestAnimationFrame(就像你应该这样),你只需要将块Canvas对象绘制到屏幕上。独立地,您可以在setTimeout循环等中执行游戏逻辑。然后,每个块可以在帧之间自己更新,而不会影响性能。这也可以在Web工作者中使用getImageDataputImageData在需要更新时将渲染的块发送回主线程,尽管无缝地完成这项工作需要花费大量的精力
  4. 您拥有的另一个选项是使用像pixi.js这样的库来使用WebGL渲染场景。即使对于2D,它也会通过减少CPU需要做的工作量并将其转移到GPU来提高性能。我强烈建议您查看它。

答案 1 :(得分:1)

我知道GameJS有blit操作,我当然也认为其他任何html5游戏库都有(gameQuery,LimeJS等)。我不知道这些软件包是否已经解决了您所遇到的特定数组边界检查问题,但实际上它们的样本似乎在所有平台上运行得非常快。

你不应该假设加速是有意义的。例如,GameJS开发人员报告他将实施脏矩形跟踪,但事实证明现代浏览器会自动执行此操作--- link

出于这个原因和其他原因,我建议在考虑速度之前先做点工作。此外,使用绘图库,因为作者可能花了一些时间来优化性能。

我对此没有个人知识,但您可以查看appMobi“直接画布”HTML元素,据称这是普通画布的更快版本link。我很困惑这是适用于所有浏览器还是只适用于webkit浏览器,或者只是appMobi自己的特殊浏览器。

同样,如果没有对Web浏览器内部流程的深入了解,您不应该假设加速是有意义的。关于“直接画布”的网页提到了一系列减慢画布速度的事情:“重新流动文本,映射热点,为参考链接创建索引,不断创建。”没有提到Alpha混合和数组边界检查是导致缓慢的主要原因!

答案 2 :(得分:0)

不幸的是,没有办法解决alpha合成开销问题。剪切可能是一种解决方案,但我怀疑会有多少(如果有的话)性能提升。更不用说这种路线在不规则形状上的实施有多复杂。

当你必须绘制整个显示器时,你将不得不处理性能损失。虽然之后,您有一个完整的屏幕预先计算的阿尔法图像,您可以在一个 drawImage 调用中以偏移量绘制此图像数据。然后,您只需要单独绘制滚动到视图中的新切片。

但是,浏览器仍然需要在画布中的不同位置重绘每个像素。这是非常昂贵的。如果只有滚动像素的方法会很好,但也没有运气。

我想到的一个想法是,您可以实现多个画布,翻译每个画布而不是重新绘制像素。这将允许浏览器以更原生的方式决定如何重绘这些像素,至少在理论上是这样。然后,您可以在新的或已使用/缓存的canvas元素上呈现新显示的tile。定位它以匹配最后一个屏幕渲染。

但那只是我的两个蠢事...我的意思是......我的意思是美分:]