アーカイブ

‘Tips’ タグのついている投稿

ActionScript の最適化 Tips を wonderfl に投稿しました

ActionScript の最適化って色々なサイトに載っていますが、wonderfl にまとめて載っておくとコードと動きを同時に確認できるし、自分のためにも便利だと思って色々と投稿しました。コードへのリンクに個人的な私見を加えてご紹介します。ただ、人によって意見が異なるかもしれないので、コードと動きを直接確認しておくことをお勧めします。この処理はおかしいんじゃないか?とかありましたらコメントください。

変数名の長さによる処理速度の違い

変数名の長さによる違いはありません。ですので変数名は、他の人が見やすい・自分が後で確認しても分かり易いような名前を付けておいた方が良いです。

変数を参照する際の処理速度の違い

上のコードでは _getPi <<< Math.PI <<< MyMath.PI = Main.PI < PI = _pi = ns::_pi = pi という結果で、ビルトインクラスのプロパティアクセスは若干重いので、ループ内で大量に参照する場合は変数に格納しておく方が良いです。また、getter アクセスの実態は関数ですので結構重いみたいです。MyMath.PI や Main.PI は、他の参照方法に比べると一階層下がるので若干重いですが、100 万回もループしての結果なので、あまり気にする必要はないんじゃないかと思います。ただ、注意事項が一つありますので「色々な整数化手段での処理速度の違い」も目を通しておいて下さい。

if … else と switch での処理速度の違い

if … else 文は比較回数が少ない場合は軽いですが、比較回数が増えると switch 文の方が高速です。ただ、100 万回も処理させて数ミリ秒の違いですので、臨機応変に見やすい方を記述しておけば良いんじゃないかと思います。

色々な整数化手段での処理速度の違い

Math.floor() が重いのは周知の事実。ただ、ローカル変数に格納したもので計算した場合は軽くなりそうなものの、逆に重くなるというのは以外だったと思います。これは先の「変数を参照する際の処理速度の違い」で Math.PI のようなプロパティを変数に格納しておく Tips と反して、ビルトインクラスのメソッドは逆に負担になりますので注意が必要です。そして本題の整数化では、n >> 0 などのビット演算で整数化する方が多いのですが、int(n) の方が高速だし見やすいのでお勧めです。

Array, Vector 走査時のイテレーション方法による処理速度の違い

forEach は関数を実行するコストが掛かるのでやはり重いです。ただ、for each よりも for の方が高速なのは自分的にもビックリでした。倍速近い差が出るので、大量な処理の中で走査処理が必要な場合は for の方が良いかもしれません。もちろん、Array より Vector の方が高速です。

Array, Vector 走査時に加算を行う際の処理速度の違い

これももちろん、Array より Vector の方が高速という結果に。ただ、Vector の長さを固定している方が高速になるかと思いきや、固定していなくても参照速度に差はないようです。

オブジェクト生成による処理速度の違い

new Object() より {}、new Array() より [] が高速というのは周知だと思います。あと、Vector の長さを指定すると最初に要素の初期化処理が入るようで、生成コストが高くなります。あとは Sprite の生成コストは当たり前のように高いです。独自クラスの生成は、処理が少なければ Object を生成するのとあまり変わりません。

サイン・コサインの取得方法による処理速度の違い

予めサインテーブルを生成した後、ラジアンをテーブルのインデックスに変換して近似値を参照するというもの。かなりの高速化が期待できますが、取得できる値は近似値だという点に注意が必要です。3D での頂点処理などで大量のループ処理を行う際などに効果が期待できるかと思います。

今のところ試したコードはこんな感じです。これからも、他の最適化を思い付いたら wonderfl に投稿した後、ブログにエントリーしていきます。

カテゴリー: Flash (ActionScript) タグ: ,

