HTML5のキャンバスには、いくつかの方法でパフォーマンスを向上させます

簡単な紹介

HTML5のキャンバスは、今では広くサポートされている2DのWebになってきたアップル(アップル)の実験に由来高速モードグラフィックス(2次元 MODEグラフィック即時負荷の基準)。多くの開発者は現在、マルチメディアプロジェクトの数だけでなく、目を引く視覚ゲームを達成するためにそれを使用します。しかし、我々が構築したアプリケーションの複雑で、私たちは、必然的に、いわゆるパフォーマンスの問題が発生します。

キャンバスのパフォーマンスがすでに存在して最適化することが、ない記事がこれらの方法およびシステムを整理しないだろう多くの方法が分析されています。本稿の目的は、理解するのがより簡単で、開発者を統合ダイジェスト、リソースを吸収するように、これらのメソッドを整理することです。この記事でカバーされ、基本的な最適化手法は、すべての環境のコンピュータグラフィックス(コンピュータグラフィックス環境)、およびキャンバスを最適化する具体的な方法にも適用可能です。達成することができるキャンバスで特定の更新方法は、キャンバスの最適化のために異なります。ブラウザの開発者は時にキャンバスのGPUアクセラレーションを実現する場合、特に、我々はいくつかの最適化を探る、我々は特定の場所にラベルを付けたこれらのケースを特に有効思えないかもしれません。

この記事はHTML5のキャンバスの使用の焦点を議論することではないことに注意してください。あなたはHTML5ロックスサイトキャンバス具体的な使用方法をお知りになりたい場合はで見つけることができますキャンバスに関連する記事以下のようなHTML5の章へのダイブ  やMDNチュートリアル

パフォーマンステスト

急速に変化するキャンバスHTML5に対応するために、JSPerfjsperf.com)テストでは、我々は、テキストで記述されているすべてのメソッドは現在も有効であることを証明しました。JSPerfは、Web開発者は、JavaScriptのパフォーマンスのテストケースを書くためにこのプログラムを使用することができ、非常に便利なWebアプリケーションです。各テストケースの問題(例えば、キャンバスをクリア)に到達するためにあなたの試みの特定の態様の結果のみが、このような各テストケースは、同じ結果を達成するために多くの異なる方法を含んでいます。できるだけ多くのランの各メソッドは、秒あたりの反復回数に統計を与えなかった短い時間のために重要なJSPerfがあります。平均値は、より高い性能を獲得します。

視聴者がブラウザでJSPerfパフォーマンス・テスト・ページを開き、そして標準化されたテスト結果はに保存されているにJSPerfをすることができますすることができますBrowserscopebroserscope.orgで)。この資料に記載の最適化技術がJSPerfの結果にバックアップされているので、あなたは、再実行し、対応する方法も有効であるかどうかを判断するために、最新の情報を表示することができますので。私は小さな書かれているヘルパーアプリケーションヘルパーapplicatinを記事全体に埋め込まチャートへのテストの結果に)。

特定のブラウザのバージョンと、この記事では、パフォーマンス・テストの結果は、非常に重要な関係を有しています。我々はより重要であるかについてのオペレーティングシステムとブラウザを実行するかわからないので、あなたはこれらのテストを行うときに加速HTML5のキャンバスは、ハードウェアだったかどうかを知ることはできません。ChromeのHTML5のキャンバスは、ハードウェアアクセラレーションであるかどうかを確認するために、GPUコマンド:あなたは、Chromeブラウザのアドレスバーについて使用することができます。

 

オフスクリーンキャンバスに1.PRE-RENDER

 私たちはしばしば、連続する複数のフレームでオブジェクトを再描画すると似たような状況を記述するために、ゲームに遭遇します。この場合には、あなたがオブジェクトのほとんどの事前レンダリングされたシーンで大幅なパフォーマンス向上を得ることができます。すなわち、一つ以上の一時的なキャンバスの一時的なプリレンダリングされた画像をレンダリングして画面上に表示されず、これらの不可視キャンバス画像としてキャンバスに可視化。より身近な友人はすべてを知っている必要があり、コンピュータグラフィックスの場合、この技術も呼ばれているディスプレイリストを実行します

