ClickableCanvasのパフォーマンスを改善する
これは以前から気になっていたことなんですが、
ClickableCanvasのデモページを自分が持っている低スペックのネットブック(Celeron、XP)で見てみると、すべてのデモがとてつもなく重く動作します。実用性はゼロと言ってもいいくらいです。これは
CanvasFighterにも言えることですが、
HTML5/
Canvas機能がPCのスペックに大きく左右されるためです。
そのなかで、
Chrome(ver 19)を使うと低スペックPCでも問題ない水準で動きました。この辺はさすがというか他のモダンブラウザに水をあけている観があります。
Chromeのシェアは今年5月時点の情報では約19%。
Firefoxと
IEでシェア減少が続いているなか、じりじりと上昇傾向が続いています。低スペックPCのユーザーには
Chromeがお勧めです。
一方で
IE9は
Vistaか
Windows7の環境が必要ですが、これで
ClickableCanvas バージョン2を実行すると意外に滑らかに動作します。また、
Chromeの
Canvasグラフィックがやや汚いというか劣るのに比べて、
IE9は
Firefox並みにきれいに表示されます。
IEのバージョン別内訳を見ると、
8が27%で
9が17%となっています。
IE9の今後の普及にも期待したいところです。
とはいうものの、ブラウザに頼らずに何とか
Canvasのパフォーマンスをよくしたいところ。以下のサイトを参考にして、
ClickableCanvasの書き直しをしようと考えています。
HTML5 canvas のパフォーマンスの改善このページの中でいくつか挙げられている方法をどのように
ClickableCanvasに取り入れるか考えてながら、
Canvasのパフォーマンス改善をはかっていきたいと思います。
対策1: プリレンダリング
Canvasで有効なプリレンダリングの方法は、別の
Canvas要素に頻繁に更新しない静的な図形(たとえばキャラクターのグラフィックなど)を描画しておいて、その
Canvas要素をメインで使う
Canvas要素で
drawImageメソッドの引数に渡して呼び出し、必要な領域にレンダリングするというものです。要するに
fillメソッドや
strokeメソッドを使用して毎回スーパーマリオのキャラを描画するより、あらかじめ他の
Canvas要素にレンダリングしておいたキャラグラフィックを画像として呼び出した方が速いということです。というか
drawImageメソッドって
Imageオブジェクトだけしか受け取らないと勘違いしていました。
Canvas、
Img、
Video要素といった
HTML要素も第1引数に渡すことができるようです。勉強になりますね。ただ、図形のアニメーションが前提になる
ClickableCanvasでこの手法を取り入れるのはちょっと難しい気がします。なお、この手法を使う場合、キャラなどが描かれた読み込み専用の
Canvas要素のサイズは最小限にすべしとあります。たとえばマリオのサイズが64×64ならば、パフォーマンスのためにもその
Canvas要素を64×64以上にする必要はないということです。
対策2: canvas を一括して呼び出す
これは線形図形やポリゴンを作成するときに適用できる手法です。これらの図形の作成手順は、まず
beginPathメソッドで始点を作り、以降
moveTo、
lineToメソッドでパスを作成、ポリゴンの場合だけ最後に
closePathメソッドを実行し、塗りつぶし(
fill)やストローク(
stroke)メソッドを実行するというものですが、このときできるかぎり
fillメソッドや
strokeメソッドを使う回数を減らすべしとのこと。この方法は実際に
ClickableCanvasで図形単位で行っています。一つの図形を描くのに
fillメソッドと
strokeメソッドを一度ずつで済ませるようにしています。
対策3: canvas の状態を不必要に変更しない
この対策の意味することは、
Canvasのプロパティである
strokeStyleや
fillStyleを頻繁に変更するなというものです。たとえば10本の線からなる二色のストライプ図形を作成する場合、座標をずらしながら
fillStyleプロパティを変更してそのつど長方形を作成していく方法が考えられますが、これだと
fillStyleプロパティを10回変更しなければなりません。一方、最初にひとつの色で一本分の間隔をあけながら長方形を描画し、
fillStyleプロパティを変更した後、あいている空間を別の色で埋めていく方法をとれば、
fillStyleプロパティの変更は2回で済みます。ただしこれを
ClickableCanvasに適用するのは難しいです。色をフェードさせるアニメーションでは更新ごとに
fillStyleプロパティを書き換える必要がありますので。
対策4: 新しい状態の画面全体ではなく画面の差分のみをレンダリングする
Canvasでは描画したグラフィックにオブジェクトの概念がないため、前に描画したグラフィックを
clearRectメソッドなどで消去して、少しだけ色や位置をずらしたグラフィックを再描画し、それを繰り返すことによりアニメーションを表現します。
ClickableCanvasではどうしているかというと、更新のたびに
Canvas要素の画面全体を
clearRectメソッドで消去して再描画する一般的な方法をとっています。この項目の要点というのは、更新のために直前の図形を消去するのにも(つまり
clearRectメソッドを実行するのにも)コストがかかるということです。たとえば画面上に小さな丸い図形しか描かれていないのに、それをいちいち更新するたびに画面全体を消去して再描画するのは無駄ということです。これは是非自分のプラグインにも取り入れたいところですが、消去すべき描画領域を図形ごとに計算しなければならず、コードの追加と書き直しがかなり増えそうな気がします。
対策5: 複雑なシーンには複数の CANVAS をレイヤーにして使用する
ClickableCanvasはバージョン
2から複数の
Canvas要素に効果を適用できるようになりました。なので複数のレイヤーを使ってアニメーションを表現することができます。この手法はプラグイン自体のパフォーマンス改善に使えるというよりは、ユーザーがプラグインを利用時にパフォーマンス改善策として使える方法といえます。重要なことは、更新頻度の少ない背景グラフィックなどを下層のレイヤー(
Canvas要素)にして、更新頻度の高い図形などと一緒のレイヤーにしないようにすることです。
対策6: SHADOWBLUR の使用を控える
図形に影をつける(ぼかしを入れる)効果は
Canvasであまり最適化が進んでいないもようで、この効果を乱用することはパフォーマンス低下につながるとしています。また、この対策を選択するかどうか(つまりぼかしを利用するかどうか)はユーザー次第となります。しかし、ぼかし効果は図形を立体的にして見栄えをよくする非常に効果的な技術なので、パフォーマンスをよほど気にする場合以外では、最小限のぼかしにとどめる程度でよいと思います。
対策7: 浮動小数点座標の使用を控える
Canvasの
lineWidthといったプロパティは、値に整数値のみならず少数の指定ができます。そして、小数値で指定した場合にも無視されることなく、アンチエイリアスがかかる仕様になっていて「なんとなく」グラフィックに反映されるようになっています。ただ、浮動小数点を指定すると、アンチエイリアス効果にコストを使うことになるので、パフォーマンスを気にする場合は
Math.floor(切り捨て)や
Math.round(四捨五入)で整数にすることをすすめています。これは自分のプラグインでもまだ導入していないので、テストしてみて次のバージョン更新時にも導入してみたいと思います。
対策8: REQUESTANIMATIONFRAME を使ってアニメーションを最適化する
恐ろしいことに、この記事を見るまでこのメソッドの存在を忘れていました。これはもっと早く試すべきだったかもしれません。しかし、メソッドが実装されているのがモダンブラウザ限定であり、ベンダーによって挙動が違うかもしれない感じがそこはかとなくしていたため、導入を見送りそのまま忘却してしまったのです。
FPSが60に固定されるなど、何となく使い勝手がよくない感じがしますが、
よーしおまえらー、アニメーションにsetInterval使うなよー - 「くろまほうさいきょうでんせつ」より
こちらのサイトで、
requestAnimationFrameメソッドの使用によって、アニメーション描写処理の最適化、不必要にアニメーションループを行わずCPUなどに負荷をかけないなどメリットが多いことがわかったので、次回以降のバージョンでさっそく
requestAnimationFrameメソッドを取り入れてみたいと思います。
まとめ
項目ごとにパフォーマンス改善策を解説してきましたが、
ClickableCanvasに導入できる方法がいくつもあるのが分かりました。いずれも根本的な改善策というよりはチューンアップといった感じの効果になるかもしれませんが、
Canvasが
Flashなどに比べて明らかにパフォーマンスで劣っていることや、ハードウェアアクセラレータを実装していない
IE8以下のシェアがいまだに4割近くあることを考慮すると、やはりした方がましだと感じます。今回参考にした記事はもともと英文記事で、幸運にも邦訳されたものを読めたのですが、
Web関連の最新記事は多くが海外のものなので、こういう数少ない翻訳記事は見逃さないでいきたいところです。
-
JavaScript/Ajax, ブラウザ Canvas, ClickableCanvas, HTML5