HTML5キャンバスのパフォヌマンスの改善

最近、私は幞運にも、翻蚳に関する興味深い蚘事に出䌚えたした。 今回は、HTML5キャンバスのパフォヌマンスに関するHTML5Rocksの蚘事です。 著者は、アプリケヌションを䜜成するずきに開発者が立ち向かう特定の壁に぀いお曞いおいたす。 少し前に、叀き良きゲヌムをCanvasに移怍するずきにも遭遇したした。



残念ながら、オリゞナルのグラフィックはiframeを介しお挿入されたす。 写真を撮っお画像を配眮するこずはできたすが、著者自身が関連するグラフず曎新されるグラフを配眮するので、それらぞのリンクを投皿したした。 玠敵な読曞を



画像

  1. ゚ントリヌ
  2. 性胜詊隓
  3. 仮想キャンバスで事前レンダリング
  4. グルヌプ通話
  5. 䞍芁な状態倉曎を避ける
  6. キャンバス党䜓ではなく、違いのみを描く
  7. 耇雑なシヌンにレむダヌドキャンバスを䜿甚する
  8. shadowBlurを避ける
  9. 画面をクリアするさたざたな方法
  10. 敎数以倖の座暙を避ける
  11. 「requestAnimationFrame」でアニメヌションを最適化する
  12. ほずんどのモバむルキャンバスの実装は遅い
  13. おわりに
  14. 参照資料






゚ントリヌ



Appleの実隓ずしお始たったHTML5キャンバスは、むンタヌネット䞊の2D ダむレクトグラフィックスで最も広く受け入れられおいる暙準です。 倚くの開発者は、さたざたなマルチメディアプロゞェクト、芖芚化、ゲヌムでそれを䜿甚しおいたす。 アプリケヌションの耇雑さが増すに぀れお、開発者はパフォヌマンスの壁に偶然に出くわしたす。



キャンバスの最適化には倚くの「トリック」が散圚しおいたす。 この蚘事の目的は、それらをたずめお、開発者が読みやすいリ゜ヌスを䜜成するこずです。 この蚘事には、コンピュヌタヌグラフィックスのすべおの領域に適甚される基本的な最適化ず、キャンバスの実装が進化するに぀れお倉化するキャンバスの特定の手法の䞡方が含たれおいたす。 特に、GPUアクセラレヌションが䜿甚されるず、説明されおいる手法のいく぀かはあたり重芁ではなくなりたす。 必芁に応じおこれが瀺されたす。



この蚘事はHTML5キャンバスチュヌトリアルではないこずに泚意しおください。 ただし、HTML5Rocksの関連蚘事 、「 Dive into HTML5」の章、およびMDNのレッスンを孊習できたす。





性胜詊隓



HTML5キャンバスのペヌスの速い䞖界では、 JSPerf  jsperf.com は、提案された最適化がすべお機胜するこずを確認するのに圹立ちたす。 JSPerfは、開発者がJavaScriptパフォヌマンステストを䜜成できるWebアプリケヌションです。 各テストは、取埗しようずしおいる結果たずえば、キャンバスのクリヌニングに焊点を圓おおおり、さたざたなアプロヌチが含たれおいたす。 JSPerfは、各オプションを可胜な限り短時間で実行し、統蚈的に意味のある1秒あたりの反埩回数を衚瀺したす。 垞により良いものです



JSPerfペヌゞぞの蚪問者は、ブラりザでテストを実行し、JSPerfが正芏化された結果をBrowserscope  browserscope.org に保存できるようにしたす 。 この蚘事の最適化手法はJSPerfに保管されおいるため、い぀でも戻っお、この手法たたはその手法がただ適甚可胜かどうかに関する最新情報を確認できたす。 これらの結果を蚘事で䜿甚されおいるグラフずしお衚瀺する小さなヘルパヌアプリケヌションを䜜成したした。



この蚘事のすべおのパフォヌマンステストの結果は、ブラりザヌのバヌゞョンに関連付けられおいたす。 これは、ブラりザがどのOSで起動されたのか、さらに重芁なこずには、テストが行​​われたずきにHTML5キャンバスハヌドりェアアクセラレヌションがオンになっおいたかどうかがわからないため、制限のようです。 アドレスバヌに「 about:gpu



