TAT.Cson canvas 动画优化小议
In 未分类 on 2013年12月01日 by view: 14,280
8

在使用 canvas 制作动画时,最传统的方式是对 canvas update -> clear -> draw 的过程

e1

但是对于同一个 view 里的不同的动画,需要的更新频率可能并不一样,所以对于不同类型的动画,我们可以放在不同的 canvas 层上进行渲染,使用多层 canvas 分别渲染取代单个 canvas

e2

 

这样的好处是对不同更新频率的动画,可以分别以他们各自的频率进行 update -> clear -> draw 的操作,并不会因为一个高频率的动画而导致所有动画频繁地刷新。另一个好处是各个层之间相对独立,刷新和绘制不会对其他层造成影响。

 

对动画进行分层之后,我们发现对于单个层我们其实也没必要每帧清空该层的整个 canvas 并重新绘制,我们需要 clear 和 draw 的其实仅仅是 canvas 里 “变更了的部分”

一种比较简单的方法是尽量缩小清除与绘制的整体区域:

e5

 

我们圈出所有变化元素所形成的最大矩形区域,clear 掉该区域部分,然后仅仅对变化元素进行 redraw。

这样的优点是仅仅对所有变化面积范围内的元素进行清楚与绘制操作,减少渲染的面积。

 

但是,上面的方案还是会对一些没必要进行清除的 canvas 区域进行清除操作,例如上面 clear area 里中间的空白部分,因此,更极致的优化方式是记录每一个元素移动造成的 “脏矩形” 区域,每次只清除所有 “脏矩形” 区域并绘制改变的元素,最大化减少渲染面积。

e10

 

 

然而,对于方案 3,还存在一些在实现上需要考虑的问题,例如如何保存运动元素的脏矩形列表,对于重叠元素如何处理等等,具体的流程可以参考下图:

 

e13

 

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2013/12/canvas-animation-optimized-discussion/

  1. 大笨猫同学 2014 年 8 月 5 日

    我觉得除非是做事件驱动的 UI,用脏矩形的话可能得不偿失,也许可以试试 tile。

  2. 沉默的老虎 2014 年 1 月 10 日

    我也同意楼上两位的观点,计算脏矩形需要消耗的 CPU 资源估计不小,还不如整个重绘。

    我所在的项目做了一个在线的白板的页面。所有的笔画都是以一个对象记录的。
    用户可以选中某一个笔画然后拖动。
    开始我也觉得我每次重绘的时候计算出需要重绘的部分就好,结果是,我发现由于笔画间互相有重叠的部分,要计算出哪些笔画需要重绘就要用碰撞算法算很久。

    我试了一下,Chrome 里面,用户手动绘制的笔画,一秒钟内可以绘制 500 个,基本上来说性能还是不错的。

    楼主说的将不同刷新频率的内容放入不同的层,这个我们也用到了,效果确实不错。

  3. TAT.Minren

    TAT.Minren 2013 年 12 月 2 日

    把脏矩形拆分的过细没有意义,性能反而更差。因为要调用多次 drawImage,得不偿失。

    • TAT.Cson

      TAT.Cson 2013 年 12 月 2 日

      drawImage 的话如果不拆分的话会调用得更多哦 因为如果不使用脏矩形的话,每个 sprite(不管是否有改变位置)都需要使用 drawImage 重新绘制

  4. TAT.Johnny

    TAT.Johnny 2013 年 12 月 2 日

    分层后其实没必要算脏矩形清除, 实际上整层的清除性能更高, 因为本身计算脏矩形是有 CPU 时间的

    另外怎么就突然方案 3 了?..

    • TAT.Minren

      TAT.Minren 2013 年 12 月 2 日

      因为一下到了 3013 呀

    • TAT.Cson

      TAT.Cson 2013 年 12 月 2 日

      脏矩形清除的话主要是为了减少对没有改变的元素的重复绘制吧 因为整层清除的话所有元素都需要重新绘制

      计算脏矩形确实是需要 cpu 时间 所以我觉得这里还是在绘制和计算之间取舍哈 根据不同情况选择是否使用脏矩形

      对于脏矩形的计算 主要耗损还是在检测脏矩形和其他元素的重叠里吧 这个我觉得可以加一个优化,就是对矩形所属圆周范围外的矩形就不用进行重叠的检测了

    • TAT.Cson

      TAT.Cson 2013 年 12 月 2 日

      方案 3 这里是指最后一个哈

发表评论