プリレンダリングは、描画に必要な表示状態を都度生成するのではなく、あらかじめ描画が高速な状態(ビットマップなど)にしておき、再生速度を向上させるというものです。もともと、3Dグラフィックなどで使われている用語です。
拡大縮小・回転されたMovieClipの状態をプリレンダリングしておけば、ビットマップキャッシュと同様の高速化を、拡大縮小・回転が発生するアニメーションでも実現することが可能になります。プリレンダリングは、表示前にいくばくかの処理時間が必要になってしまいますが、表示後の快適さとのトレードオフを考えても、実装する価値はあるでしょう。
ただし、プリレンダリングは高速な動作を実現できる半面、「メモリを大量に使ってしまう」という欠点があります。最近のPCは、かなりメモリが潤沢に積まれるようになってきていますが、あまりに大きな画像や大量のアニメーションをプリレンダリングする際には注意が必要です。どんなに多くても、メモリ使用量が100Mbytes程度を超えないくらいで控えめに使ってください。
今回はサンプルとして、1つ前にお見せしたFlashサンプル(「ビットマップキャッシュ」を使ったけど、形状そのものが変化するような値を変更してしまう場合)を、プリレンダリングを用いて高速化したものを以下に示します。
ベクタをラスタに動的に書き出す処理(プリレンダリング)により高速化した例 |
Flashでプリレンダリングを行う具体的な方法としては、BitmapDataクラスを使います。BitmapDataはdraw関数を用いてMovieClipをビットマップに書き込めるので、必要な枚数分BitmapDataを生成し、あらかじめ回転状態のMovieClipをdrawします。
今回は、回転ということなので、0.2から1.5までの各スケールごとに6度ずつ360度分、計840枚のBitmapを最初に生成しています。この機能を実装するために作成したMovieClipの継承クラスの実装は、以下のようになっています。
package { import flash.display.*; import flash.events.Event; import flash.geom.Matrix; import flash.geom.Rectangle; /** * ベクタ画像の 0.2 〜 1.5 までのスケールにおける * 回転状態をプリレンダリングするクラスです */ public class Prerendering extends MovieClip { /** プリレンダリング用 BitmapData 格納 Vector */ private static var _bmdList:Array; /** x 方向の移動速度 */ private var _x:Number; /** y 方向の移動速度 */ private var _y:Number; /** rotation を override するため、別途変数を用意 */ private var _rotation:Number; /** 表示用 Bitmap */ private var _bmp:Bitmap; private var _scale:Number; /** * コンストラクタ */ public function Graphic6() { // プリレンダリングが未完の場合は行う if ( !_bmdList ) { _bmdList = new Array(); // GraphicBase は書き出したい元ベクタ MovieClip var mc:MovieClip = new GraphicBase(); // MovieClipの矩形サイズを取得する var rect:Rectangle = mc.getBounds(this); var size:Number = Math.sqrt( rect.right * rect.right + rect.bottom * rect.bottom ); // 0.2 〜 1.5までのスケール回転状態をプリレンダリングする for ( var s:uint = 2; s <= 15; s++ ){ // スケールを計算 var scale:Number = s / 10; // レンダリング保持用 Vector を生成 _bmdList[s] = new Vector.<BitmapData>(); // スケール s の回転状態を生成 for ( var i = 0; i < 360; i+=6 ) { // BitmapDataを生成 var bmd:BitmapData = new BitmapData( size * 2 * scale + 1, size * 2 * scale + 1, true, 0 ); // 変換Matrixを定義 var m:Matrix = new Matrix(); m.scale( scale, scale ); m.rotate( i * Math.PI / 180 ); m.tx = size * scale; m.ty = size * scale; // レンダリングと保持 bmd.draw( mc, m ); _bmdList[s][i] = bmd; } } } // 以下インスタンスの処理 _bmp = addChild( new Bitmap() ) as Bitmap; _scale = Math.max( 2, Math.round( Math.random() * 15 ) ); rotation = super.rotation; // 初期位置を決定 x = 30 + Math.random() * 700; y = -100 + 30 * Math.random(); // 移動速度を決定 _x = Math.max( 1, Math.round( 6 * Math.random() ) ); _y = Math.max( 1, Math.round( 6 * Math.random() ) ); // EnterFrame の処理を登録 addEventListener(Event.ENTER_FRAME, _enterFrame); } /** * rotation. * 回転に応じた BitmapData を表示する処理に変えるため、override しています */ override public function get rotation():Number{ return _rotation; }; override public function set rotation( value:Number ):void{ _rotation = Math.round( value % 360 ) _bmp.bitmapData = _bmdList[_scale][_rotation / 6]; } /** * EnterFrame Listener. * @param e */ public function _enterFrame(e:Event){ x -= _x; y += _y; rotation += 6; if ( x < -80 || 480 < y ) { x = Math.random() * 700; y = -80; } } } }
厳密にいうと、このクラスは今回のサンプルの実装といくつかの相違点があります。一番の違いは、コンストラクタ内でプリレンダリングをfor文を用いて一気に行ってしまっている個所です。
このやり方でも、プリレンダリングを達成できるのですが、非常に重い処理のため、数秒間処理が固まる可能性があります。そのため、今回のサンプルでは処理を分散して固まらないように配慮しています。
このほかにも何点か改善点があるのですが、一度に説明をすると話が膨れてしまうため、今後の連載で触れていく予定です。
BitmapDataの配列をインスタンスメンバではなく、クラスメンバとして定義している点に注目してください。
Bitmap.bitmapDataプロパティは、BitmapDataを占有するのではなく参照のみ利用するので、まったく同じBitmapDataでいいのであれば、複数のBitmapインスタンスから同じBitmapDataを参照した方が無駄がありません。
プリレンダリングは、初期化に時間がかかってしまうものの、一度描画状態作ってさえしてしまえば速度が維持できるのが大きな利点です。この特性を利用すれば、重くなりがちなフィルタ(グラフィックのエフェクト/視覚効果)機能も高速にアニメーションさせることが可能で、以下のような表現も高速にこなせます。
フィルタ機能などの重い処理を、プリレンダリングで高速化した例(スコアは表示されません) |
どうでしょう、吹雪は吹きましたか? 今回のチューニングは以上です。
FlashのBitmapDataには、限界サイズがあります。Flasy Player 10またはAdobe AIR 1.5の実行環境では、widthもしくはheightは8191pxまで、width×heightが1677万7215pxまでとされています。
これ以上大きなものを描画できませんので、注意してください。
プリレンダリングの処理を一気にやり過ぎると処理がたまりすぎてしまい、スクリプトタイムアウトが発生してしまう可能性もあります。これを回避するような分散実行の仕組みは、今後紹介する予定です。
ようやく本格化してきた連載第2回、いかがでしたでしょうか。描画に直接関係する話が主でしたので、チューニングの効果を実感しやすかったのではと思います。
次回は、今回に引き続きMovieClipの高速化を題材に、イベント処理の最適化について解説していきます。たかがイベント処理と侮るなかれ、やり方1つで描画速度はかなり変わってしまいます。
また、今回触れられなかった細かなチューニング手法もちょっとずつ紹介できたらと思います。それでは、次回もよろしくお願いします。
今回の記事のために作成したサンプルのソースコード一式が、こちらからダウンロードできますので、参考にお使いください。
@IT関連記事
作って学ぶAIRウィジェットの基礎→応用
最近よく聞くAdobe AIRって何だっけ? ウィジェットを簡単に作れるらしいけど…… と曖昧な知識のあなたに贈る超入門連載。楽しいサンプルを作って基礎から応用まで学ぼう
現場で使えるFlex実践テクニック
本連載では、Flex開発で基本となる特徴的な機能から一歩進んで、実開発の現場でよく使われるテクニックについて、より実践的に解説します
画像とコードの触媒Flash Catalystについて語りますと
WebとUIをつなぐトリックスター(3) 先月発表があったアドビの新ツールFlash CatalystとFlex Builder 4を実際に使ってみた。その感想とアドビ社員たちが語ったことを紹介しよう
デザインハック < リッチクライアント 2008/12/26
Flash CS5のiPhoneアプリ変換機能は無駄にならない
D89クリップ(15) Flash CS5製とiPhone SDK製のアプリの違いや、Flash Lite 4.0などFlashプラットフォームのモバイル対応について、Flashのエバンジェリストに聞いた
デザインハック < リッチクライアント 2009/12/24
WebデザイナのためのHTMLチューニング入門
Webサイトを見た人の印象を良くするのか悪くするのかには“速度”が大きくかかわってきます。FirefoxのプラグインYSlowで測る7つの計測ポイントから“速い” HTMLの書き方を学びましょう
「デザインハック」コーナー
河北 啓史(かわきた ひろふみ)
WebサイトのHTML/CSS/Flash/JavaScriptといったフロント部分の開発やUI制作のディレクションを担当。現在は、UI検証のためのプロトタイプ作りや実験的なUIのモックアップ作成といった細かいものから、「サグールテレビ」のような大規模のFlashプロジェクトまで幅広く担当している
Copyright © ITmedia, Inc. All Rights Reserved.