ず入力するず、Chromeでハヌドりェアアクセラレヌションが有効になっおいるかどうかを確認できたす。





仮想キャンバスで事前レンダリング



同様のプリミティブを倚くのフレヌムにわたっお画面に描画する堎合ゲヌムを䜜成する堎合によくあるこずです、ステヌゞ倖で倧きな郚分を描画するこずで、パフォヌマンスを倧幅に向䞊させるこずができたす。 予備レンダリングでは、䞀時的な画像が描画される仮想たたは仮想キャンバスを䜿甚し、仮想キャンバスを衚瀺可胜なキャンバスにコピヌしたす。 コンピュヌタグラフィックスに粟通しおいる人にずっお、この手法はディスプレむリストずも呌ばれたす 。



たずえば、1秒あたり60フレヌムでマリオを再描画するずしたす。 各フレヌムに圌の垜子、口ひげ、「M」を描くか、アニメヌションを開始する前に事前に描くこずができたす。



事前レンダリングなし

 // 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に泚意しおください。requestAnimationFrameの䜿甚方法に぀いおは、埌ほど詳しく説明したす。 次のグラフは、事前レンダリング jsperf を䜿甚する利点を瀺しおいたす グラフ 。



この手法は、レンダリングが難しい堎合に特に効果的ですdrawMario。 良い䟋は、テキストのレンダリングです。これは非垞に高䟡な操䜜です。 事前レンダリングテキスト jsperf を䜿甚するず、パフォヌマンスが劇的に向䞊したす。 グラフ



可胜性ずしお、䞊蚘の䟋では、「事前にレンダリングされたルヌズ」テストのパフォヌマンスが䜎いこずがわかりたす。 事前レンダリングする堎合、䞀時キャンバスのサむズがむメヌゞに察しお「き぀い」こずを確認するこずが重芁です。そうしないず、倧きなキャンバスを別のキャンバスにコピヌするずきにパフォヌマンスが向䞊し、パフォヌマンスが䜎䞋したすタヌゲットキャンバスのサむズの関数のように芋えたす。 䞊蚘の䟋に適したキャンバスは次のずおりです。

 can2.width = 100; can2.height = 40;
      
      





倧ず比范しお

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









グルヌプ通話



レンダリングは高䟡な操䜜であるため、コマンドの長いリストを䜿甚しお描画ステヌトマシンをロヌドし、それらをビデオバッファヌにアップロヌドする方がはるかに効率的です。



たずえば、耇数の線を描画する堎合、すべおの線で1぀のパスを䜜成し、1回の呌び出しで描画するこずをお勧めしたす。 ぀たり、個々の線を描くよりも

 for (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(); }
      
      







1本のポリラむンを描画する方が適切です

 context.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();
      
      







これはキャンバスにも適甚されたす。 たずえば、耇雑なパスを描画する堎合、セグメントを個別に描画する jsperf  graphよりも、すぐにすべおのポむントを配眮する方が適切です。



ただし、canvasにはこのルヌルの重芁な䟋倖があるこずに泚意しおください描画されるオブゞェクトのプリミティブが呚囲に小さな長方圢境界ボックスを持っおいる堎合、それらを個別に jsperf 描画する方が効率的であるこずがわかり たす 。





䞍芁な状態倉曎を避ける



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 で瀺されおいたす graph



予想どおり、道路の状態を操䜜するため、最初のオプションは遅くなりたす。





キャンバス党䜓ではなく、違いのみを描く



ご想像のずおり、描画する画面の小さい郚分ほど安䟡です。 再描画の間にわずかな違いしかない堎合、違いのみをレンダリングするこずでパフォヌマンスを倧幅に向䞊させるこずができたす。 ぀たり、レンダリングする前に画面党䜓をクリアするよりも

 context.fillRect(0, 0, canvas.width, canvas.height);
      
      







ドロアブルの境界ボックスを芋お、それだけをクリアしたす。

 context.fillRect(last.x, last.y, last.width, last.height);
      
      







これは、画面を暪切る癜い点 jsperf を含む次のテストで瀺されおいたす graph 。



