[英]What's the fastest way to draw to an HTML 5 canvas?
我正在调查使用HTML画布作为显示媒体制作游戏的可能性。 为了完成我需要做的示例任务,我需要从多个等距区块构建游戏环境。 当然,在2D工作意味着他们必须采用矩形包装,因此瓷砖之间有很大的重叠。
我已经够大了,这个问题的自然解决方案就是调用BitBltMasked。 哦等等,不,HTML画布没有像BitBlt那样简单和令人愉悦的东西。 似乎将像素数据转储到画布的唯一方法是使用drawImage(),它没有用于忽略alpha通道的有用绘图模式,或者使用具有数组中图像数据的ImageData对象。 访问。 是。 界限。 检查。 和。 因此。 狗。 慢。
好吧,这更像是一个咆哮而不是一个问题(W3C喜欢的东西往往会引起我的注意),但我真正想知道的是如何快速绘制画布? 我发现很难放弃做100s drawImages()的感觉,每次抽奖都尊重alpha通道,这本身就是有罪的,并且可能使我的应用程序在许多浏览器中表现得像屁股。 另一方面,实现BitBlt的唯一方法在很大程度上依赖于浏览器使用类似热点的执行技术来使其快速运行。
有没有办法快速划分每个可能的实现,或者我只是忘记性能?
这是一个非常有趣的问题,你可以做一些有趣的事情来解决它。
首先,您应该知道drawImage
可以接受Canvas,而不仅仅是图像。 “sub-Canvas”甚至不需要在DOM中。 这意味着您可以在一个画布上进行一些合成,然后将其绘制到另一个画布上。 这开启了整个世界的优化机会,特别是在等距瓷砖的背景下。
假设你的区域有50个瓷砖长50个瓷砖宽(为了我自己的理智,我会说米)。 您可以将区域划分为10x10m块。 每个块都由自己的Canvas表示。 要绘制完整场景,您只需将每个块的Canvas对象绘制到显示给用户的主画布上。 如果只有四个块(一个20x20m的区域),则只执行四次drawImage
操作。
当然,每个单独的块都需要渲染自己的Canvas。 在游戏刻度中,块中没有任何反应,您根本不做任何事情:画布将保持不变并将按照您的预期绘制。 当某些事情发生变化时,你可以根据你的游戏做一些事情:
drawImage
,这将是100),然后在块(10)中每层执行一次drawImage
操作以重新绘制大块的画布。 减少或增加块大小可能会增加或减少性能,具体取决于您对游戏环境所做的更新次数。 可以进一步优化以消除对于模糊的瓦片等的drawImage
调用。 drawImage
。 如果更新了两个块,那么每个tick只有200个drawImage
调用(加上屏幕上每个块可以调用一个)。 如果您的游戏只涉及很少的更新,减少块大小将进一步减少调用次数。 requestAnimationFrame
(你应该这样),你只需要将块Canvas对象绘制到屏幕上。 独立地,您可以在setTimeout
循环等中执行游戏逻辑。 然后,每个块可以在帧之间自己更新,而不会影响性能。 这也可以在web worker中使用getImageData
和putImageData
在需要更新时将渲染的块发送回主线程,尽管无缝地完成这项工作需要花费很多精力。 您拥有的另一个选项是使用像pixi.js这样的库来使用WebGL渲染场景。 即使对于2D,它也会通过减少CPU需要做的工作量并将其转移到GPU来提高性能。 我强烈建议您查看它。
我知道GameJS有blit操作,我当然也认为其他任何html5游戏库都有(gameQuery,LimeJS等)。 我不知道这些软件包是否已解决了您所遇到的特定数组边界检查问题,但实际上它们的示例似乎在所有平台上都能快速运行。
你不应该假设加速是有意义的。 例如,GameJS开发人员报告说他将实现脏矩形跟踪,但事实证明现代浏览器会自动执行此操作--- 链接 。
出于这个原因和其他原因,我建议在考虑速度之前先做点工作。 此外,使用绘图库,因为作者可能花了一些时间来优化性能。
我对此没有个人知识,但是您可以查看appMobi“直接画布”HTML元素,据称这是一个更快的普通画布链接版本。 我很困惑这是适用于所有浏览器还是仅适用于webkit浏览器,或者仅适用于appMobi自己的特殊浏览器。
同样,如果没有对Web浏览器内部流程的深入了解,您不应该假设加速是有意义的。 关于“直接画布”的网页提到了一系列减慢画布速度的事情:“重新流动文本,映射热点,为参考链接创建索引,不断创建。” Alpha混合和数组边界检查没有被提及作为缓慢的主要原因!
不幸的是,没有办法解决alpha组合开销问题。 剪切可能是一种解决方案,但我怀疑会有多少(如果有的话)性能提升。 更不用说这种路线在不规则形状上的实施有多复杂。
当你必须绘制整个显示器时,你将不得不处理性能损失。 虽然之后,您有一个完整屏幕的预先计算的alpha图像,您可以在一个drawImage调用中以偏移量绘制此图像数据。 然后,您只需要单独绘制滚动到视图中的新切片。
但是,浏览器仍然需要在画布中的不同位置重绘每个像素。 这是非常昂贵的。 如果只有滚动像素的方法会很好,但也没有运气。
想到的一个想法是,您可以实现多个画布,翻译每个单独的画布而不是重绘像素。 这将允许浏览器以更原生的方式决定如何重绘这些像素,至少在理论上是这样。 然后,您可以在新的或已使用/缓存的canvas元素上呈现新显示的tile。 定位它以匹配最后一个屏幕渲染。
但那只是我的两个blits ...我的意思是位...呃,我的意思是美分:]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.