[Flash Player 10 #4] PixelBender のファイルを使わずにカスタムフィルターを定義

すっかり FlashPlayer 10 の魅力に取り付かれています。

‘08.10.09 追記:
CS4 からはメタデータを使ってファイルの埋め込みができるようになるようなので、こんな面倒臭いことしなくても大丈夫です。

通常、Shader を使用するときは pbj 形式のファイルが必要ですが、今回はこのファイルを使用せずにカスタムフィルターを作成するという試み。結果から言うと大成功でした。これで他の BitmapFilter 同様、import するだけでカスタムフィルターが使用できます。このやり方は流行ると思うなぁ。Adobe の人もこういう使い方を想定しているんでしょう、きっと。

まずはカスタムフィルターのコード。

package
{
    import flash.display.Shader;
    import flash.filters.ShaderFilter;
    import flash.utils.ByteArray;

    public class ColorizeFilter extends ShaderFilter
    {
        // ここが重要!
        // あらかじめ、PixelBender のバイナリデータをベクター情報として格納しておく。
        private static var _data:Vector.<int> = Vector.<int>([-91,1,0,0,0,-92,11,0,67,111,108,111,114,70,105,108,116,101,114,-96,12,110,97,109,101,115,112,97,99,101,0,109,117,116,97,0,-96,12,118,101,110,100,111,114,0,109,117,116,97,0,-96,8,118,101,114,115,105,111,110,0,1,0,-96,12,100,101,115,99,114,105,112,116,105,111,110,0,84,104,105,115,32,102,105,108,116,101,114,32,70,105,108,108,32,99,111,108,111,114,46,0,-95,1,2,0,0,12,95,79,117,116,67,111,111,114,100,0,-95,1,4,1,0,15,99,111,108,111,114,0,-94,4,100,101,102,97,117,108,116,86,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,63,-128,0,0,-94,12,100,101,115,99,114,105,112,116,105,111,110,0,99,111,108,111,114,0,-93,0,4,115,114,99,0,-95,2,4,2,0,15,100,115,116,0,48,3,0,-15,0,0,16,0,29,4,0,-13,3,0,27,0,1,4,0,-13,1,0,27,0,29,2,0,-13,4,0,27,0]);
        private static var _byteCode:ByteArray;

        private var _color:uint;

        public function ColorizeFilter(color:uint):void
        {
            // ムービーを通して初めての new 時のみ、Vector を ByteArray に変換する。
            if (_byteCode == null)
            {
                _byteCode = new ByteArray();

                for (var i:int = 0, l:int = _data.length; i < l; i++)
                {
                    _byteCode.writeByte(_data[i]);
                }
            }

            super(new Shader(_byteCode));

            this.color = color;
        }

        public function get color():uint
        {
            return _color;
        }

        public function set color(value:uint):void
        {
            _color = value;
            // プロパティのセッター内で Shader にデータを渡す。
            shader.data.color.value = [value >> 16, value >> 8 & 0xFF, value & 0xFF];
        }
    }
}

実際に使用するときのコード。

var data:BitmapData = Bitmap(new image()).bitmapData;

data.applyFilter(
    data,
    data.rect,
    new Point(),
    new ColorizeFilter(0xFF0000)
);

addChild(new Bitmap(data));

こんな感じで通常のフィルターと同じように import して new するだけで使用できます。今回のコード一式も例のごとく libspark に上げてますので、必要な方は http://www.libspark.org/svn/as3/Astro/ShaderFilter/CustomFilter/ 以下をチェックアウトしてください。

カテゴリー: Flash (ActionScript) タグ: , ,

[Flash Player 10 #3] Shader + Vector で計算の高速化

2008 年 5 月 19 日 muta244@admin コメント 1 件

beinteractive さんの twitter でのコメント。

Player10 で結構な長さのint配列に対して演算をしなければならない場合、
1. ただのArray
2. Vector.<int>
3. Vector.<int> を BitmapData に setVector して、Shader (Pixel Bender) で計算後、 getVector
のどれが一番速いんだろう

を受けて、自分も気になったので調べてみました。100 万個強のデータに uint を加算するテスト結果は以下の通り。

Array => 361 ms
Vector => 188 ms
Shader + Vector => 35 ms

Shader + Vector の組み合わせは Array より十倍近く早い結果に。今回は簡単な加算のみですが、色々と試してみる価値がありそうですね。試したコードは libspark に上げています。一式必要な方は http://www.libspark.org/svn/as3/Astro/ShaderFilter/CalcShader/ 以下をチェックアウトしてください。

‘08 5/23 追記:
活用法がないか色々と考えたり試したりしているんですが、そもそも setVector する時点で 0×00FFFFFF 以下のデータはアルファが 0 になるので、数値自体も 0 としてセットされてしまうんですよね。PixelBender 上で一ピクセルの情報だけを取り出して・・・とかの方法も分からない(できない?)し、何か良い活用法思いついた方はいらっしゃらないでしょうか?

カテゴリー: Flash (ActionScript) タグ: , ,

ActionScript 3 のフィルターについて。

以前、HiSprite クラスという、フィルター関連の設定をプロパティで行えるようにしたクラスを作成しました。ただ、これだと Sprite を継承した独自クラスなどに適用できません。ですので、この場合は委譲用クラスを実装した方が実用的だと考えました。しかし、ことごとく壁にぶち当たり、結論から言うと断念。

そんなこんなを twitter で愚痴っていると、nium 先生と beinteractive 先生からアドバイスを頂きました。「元オブジェクトに触られた場合に整合性を取ることは委譲の永遠の課題」というコメントなどはとても参考になり、ありがたかったです。この場を借りてお礼申し上げます。両先生、ありがとうございました!

以下、色々試してみたメモ。
3. 辺りはまだ望みがありそうなので、今後も試してみる予定です。

続きを読む…

カテゴリー: Flash (ActionScript) タグ: ,