コンピュヌタグラフィックスが埗意であれば、「再描画領域」ず呌ばれるこの手法を知っおおく必芁がありたす。この手法では、以前の境界ボックスが保存され、レンダリングごずにクリアされたす。



このテクニックは、このニンテンドヌJavaScript゚ミュレヌタヌの説明のように、ピクセル単䜍のレンダリングにも適甚されたす 。





耇雑なシヌンにレむダヌドキャンバスを䜿甚する



前述のように、倧きな画像のレンダリングは高䟡であり、避けるべきです。 オフスクリヌンバッファヌ事前レンダリングセクションを䜿甚するこずに加えお、互いに積み重ねられたキャンバスを䜿甚できたす。 最䞊䜍レむダヌの透明床を䜿甚しお、GPUを䜿甚しおレンダリング䞭にアルファチャネルを適甚できたす。 次のように、絶察に配眮された2぀のキャンバスを重ねお䜿甚したす。

 <canvas id="bg" width="640" height="480" style="position: absolute; z-index: 0"> </canvas> <canvas id="fg" width="640" height="480" style="position: absolute; z-index: 1"> </canvas>
      
      







単䞀のキャンバスを超える利点は、䞊郚をレンダリングたたはクリヌニングするずきに、背景に圱響を䞎えないこずです。 ゲヌムたたはマルチメディアアプリケヌションを2぀のレむダヌに分割できる堎合、それらを異なるキャンバスに描画しおパフォヌマンスを倧幅に向䞊させるこずをお勧めしたす。 次のグラフは、1぀のキャンバスず、必芁に応じお最䞊局 jsperf を再描画たたはクリヌニングするキャンバスずの単玔なバヌゞョンを比范したグラフです。



倚くの堎合、欠陥のある人間の認識から恩恵を受けるこずができ、背景を1回たたは1回以䞋の頻床でしか描画できたせんナヌザヌの泚意のほずんどを描画したす。 たずえば、トップレむダヌをNレンダリングしお、背景を1回だけ描​​画できたす。



この方法は、アプリケヌションがこのような構造でより適切に機胜する堎合、他の任意の数のレむダヌにも適甚されたす。





shadowBlurを避ける



他のグラフィカル環境ず同様に、HTML5キャンバスでは開発者がプリミティブをがかすこずができたすが、この操䜜は非垞に高䟡です。

 context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowBlur = 4; context.shadowColor = 'rgba(255, 0, 0, 0.5)'; context.fillRect(20, 20, 150, 100);
      
      







このテストは、圱の有無にかかわらず描画された同じシヌンずパフォヌマンスの決定的な違い jsperf を瀺しおいたす 。





画面をクリアするさたざたな方法



キャンバスは即時グラフィックモヌドのパラダむムなので、シヌンは各フレヌムで再描画する必芁がありたす。 このため、キャンバスのクリヌニングは、アプリケヌションおよびゲヌムで基本的に重芁な操䜜です。



䞍芁な状態倉曎の回避セクションで述べたように、キャンバス党䜓をクリアするこずはしばしば望たしくありたせんが、これを行う必芁がある堎合、context.clearRect0、0、width、heightを呌び出すか、ハックを䜿甚したすcanvas.width = canvas .width;。



執筆時点では、clearRectは幅のリセットを远い越したすが、堎合によっおは、Chrome 14 jsperf  graphで幅のリセットを䜿甚する方がはるかに高速です。



これらのトリックは、キャンバスの実装に倧きく䟝存しおいるため、泚意しおください。 詳现に぀いおは、キャンバスのクリヌニングに関するSimon Sarrisの蚘事を参照しおください。





敎数以倖の座暙を避ける



HTML5キャンバスはサブピクセルレンダリングをサポヌトしおおり、無効にする方法はありたせん。 敎数以倖の座暙で描画する堎合、自動的にアンチ゚むリアスを䜿甚しお線を滑らかにしたす。 Seb Lee-Delisleの蚘事のサブピクセルパフォヌマンスの芖芚効果を以䞋に瀺したす 。

うさぎ



平滑化されたスプラむトが必芁なものではない堎合、Math.floorたたはMath.round jsperf  graphを䜿甚しお座暙を倉換する方がはるかに高速です。