たとえば、あなたが毎秒60のフレームで動作してマリオを再描画するとします。あなたは、どちらかのフレームは、アニメーションを実行する前に、各もできるプリレンダリングマリオの帽子、口ひげ、および「M」を再描画することができます。

プリレンダリングのいかなる場合ありません。

[ジャバスクリプト]   ビュー無地 コピー
  1. //キャンバス、コンテキストが定義されています  
  2. 機能 レンダリング(){  
  3.   drawMario(コンテキスト)。  
  4.   requestAnimationFrameの(レンダリング)。  
  5. }  

前の状況は、レンダリングされました:

[ジャバスクリプト]   ビュー無地 コピー
  1. VAR  m_canvas =のdocument.createElement('キャンバス' );  
  2. m_canvas.width = 64;  
  3. m_canvas.height = 64;  
  4. VAR  m_context = m_canvas.getContext( '2D');  
  5. drawMario(m_context)。  
  6. 機能 レンダリング(){  
  7.   context.drawImage(m_canvas、0、0);  
  8.   requestAnimationFrameの(レンダリング)。  
  9. }  

後続のセクションで説明した詳細の使用にrequestAnimationFrameの。以下は、アイコンは、プリレンダリング技術の使用は、パフォーマンスの向上をもたらしますそれぞれ示します。(からJSPerf):

操作(例えばdrawmario上記の例)方法は非常に有効である大きなオーバヘッドをレンダリングするとき。これでテキストが非常にリソース集中型のレンダリング操作が良い例です。下の表からは改善がもたらしたプリレンダリング強い業績の使用を見ることができます。(からJSPerf):

しかし、例えば私たちは、上緩いプリレンダリング(前renderde緩い)パフォーマンスの低下を観察見ることができます。プリレンダリングを使用するとき、私たちは正確にあなたの写真のサイズに合わせ、または大きすぎるキャンバスは、性能向上のために私たちをリードするレンダリングする準備ができて、一時的なキャンバスは別の動作キャンバスに大きなキャンバスをコピーすることであることを確認しますオフセット性能の損失をもたらします。

上記試験における小さなコンパクト比較的キャンバス。

[ジャバスクリプト]   ビュー無地 コピー
  1. can2.width = 100;  
  2. can2.height = 40;  

ルーズキャンバスは、パフォーマンスの低下になります。

[ジャバスクリプト]   ビュー無地 コピー
  1. can3.width = 300。  
  2. can3.height = 100;  

 

2.BATCH CANVASはTOGETHER CALLS

図面は、図面をロード状態マシンをロードされた命令の長いセットで、従って、高価な操作であり、次いで、ビデオバッファに落ちるため、すべてに書き込まれます。これは、優れた効率となります。

たとえば、すべての行のパスを含む行の絵を作成し、個別にすべての線を引くよりもドローでコールする必要があるときにはるかに効率的です。

[ジャバスクリプト]   ビュー無地 コピー
  1. または(VAR  i = 0; iはpoints.length < - 1; iが++){  
  2.   VaRの P1 =点[i]は、  
  3.   VaRの p2は=点[I + 1]。  
  4.   context.beginPath();  
  5.   context.moveTo(p1.x、p1.y)。  
  6.   context.lineTo(p2.x、p2.y)。  
  7.   context.stroke();  
  8. }  

複数のラインを備えたパスを描画することによって、私たちはより良いパフォーマンスを得ることができます:

[ジャバスクリプト]   ビュー無地 コピー
  1. ontext.beginPath();  
  2. ため (VAR  i = 0; iはpoints.length < - 1; iは++){  
  3.   VaRの P1 =点[i]は、  
  4.   VaRの p2は=点[I + 1]。  
  5.   context.moveTo(p1.x、p1.y)。  
  6.   context.lineTo(p2.x、p2.y)。  
  7. }  
  8. context.stroke();  

このアプローチはまた、HTML5のキャンバスに適用されます。私たちは、複雑なパスを描画するとき、例えば、すべてのポイントのパスにはるかに効率的(個別に各パーツのレンダリングよりなりJSPerfを):

