我们正在构建一个在浏览器中运行的CAD应用程序。
它基于Paper.js,这是一个非常简洁的画布库,允许您以编程方式操作向量。
问题所在
我目前遇到的主要问题是重绘周期性能。
重绘算法是“哑巴”(就提高性能的巧妙技巧而言),因此效率低下且渲染缓慢的场景图项目依赖于逐渐变慢的重绘周期。
随着绘制点数的累积,每个重绘周期都会变得越来越慢。
重绘方案非常简单:
问题是
在这种情况下,有没有任何渲染优化的课堂例子-假设我想停止实现脏矩形算法(只绘制发生变化的区域)
编辑:我已经尝试了手动现场光栅化,效果很好,我已经在下面发布了一个答案。
发布于 2014-12-29 18:18:10
这可以通过类似于Bitmap Caching的过程/技术中的光栅化来完成。
高节点数场景图的问题是渲染它们会导致渲染引擎发出叹息。浏览器必须遍历它们的节点并在画布上渲染它们的像素。
所以这里有一个很好的解决方案:
1.渲染位图,但隐藏下面的原始形状
解决方案是将矢量替换为图像,将其栅格化-仅在渲染时,但仍将原始形状保留在其图像副本之下,只有在不活动时(当前未被操纵)才处于隐藏状态。
在单击图像时-我们删除它们并切换原始形状的可见性。通过这种方式,不活动的形状被渲染为图像,活动的形状从它们的位图表示中释放出来,并充当矢量,可以自由地进行操作。当不活动时,他们只是坐在那里,他们的光栅副本在他们的顶部。
这允许引擎保留形状的矢量表示,但避免将它们渲染为矢量-相反,看起来与它们相似的图像会层叠在它们上面。
数以千计的路径命令本质上是由单个图像替换的-但只有在渲染时-原始路径实际上作为对象存在于场景图中,或者您正在使用的任何类型的DOM
2.分组栅格化
诀窍是在组中执行光栅化-将10-15个形状组合在一起,并将它们光栅化为单个图像。这将使栅格计数保持较低。在点击图像时-我们可以释放整个组,或者只释放被点击的项目。
3.在组上附加单击处理程序,以便在重新激活时恢复矢量副本
当光栅化一个组时,我们可以简单地在它上面附加一个click
处理程序,所以当单击它时,我们可以用矢量切换位图。在命中测试时,图像的行为与向量不同-图像本质上是squares
的,不能进行非对称的命中测试。当一个向量认为它的边在它的路径边界上时,一个图像认为它的边界是它的整个边界框。解决方案是,当点击图片时,用图片下方的向量路径测试点击点,如果返回true,则执行释放。
发布于 2014-05-29 21:46:12
有用的工具
My branch of paper.js可以提供帮助,但它可能不是最适合您的。
它使您能够防止paper.js每帧重绘所有内容(使用paper.view.persistence = 1;
)。
这样,您可以更好地控制要清除和应该重绘的内容:例如,当您移动形状时,可以清除该形状所在的区域(例如,使用本地canvas drawRect ),并在移动该区域后对其进行更新(使用path.needsUpdate();
)。
缺点
当形状相交时,问题就来了。如果要修改一个与另一个形状相交的形状,则必须同时更新这两个形状。如果第二个形状与第三个形状相交,则情况相同,依此类推。
所以你需要一个递归函数,并不难编码,但是如果有许多复杂的形状相交,那么它可能会很昂贵,所以在这种情况下你可能得不到性能。
(更新)位图缓存
正如Nicholas Kyriakides在following answer中所建议的,位图缓存是一个非常好的解决方案。
每个形状一个画布
另一种方法是在单独的画布上绘制每个形状(作为层工作)。这样,您就可以自由地分别清除和重新绘制每个形状。您可以分离未更改的视图(除用户正在处理的画布之外的所有画布)的onFrame事件。这应该更容易,但它会导致其他小问题,比如共享相同的项目视图参数(在缩放的情况下),而且对于许多形状(这意味着许多画布),它可能会很昂贵。
静态和动态画布
一种(可能)更好的方法是只有两个画布,一个用于静态形状,另一个用于活动形状。静态形状画布将包含所有形状(除了正在编辑的形状),并将在用户开始和停止编辑活动形状时重新绘制。当用户开始编辑形状时,它将从静态画布传输到动态画布,当用户停止编辑时,将以另一种方式传输。
https://stackoverflow.com/questions/23884074
复制相似问题