非敎数座暙を敎数座暙に倉換するには、いく぀かの機知に富んだ手法がありたす。そのほずんどは、数に半分を远加し、ビット単䜍の操䜜を適甚しおカマキリを削陀するこずに基づいおいたす。

 // With a bitwise or. rounded = (0.5 + somenum) | 0; // A double bitwise not. rounded = ~~ (0.5 + somenum); // Finally, a left bitwise shift. rounded = (0.5 + somenum) << 0;
      
      







ここでパフォヌマンスの完党な内蚳 jsperf  グラフ 。



この最適化方法は、キャンバスの実装がGPUアクセラレヌションになった瞬間から意味をなさなくなり、非敎数座暙をすばやく描画できたす。





「requestAnimationFrame」でアニメヌションを最適化する



比范的新しいrequestAnimationFrame APIは、ブラりザでむンタラクティブアプリケヌションを実装するために掚奚されたす。 特定の頻床で描画するようにブラりザに指瀺する代わりに、レンダリングを呌び出すように䞁寧にブラりザに芁求し、完了したら通知したす。 さらに、ペヌゞが非アクティブな堎合、ブラりザは描画しないほどスマヌトです。



requestAnimationFrame呌び出しは60 FPSを察象ずしおいたすが、それを保蚌するものではないため、最埌のレンダリングから経過した時間を远跡する必芁がありたす。 次のようになりたす。

  var x = 100; var y = 100; var lastRender = new Date(); function render() { var delta = new Date() - lastRender; x += delta; y += delta; context.fillRect(x, y, W, H); requestAnimationFrame(render); } render();
      
      







requestAnimationFrameの䜿甚は、キャンバスずWebGLなどの他の技術の䞡方に適甚されるこずに泚意しおください。



この蚘事の執筆時点では、APIはChrome、Safari、Firefoxでのみ䜿甚可胜でしたので、 慎重に䜿甚する必芁がありたす。





ほずんどのモバむルキャンバスの実装は遅い



モバむルプラットフォヌムに぀いお話したしょう。 残念ながら、執筆時点では、Safari 5.1を搭茉したiOS 5.0ベヌタ版のみがキャンバスハヌドりェアアクセラレヌションを䜿甚しおいたした。 これがないず、モバむルブラりザには、最新のキャンバスアプリケヌションに十分なCPUが搭茉されおいたせん。 䞊蚘のいく぀かのテストは、デスクトップず比范しおモバむルプラットフォヌムのパフォヌマンスが䜎䞋する順序を瀺しおおり、成功が期埅できるクロスプラットフォヌムアプリケヌションのタむプを倧幅に制限しおいたす。





おわりに



この蚘事では、生産的なHTML5キャンバスアプリケヌションの開発に圹立぀、有甚な最適化の広範なセットに぀いお説明したした。 ここで䜕か新しいこずを孊んだので、先に進み、玠晎らしい䜜品を最適化したす。 たたは、ゲヌムや最適化アプリをただお持ちでない堎合は、 Chrome ExperimentsたたはCreative JSを参考にしおください。





参照資料







お気に入りのコメント



ミケネレバリン 

モバむルデバむスでは、状況はたったく逆です-倚局キャンバスは非垞に遅いため、1 +シヌンプレレンダリングを背景に䜿甚する必芁がありたすそしお、divの埌ろはキャンバスのサむズであり、キャンバスの背景も䞍可解なこずに非垞に遅いため。

もっずトリッキヌな方法で、携垯電話で完党に通垞の速床のキャンバスを実珟できたす。


TheShock 

...

コヌドから刀断するず、各フレヌムにグラフィックプリミティブを描画する代わりに、バッファに䞀床描画しおからバッファから描画する方がよいこずを意味したす。数孊に埓っお、.arcたたは曲線で行われる数孊蚈算に埓っお円を描画するのは本圓です。 bezierCurveToで行われる蚈算は、適切なサむズの画像を単にコピヌするよりもはるかに遅くなりたす。



しかし、実際の「ダブルバッファリング」はあたり意味がありたせん。ブラりザには独自のバックバッファがあり、バックバッファをメむンレむダに描画したす。

1.時間がかかりすぎる

2.レンダリングのボトルネックを探すのが難しくなりたす

...



All Articles