canvas教程

HTML5 Canvas性能分析与提升技巧(2)

字号+ 作者:H5之家 来源:H5之家 2016-01-16 14:47 我要评论( )

// canvas, context are defined function render() { drawMario(context); requestAnimationFrame(render); } 预渲染的情况: var m_canvas = document.createElement('canvas'); m_canvas.width = 64; m_canvas.h

// canvas, context are defined 
function render() { 
  drawMario(context); 
  requestAnimationFrame(render); 

预渲染的情况:

var m_canvas = document.createElement('canvas'); 
m_canvas.width = 64; 
m_canvas.height = 64; 
var m_context = m_canvas.getContext(‘2d’); 
drawMario(m_context); 
function render() { 
  context.drawImage(m_canvas, 0, 0); 
  requestAnimationFrame(render); 

关于requestAnimationFrame的使用方法将在后续部分做详细的讲述。下面的图标说明了显示了利用预渲染技术所带来的性能改善情况。(来自于jsperf):


当渲染操作(例如上例中的drawmario)开销很大时该方法将非常有效。其中很耗资源的文本渲染操作就是一个很好的例子。从下表你可以看到利用预渲染操作所带来的强烈的性能提升。(来自于jsperf):


然而,观察上边的例子我们可以看出松散的预渲染(pre-renderde loose)性能很差。当使用预渲染的方法时,我们要确保临时的canvas恰好适应你准备渲染的图片的大小,否则过大的canvas会导致我们获取的性 能提升被将一个较大的画布复制到另外一个画布的操作带来的性能损失所抵消掉。

上述的测试用例中紧凑的canvas相当的小:

can2.width = 100; 
can2.height = 40; 
如下宽松的canvas将导致糟糕的性能:

can3.width = 300; 
can3.height = 100; 


2.BATCH CANVAS CALLS TOGETHER

因为绘图是一个代价昂贵的操作,因此,用一个长的指令集载入将绘图状态机载入,然后再一股脑的全部写入到video缓冲区。这样会会更佳有效率。

例如,当需要画对条线条时先创建一条包含所有线条的路经然后用一个draw调用将比分别单独的画每一条线条要高效的多:

or (var i = 0; i < points.length - 1; i++) { 
  var p1 = points[i]; 
  var p2 = points[i+1]; 
  context.beginPath(); 
  context.moveTo(p1.x, p1.y); 
  context.lineTo(p2.x, p2.y); 
  context.stroke(); 

通过绘制一个包含多条线条的路径我们可以获得更好的性能:

ontext.beginPath(); 
for (var i = 0; i < points.length - 1; i++) { 
  var p1 = points[i]; 
  var p2 = points[i+1]; 
  context.moveTo(p1.x, p1.y); 
  context.lineTo(p2.x, p2.y); 

context.stroke(); 
这个方法也适用于HTML5 canvas。比如,当我们画一条复杂的路径时,将所有的点放到路径中会比分别单独的绘制各个部分要高效的多(jsperf):


然而,需要注意的是,对于canvas来说存在一个重要的例外情况:若欲绘制的对象的部件中含有小的边界框(例如,垂直的线条或者水平的线条),那么单独的渲染这些线条或许会更加有效(jsperf):


3.AVOID UNNECESSARY CANVAS STATE CHANGES

HTML5 canvas元素是在一个状态机之上实现的。状态机可以跟踪诸如fill、stroke-style以及组成当前路径的previous points等等。在试图优化绘图性能时,我们往往将注意力只放在图形渲染上。实际上,操纵状态机也会导致性能上的开销。

例如,如果你使用多种填充色来渲染一个场景,按照不同的颜色分别渲染要比通过canvas上的布局来进行渲染要更加节省资源。为了渲染一副条纹的图案,你可以这样渲染:用一种颜色渲染一条线条,然后改变颜色,渲染下一条线条,如此反复:

for (var i = 0; i < STRIPES; i++) { 
  context.fillStyle = (i % 2 ? COLOR1 : COLOR2); 
  context.fillRect(i * GAP, 0, GAP, 480); 

也可以先用一种颜色渲染所有的偶数线条再用另外一种染色渲染所有的基数线条:

context.fillStyle = COLOR1; 
for (var i = 0; i < STRIPES/2; i++) { 
  context.fillRect((i*2) * GAP, 0, GAP, 480); 

context.fillStyle = COLOR2; 
for (var i = 0; i < STRIPES/2; i++) { 
  context.fillRect((i*2+1) * GAP, 0, GAP, 480); 

下面的性能测试用例分别用上边两种方法绘制了一副交错的细条纹图案(jsperf):


正如我们预期的,交错改变状态的方法要慢的多,原因是变化状态机是有额外开销的。


4.RENDER SCREEN DIFFERENCES ONLY, NOT THE WHOLE  NEW STATE

这个很容易理解,在屏幕上绘制较少的东西要比绘制大量的东西节省资源。重绘时如果只有少量的差异你可以通过仅仅重绘差异部分来获得显著的性能提升。换句话说,不要在重绘前清除整个画布。:

context.fillRect(0, 0, canvas.width, canvas.height); 
跟踪已绘制部分的边界框,仅仅清理这个边界之内的东西:

context.fillRect(last.x, last.y, last.width, last.height); 
下面的测试用例说明了这一点。该测试用例中绘制了一个穿过屏幕的白点(jsperf):


如果您对计算机图形学比较熟悉,你或许应该知道这项技术也叫做“redraw technique”,这项技术会保存前一个渲染操作的边界框,下一次绘制前仅仅清理这一部分的内容。

这项技术也适用于基于像素的渲染环境。这篇名为JavaScript NIntendo emulator tallk的文章说明了这一点。


5.USE MUTIPLE LAYERED CANVASES FOR COMPLEX SCENES

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • html5canvas核心技术图形、动画与游戏开发源码

    html5canvas核心技术图形、动画与游戏开发源码

    2017-05-02 17:42

  • 打印html5中Canvas的方法

    打印html5中Canvas的方法

    2017-05-01 15:03

  • HTML5+Canvas调用手机拍照功能实现图片上传(下)

    HTML5+Canvas调用手机拍照功能实现图片上传(下)

    2017-04-30 17:00

  • HTML5新特性详解(三)

    HTML5新特性详解(三)

    2017-04-30 16:03

网友点评