Canvas 性能优化:脏矩形渲染
Author:zhoulujun Date:
改变画布中的某个图形,去更新画布,最简单的是清空画布,然后根据图形树将所有图形再绘制一遍。
这在图形较少的情况下是没什么问题的。但如果图形数量很多,那绘制起来可能就出现卡顿了。
我们可以用分层去解决,但是分层也是有代价的。
那么,有没有什么办法来优化一下?有,脏矩形渲染。
计算的开销与绘制的开销相差 2~3 个数量级
脏矩形渲染原理
在讲解之前,我们先明白几个概念。
脏矩形:改变某个图形的物理信息后,需要重新渲染的矩形区域,通常为目标图形的当前帧和下一帧组成的包围盒。
包围盒:包围图形的最小矩形。通常用作低成本的碰撞检测。因为矩形的碰撞检测的算法是简单高效的,而复杂图形的碰撞检测是复杂且低效的。
脏矩形渲染简单来说,就是计算被改变的目标图形两帧所产生的包围盒(脏矩形),将该区域清空,然后将和脏矩形发生相交的所有图形在这个区域内重绘。
对于前面移动红球的场景,具体逻辑为:
计算红球在当前帧和下一帧所形成的包围盒,这个包围盒就是脏矩形。
遍历绿球的物理信息,计算它们的包围盒,取出和脏矩形发生相交的绿球。
将脏矩形区域清空。
将脏矩形设置为裁剪区域,这样保证只能绘制在脏矩形中。
按顺序绘制绿球,最后绘制红球。按顺序是为了保证层级正确。
相比全部绘制,局部绘制能有效减少需要绘制的图形数量,减少对 GPU 绘制指令的调用,从而提高渲染性能。
这里还有个优化点,就是减少遍历的图形数量,可以使用《碰撞检测性能优化:四叉树碰撞检测 》来做优化
以前 ECharts 底层的 ZRender 为例来讲解:
根据图形前后变化,来计算出重绘区域,比如上图的区域,在飞书文档中会将整个移动的路径当做重绘区域。
如果有多个重绘区域,那么优先尝试将相交(包围盒)的重绘区进行合并,并且优先合并相交面积最大的重绘区。
如果合并完成后,当前剩余的重绘区数量大于5,则进一步进行合并,直到数量只剩5。
依次遍历这些重绘区域,先清除掉原有的内容,再进行绘制。
飞书文档多维表格没有做 Canvas 渲染分层,但对各种交互响应速度非常快,也是得益于底层渲染引擎对脏矩形渲染的支持,它的性能也是所有同类产品里面最好的。
除了上述的这些,还有在文档这边使用的一些优化手段,比如合并相同属性的图形绘制(线、矩形、文本等)、Canvas 分层等等,这些就不多做阐述了。
参考文章:
Canvas 性能优化:脏矩形渲染 https://cloud.tencent.com/developer/article/2197387
前端“油画设计师”——双缓存绘制与油画分层机制 https://www.cnblogs.com/powertoolsteam/p/15213573.html
浅谈 Canvas 渲染引擎设计 https://github.com/yinguangyao/blog/issues/84
转载本站文章《Canvas 性能优化:脏矩形渲染》,
请注明出处:https://www.zhoulujun.cn/html/webfront/visualization/comprehensive/9238.html