javascript - 绘制到 HTML 5 Canvas 的最快方法是什么?

标签 javascript performance html5-canvas

我正在研究仅使用 HTML 的 Canvas 作为显示媒体制作游戏的可能性。以我需要完成的示例任务为例,我需要从多个等距图 block 构建游戏环境。当然,在 2D 中工作意味着它们必须采用矩形包装,因此图 block 之间有很大的重叠。

我已经足够大了,这个问题的自然解决方案是调用 BitBltMasked。哦等等,不,HTML Canvas 没有像 BitBlt 这样简单和令人愉悦的东西。似乎将像素数据转储到 Canvas 中的唯一方法是使用没有忽略 alpha channel 的有用绘图模式的 drawImage() 或使用在数组中具有图像数据的 ImageData 对象。使用权。是。界限。检查。和。所以。狗。慢。

好吧,这与其说是一个问题,不如说是一个咆哮(W3C 之类的事情往往会激起我的兴趣),但我真正想知道的是如何快速绘制到 Canvas 上?我发现很难摆脱这种感觉,即每秒执行 100 次 drawImages(),每次绘制都尊重 alpha channel 本质上是有罪的,并且可能使我的应用程序在许多浏览器中表现得像屁股一样。另一方面,正确实现 BitBlt 的唯一方法在很大程度上依赖于使用类似热点的执行技术的浏览器来使其快速运行。

有什么方法可以在所有可能的实现中快速绘制,还是我只需要忘记性能?

最佳答案

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

首先,您应该知道 drawImage 可以接受 Canvas,而不仅仅是图像。 “子 Canvas ”es 甚至不需要在 DOM 中。这意味着您可以在一个 Canvas 上进行一些合成,然后将其绘制到另一个 Canvas 上。这打开了一个充满优化机会的世界,尤其是在等距图 block 的情况下。

假设您有一个长 50 格、宽 50 格的区域(为了我自己的理智,我会说米)。您可以将该区域划分为 10x10 米的 block 。每个 block 都由它自己的 Canvas 表示。要绘制完整场景,您只需将每个 block 的 Canvas 对象绘制到显示给用户的主 Canvas 上。如果只有四个 block (一个 20x20m 的区域),您将只执行四个 drawImage 操作。

当然,每个单独的 block 都需要渲染自己的 Canvas 。在 block 中没有发生任何事情的游戏时间刻度上,您只需不做任何事情:Canvas 将保持不变并按照您的预期进行绘制。当某些事情确实发生变化时,您可以根据自己的游戏执行以下操作之一:

  1. 如果您的图 block 延伸到三维(即:您有一个 Z 轴),您可以将 block 的每个“层”绘制到它自己的 Canvas 中,并且只更新需要更新的层。例如,如果每个 block 包含十层深度,则您将有十个 Canvas 对象。如果更新了第 6 层上的某些内容,您只需要重新绘制第 6 层的 Canvas(可能每平方米一个 drawImage,即 100 个),然后执行一个 drawImage chunk 中的每层操作(十)重新绘制 chunk 的 Canvas。减少或增加 block 大小可能会增加或减少性能,具体取决于您对游戏环境所做的更新次数。可以进一步优化以消除对模糊图 block 等的 drawImage 调用。
  2. 如果您没有第三维,您可以简单地在每平方米的 block 上执行一个drawImage。如果更新了两个 block ,则每次更新只有 200 次 drawImage 调用(加上屏幕上可见的每个 block 调用一次)。如果您的游戏只涉及很少的更新,则减小块大小会进一步减少调用次数。
  3. 您可以在自己的游戏循环中对 block 执行更新。如果您正在使用 requestAnimationFrame(您应该这样做),则只需将 block Canvas 对象绘制到屏幕上。独立地,您可以在 setTimeout 循环等中执行游戏逻辑。然后,每个 block 都可以在帧之间的自己的滴答中更新,而不会影响性能。这也可以在 Web Worker 中完成,使用 getImageDataputImageData 在需要更新时将渲染的 block 发送回主线程,尽管无缝地完成这项工作将付出很多努力。

您的另一个选择是使用像 pixi.js 这样的库来使用 WebGL 渲染场景。即使对于 2D,它也会通过减少 CPU 需要完成的工作量并将其转移到 GPU 来提高性能。我强烈建议您检查一下。

关于javascript - 绘制到 HTML 5 Canvas 的最快方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8917384/

相关文章:

javascript - 在一个选项卡中选中的单选按钮在其他选项卡中未选中

javascript - Express.js - 如何检查 header 是否已发送?

c# - 由于 JIT_MethodAccessCheck,编译的表达式树很慢

python - pandas 中的并行字符串替换

mysql - 哪个更快?插入还是更新?

javascript - 使用 canvas 绘制从 div 到 div 的时间线

javascript - 如何使用canvas和javascript对图像进行像素化

javascript - 将多个数据条目存储到 javascript 对象中?

javascript - Google Charts 每页仅显示一个图表

css - 将 svg 转换为 png 时如何包含 CSS 样式