• home > webfront > visualization > comprehensive >

    Canvas 性能优化:脏矩形渲染

    Author:zhoulujun Date:

    改变画布中的某个图形,去更新画布,最简单的是清空画布,然后根据图形树将所有图形再绘制一遍。这在图形较少的情况下是没什么问题的。但如

    改变画布中的某个图形,去更新画布,最简单的是清空画布,然后根据图形树将所有图形再绘制一遍。

    这在图形较少的情况下是没什么问题的。但如果图形数量很多,那绘制起来可能就出现卡顿了。

    我们可以用分层去解决,但是分层也是有代价的。

    分层渲染解决

    那么,有没有什么办法来优化一下?有,脏矩形渲染。

    计算的开销与绘制的开销相差 2~3 个数量级


    脏矩形渲染原理

    在讲解之前,我们先明白几个概念。

    1. 脏矩形:改变某个图形的物理信息后,需要重新渲染的矩形区域,通常为目标图形的当前帧和下一帧组成的包围盒。

    2. 包围盒:包围图形的最小矩形。通常用作低成本的碰撞检测。因为矩形的碰撞检测的算法是简单高效的,而复杂图形的碰撞检测是复杂且低效的。

    d56a60f570141926a2c707d70ea92fcfea9663.png

    脏矩形渲染简单来说,就是计算被改变的目标图形两帧所产生的包围盒(脏矩形),将该区域清空,然后将和脏矩形发生相交的所有图形在这个区域内重绘。

    对于前面移动红球的场景,具体逻辑为:

    1. 计算红球在当前帧和下一帧所形成的包围盒,这个包围盒就是脏矩形。

    2. 遍历绿球的物理信息,计算它们的包围盒,取出和脏矩形发生相交的绿球。

    3. 将脏矩形区域清空。

    4. 将脏矩形设置为裁剪区域,这样保证只能绘制在脏矩形中。

    5. 按顺序绘制绿球,最后绘制红球。按顺序是为了保证层级正确。

    相比全部绘制,局部绘制能有效减少需要绘制的图形数量,减少对 GPU 绘制指令的调用,从而提高渲染性能。

    这里还有个优化点,就是减少遍历的图形数量,可以使用《碰撞检测性能优化:四叉树碰撞检测 》来做优化

    以前 ECharts 底层的 ZRender 为例来讲解:

    1. 根据图形前后变化,来计算出重绘区域,比如上图的区域,在飞书文档中会将整个移动的路径当做重绘区域。

    2. 如果有多个重绘区域,那么优先尝试将相交(包围盒)的重绘区进行合并,并且优先合并相交面积最大的重绘区。

    3. 如果合并完成后,当前剩余的重绘区数量大于5,则进一步进行合并,直到数量只剩5。

    4. 依次遍历这些重绘区域,先清除掉原有的内容,再进行绘制。

    飞书文档多维表格没有做 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