HTML5 Canvas重绘循环性能优化

Nik*_*des 16 javascript optimization paperjs

我们正在构建一个在浏览器中运行的CAD应用程序.

它基于Paper.js,这是一个非常简洁的Canvas库,允许您以编程方式操作矢量.


问题

我目前面临的主要问题是重绘循环性能.

重绘算法是"哑"(就聪明的黑客而言,以提高性能)因而效率低且速度慢 - 渲染场景图项依赖于逐渐减慢的重绘周期.

随着绘图点的累积,每个重绘周期变得越来越慢.

重绘方案非常简单:

  • 清除整个区域
  • 从场景图中获取所有项目
  • 重新绘制所有项目.

这个问题

在这种情况下是否有任何课堂示例进行渲染优化 - 假设我不想实现脏矩形算法(仅绘制已更改的区域)

编辑:我已经尝试过手动的现场光栅化,效果非常好,我在下面发布了一个答案.

art*_*.sw 9

有用的工具

我的paper.js分支可以提供帮助,但它可能不是最合适的.

它使您可以阻止paper.js重绘每个帧的所有内容(使用paper.view.persistence = 1;).

通过这种方式,您可以更好地控制要清除的内容,并且应该重新绘制:例如,当您移动形状时,可以清除它所在的区域(例如,使用本机画布drawRect),并在移动后更新它(使用path.needsUpdate();) .

退税

形状相交时会出现问题.如果要修改与另一个相交的形状,则必须同时更新两者.如果第二个形状与第三个形状相交,那么同样如此,等等.

所以你需要一个递归函数,不难编码,但如果有许多复杂的形状相交,它可能会很昂贵,因此在这种情况下你可能无法获得性能.

(更新)位图缓存

正如Nicholas Kyriakides以下答案中所建议的那样,Bitmap缓存是一个非常好的解决方案.

每个形状一个画布

另一种方法是在单独的画布上绘制每个形状(作为图层工作).这样,您可以独立地自由清除和重绘每个形状.您可以分离未更改的视图的onFrame事件(除了用户正在使用的画布之外的所有画布).这应该更容易,但它会导致其他小问题,例如共享相同的项目视图参数(在缩放的情况下),并且对于许多形状(这意味着许多画布)可能是昂贵的.

静态和动态画布

一个(可能)更好的方法是只有两个画布,一个用于静态形状,一个用于活动形状.静态形状画布将包含所有形状(正在编辑的形状除外),并且只有在用户开始和停止编辑活动形状时才会重绘.当用户开始编辑形状时,它将从静态画布转移到动态画布,而另一种方式则在用户停止时转移.


Nik*_*des 9

这可以通过类似于位图缓存的过程/技术中的光栅化来完成.

高节点数场景图的问题在于渲染它们会导致渲染引擎呻吟.浏览器必须遍历其节点并在画布上渲染其像素.

所以这是一个很好的解决方案:


1.渲染位图,但保持原始形状,隐藏

解决方案是用图像替换矢量,光栅化它们 - 仅在渲染时,但仍保持原始形状在其图像副本下方,仅在非活动状态(当前未被操纵)时处于隐藏状态.

单击图像 - 我们将其删除并切换原始形状的可见性.这样,非活动形状将呈现为图像,活动形状从其位图表示中释放出来并充当矢量,可以自由地进行操作.当它们不活跃时,它们只是坐在那里无法使用它们上面的光栅副本.

这允许引擎保持形状的矢量表示,但避免将它们渲染为矢量 - 而是看起来与它们相似的图像在它们之上分层.

1000个路径命令基本上被单个图像替换 - 但仅在渲染时 - 原始路径实际上作为场景图中的对象存在,或者您正在使用的任何类型的DOM

2.分组进行栅格化

诀窍是在组中执行光栅化- 将10-15个组合在一起并将它们光栅化为单个图像.这样可以保持较低的栅格数.在单击图像时 - 我们可以释放整个组或仅发布单击的项目.

3.在组上附加单击处理程序以在重新激活时恢复向量副本

当光栅化一个组时,我们可以简单地click在其上附加一个处理程序,所以当点击时我们用向量切换位图.在命中测试时,图像的行为与矢量不同 - 图像squares本质上是无法进行不对称测试的.虽然向量认为它的边缘位于其路径边界上 - 但是图像认为它的边界是它的整个边界框.解决方案是单击图像以使用图像下方的矢量路径实际点击测试点击点 - 如果它返回true,则执行释放.