ノートは、しかし、キャンバスに重要な例外があることである。Ruoyu部材描画オブジェクトの境界ボックスが小さい(例えば、垂直線または水平線)を含有し、線が描画分離することができますそれは、より効果的になります(JSPerf):

 

3.AVOID UNNECESSARY CANVAS状態の変化

HTML5のcanvas要素は、ステートマシンの上に実装されています。ステートマシンは、フィル、ストロークスタイルと前の点の電流路の組成などの情報を追跡することができます。グラフィックス性能を最適化しようとすると、我々は唯一のグラフィックスレンダリングに集中する傾向があります。実際には、ステート・マシンを操作すると、パフォーマンスのオーバーヘッドにつながることができます。

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

[javascript]  view plain copy
  1. for (var i = 0; i < STRIPES; i++) {  
  2.   context.fillStyle = (i % 2 ? COLOR1 : COLOR2);  
  3.   context.fillRect(i * GAP, 0, GAP, 480);  
  4. }  

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

[javascript]  view plain copy
  1. context.fillStyle = COLOR1;  
  2. for (var i = 0; i < STRIPES/2; i++) {  
  3.   context.fillRect((i*2) * GAP, 0, GAP, 480);  
  4. }  
  5. context.fillStyle = COLOR2;  
  6. for (var i = 0; i < STRIPES/2; i++) {  
  7.   context.fillRect((i*2+1) * GAP, 0, GAP, 480);  
  8. }  

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

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

 

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

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

[javascript]  view plain copy
  1. context.fillRect(0, 0, canvas.width, canvas.height);  

跟踪已绘制部分的边界框,仅仅清理这个边界之内的东西:

[javascript]  view plain copy
  1. 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

我们前边提到过,绘制一副较大的图片代价是很高昂的因此我们应尽可能的避免。除了前边讲到的利用另外得不可见的canvas进行预渲染外,我们也可以叠在 一起的多层canvas。图哦你的过利用前景的透明度,我们可以在渲染时依靠GPU整合不同的alpha值。你可以像如下这么设置,两个绝对定位的 canvas一个在另一个的上边:

[javascript]  view plain copy
  1. <canvas id="bg" width="640" height="480" style="position: absolute; z-index: 0">  
  2. </canvas>  
  3. <canvas id="fg" width="640" height="480" style="position: absolute; z-index: 1">  
  4. </canvas>  

相对于仅仅有一个canvas的情况来讲,这个方法的优势在于,当我们需要绘制或者清理前景canvas时,我们不需要每次都修改背景 canvas。如果你的游戏或者多媒体应用可以分成前景和背景这样的情况,那么请考虑分贝渲染前景和背景来获取显著的性能提升。下面的图表比较了只有一个 canvas的情况和有前景背景两个canvas而你只需要清理和重绘前景的情况(jsperf):

你可以用相较慢的速度(相对于前景)来渲染背景,这样便可利用人眼的一些视觉特性达到一定程度的立体感,这样会更吸引用户的眼球。比如,你可以在每一帧中渲染前景而仅仅每N帧才渲染背景。

注意,这个方法也可以推广到包含更多canvas曾的复合canvas。如果你的应用利用更多的曾会运行的更好时请利用这种方法。

 

6.AVOID SHADOWBLUR

跟其他很多绘图环境一样,HTML5 canvas允许开发者对绘图基元使用阴影效果,然而,这项操作是相当耗费资源的。

[javascript]  view plain copy
  1. context.shadowOffsetX = 5;  
  2. context.shadowOffsetY = 5;  
  3. context.shadowBlur = 4;  
  4. context.shadowColor = 'rgba(255, 0, 0, 0.5)';  
  5. context.fillRect(20, 20, 150, 100);  

下面的测试显示了绘制同一场景使用何不使用阴影效果所带来的显著的性能差异(jsperf):

 

7.KNOW VARIOUS WAYS TO CLEAR THE CANVAS

因为HTML5 canvas 是一种即时模式immediate mode)的绘图范式(drawing paradigm),因此场景在每一帧都必需重绘。正因为此,清楚canvas的操作对于 HTML5 应用或者游戏来说有着根本的重要性。

正如在 避免 canvas 状态变化的一节中提到的,清楚整个canvas的操作往往是不可取的。如果你必须这样做的话有两种方法可供选择:调用

[javascript]  view plain copy
  1. context.clearRect(0, 0, width, height)  

或者使用 canvas特定的一个技巧

[javascript]  view plain copy
  1. canvas.width = canvas.width  

在书写本文的时候,cleaRect方法普遍优越于重置canvas宽度的方法。但是,在某些情况下,在Chrome14中使用重置canvas宽度的技巧要比clearRect方法快很多(jsperf):

请谨慎使用这一技巧,因为它很大程度上依赖于底层的canvas实现,因此很容易发生变化,欲了解更多信息请参见 Simon Sarris 的关于清除画布的文章

 

8.AVOID FLOATING POINT COORDINATES

HTML5 canvas 支持子像素渲染(sub-pixel rendering),而且没有办法关闭这一功能。如果你绘制非整数坐标他会自动使用抗锯齿失真以使边缘平滑。以下是相应的视觉效果(参见Seb Lee-Delisle的关于子像素画布性能的文章

如果平滑的精灵并非您期望的效果,那么使用 Math.floor方法或者Math.round方法将你的浮点坐标转换成整数坐标将大大提高运行速度(jsperf):

为使浮点坐标抓换为整数坐标你可以使用许多聪明的技巧,其中性能最优越的方法莫过于将数值加0.5然后对所得结果进行移位运算以消除小数部分。

[javascript]  view plain copy
  1. // With a bitwise or.  
  2. rounded = (0.5 + somenum) | 0;  
  3. // A double bitwise not.  
  4. rounded = ~~ (0.5 + somenum);  
  5. // Finally, a left bitwise shift.  
  6. rounded = (0.5 + somenum) << 0;  

两种方法性能对比如下(jsperf):

9.OPTIMIZE YOUR ANIMATIONS WITH ‘REQUESTANIMATIONFRAME’

相对较新的 requeatAnimationFrame API是在浏览器中实现交互式应用的推荐标准。与传统的以固定频率命令浏览器进行渲染不同,该方法可以更友善的对待浏览器,它会在浏览器可用的时候使其来 渲染。这样带来的另外一个好处是当页面不可见的时候,它会很聪明的停止渲染。

requestAnimationFrame调用的目标是以60帧每秒的速度来调用,但是他并不能保证做到。所以你要跟踪从上一次调用导线在共花了多长时间。这看起来可能如下所示:

[javascript]  view plain copy
  1. var x = 100;  
  2. var y = 100;  
  3. var lastRender = new Date();  
  4. function render() {  
  5.   var delta = new Date() - lastRender;  
  6.   x += delta;  
  7.   y += delta;  
  8.   context.fillRect(x, y, W, H);  
  9.   requestAnimationFrame(render);  
  10. }  
  11. render();  

注意requestAnimationFrame不仅仅适用于canvas 还适用于诸如WebGL的渲染技术。

在书写本文时,这个API仅仅适用于Chrome,Safari以及Firefox,所以你应该使用这一代码片段

MOST MOBILE CANVAS IMPLEMENTATION ARE SLOW

让我们来讨论一下移动平台。不幸的是在写这篇文章的时候,只有IOS 5.0beta 上运行的Safari1.5拥有GPU加速的移动平台canvas实现。如果没有GPU加速,移动平台的浏览器一般没有足够强大的CPU来处理基于 canvas的应用。上述的JSperf测试用例在移动平台的运行结果要比桌面型平台的结果糟糕很多。这极大的限制了跨设备类应用的成功运行。

CONCLUSION

j简要的讲,本文较全面的描述了各种十分有用优化方法以帮助开发者开发住性能优越的基于HTML5 canvas的项目。你已经学会了一些新的东西,赶紧去优化你那令人敬畏的创造吧!如果你还没有创建过一个应用或者游戏,那么请到Chrome Experiment 和Creative JS看看吧,这里能够激发你的灵感。

 

REFFERENCE

 

(オリジナルリンク:http://www.html5rocks.com/en/tutorials/canvas/performance/

ます。https://my.oschina.net/zhepama/blog/265034で再現

おすすめ

転載: blog.csdn.net/weixin_34292959/article/details/91927353