[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 する時点で 0x00FFFFFF 以下のデータはアルファが 0 になるので、数値自体も 0 としてセットされてしまうんですよね。PixelBender 上で一ピクセルの情報だけを取り出して・・・とかの方法も分からない(できない?)し、何か良い活用法思いついた方はいらっしゃらないでしょうか?

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

[Flash Player 10 #2] 3D のプリミティブにテクスチャを適用する。

今回は先日のデモにテクスチャを適用します。コード自体に大まかな変更は無いので、前回のコードで説明が足りない所や今回の肝になる部分の解説だけしていきます。

※ 要 Flash Player 10

平面のテクスチャ適用デモはこちら
立方体のテクスチャ適用デモはこちら

まずは以下のコード。

var world:Matrix3D = scene.transform.matrix3D.clone();
world.append(projection.toMatrix3D());

早速新しい Matrix3D クラスですが、そもそも行列(Matrix)はある座標系のものを別の座標系に変換するときに使用します。今回はシーンの座標系を透視投影を用いて僕たちが見ているスクリーン上の座標に変換する必要があるので、シーンの座標系を表す行列に透視投影の行列を乗算することで変換用の行列が出来上がります。このとき使用するのが append メソッド、もしくは prepend メソッドで、A.append(B) は A × B、A. prepend(B) は B × A を表します(多分)。詳しくは行列について調べてみてください。

次はこのコード。

var v:Vector3D = world.transformVector(vertex);

v.w = projection.focalLength / (projection.focalLength + v.z);
v.project();

vertices.push(v.x, v.y);

ここでは変換用の行列でプリミティブの頂点を変換しています。その後にベクトルの w 要素に上の計算で求まる数値を代入してあげて、project メソッドを実行してあげることでスクリーン上の座標へと変換出来ます。晴れて二次元上の座標となった頂点を描画用の頂点ベクターに格納しています。

最後はこのコード。

canvas.graphics.beginBitmapFill(texture);
canvas.graphics.drawTriangles(
    vertices, primitive.indices, primitive.uvtData, TriangleCulling.NEGATIVE
);

この drawTriangles が新しく Graphics クラスに実装されたメソッドなんですが、ポリゴンを描画するために生まれたようなもので、とても便利。二次元上に変換した頂点ベクターとプリミティブの各情報、最後にカリングの指定をしてあげることでプリミティブのポリゴンが描画出来ます。ちなみに TriangleCulling.POSITIVE は描画する三角形の頂点が反時計周りの時には描画しません。逆に TriangleCulling.NEGATIVE は時計回りの時には三角形を描画しません。詳しい解説はこちら(Flash Player 10 Drawing API)や、「法線」とかでググってみるといいかも。今回も FlashDevelop のプロジェクトファイル一式を上げておきますので、参考にどうぞ。

’08 5/21 追記:
Flash Player 10 Drawing API を元ソースではなく、なぜか中国?の Flash サイトへのリンクにしてたので修正しました。すいません。

プロジェクトファイルはこちら

パースペクティブコレクトまでしてくれる(してくれてますよね?)、とても素敵な drawTriangles メソッドですが、線の設定(lineStyle)が出来ないのでワイヤーフレームなプリミティブが描画出来ないんですよね。これは仕様なのかバグなのか。

’08 5/21 追記:
パースペクティブコレクト(透視補正)はしてくれないみたいです、すいません。デモを上げておきますので、ご確認ください。

透視補正のデモはこちら

’08 5/25 追記:
やっぱり補正にも対応しているみたいですね。
Mtok-blog さんで紹介されていますので、参考にどうぞ。

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

[Flash Player 10 #1] 3D のプリミティブを回してみる。

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

ついにベータ版が登場した Flash Player 10 。GPU サポートやテキスト周りの強化なんかがありますが、その辺りは他の人に任せるとして…。3D が正式にサポートされたことが何とも嬉しいです。いくつか試してみたので、デモをアップしてみます。

※ 要 Flash Player 10

平面の回転デモはこちら
立方体の回転デモはこちら

解説を交えたコードは下記の通り。

package
{
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.geom.Matrix3D;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Vector3D;
    import flash.text.TextField;
    import net.unbland.debug.FPS;
    import primitives.Cube;
    import primitives.Plane;

    [SWF(width=320, height=320, backgroundColor=0xDDDDDD, frameRate=30)]
    public class Demo01 extends Sprite
    {
        // 描画用のスプライト
        private var canvas:Sprite = new Sprite();

        // 透視投影のためのクラス
        private var projection:PerspectiveProjection = new PerspectiveProjection();
        // 3D シーン(ステージには配置しない)
        private var scene:Sprite = new Sprite();

        // 3D プリミティブ(別クラスで定義)
        // 平面用
        private var primitive:Plane = new Plane();
        // 立方体用
        //private var primitive:Cube = new Cube();

        public function Demo01():void
        {
            // ステージの設定、3D には関係無い
            setupStage();

            // 3D では中心点が左上でなく、中央になるので画面中央に配置
            canvas.x = canvas.y = 160;
            addChild(canvas);

            // プロジェクションの視野角を決める
            // これにより焦点距離が変わる
            projection.fieldOfView = 60;

            // scene.transform.matrix3D は最初は空になっている(バグ?)ので、
            // 行列を代入しておく
            scene.transform.matrix3D = new Matrix3D();
            // 実際に描画を行う関数を毎フレーム実行
            scene.addEventListener(Event.ENTER_FRAME, renderScene);
        }

        private function renderScene(e:Event):void
        {
            // 変換用行列を作成
            var world:Matrix3D = scene.transform.matrix3D.clone();
            // 描画用の頂点情報が格納されたベクター
            var vertices:Vector.<Number> = new Vector.<Number>();

            // プロジェクションの行列を変換用行列に乗算
            world.append(projection.toMatrix3D());

            // プリミティブの各頂点を走査
            for each (var vertex:Vector3D in primitive.vertices)
            {
                // 変換用行列で頂点をシーンの座標系に変換
                var v:Vector3D = world.transformVector(vertex);

                // プロジェクションの焦点距離を元に計算
                v.w = projection.focalLength / (projection.focalLength + v.z);
                // スクリーン上に投影
                v.project();

                // 描画用頂点に追加
                vertices.push(v.x, v.y);
            }

            // ポリゴンを描画
            canvas.graphics.clear();
            canvas.graphics.beginFill(0xDDDDDD);
            // 平面用
            canvas.graphics.drawTriangles(vertices, primitive.indices);
            // 立方体用
            //canvas.graphics.drawTriangles(
                //vertices, primitive.indices, null, TriangleCulling.NEGATIVE
            //);

            // シーンを回転
            scene.rotationY += 2;
            scene.rotationZ += 1;
        }

        private function setupStage():void
        {
            FPS.show(stage);

            stage.showDefaultContextMenu = false;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            graphics.lineStyle(1, 0xAAAAAA);
            graphics.beginFill(0xFFFFFF);
            graphics.drawRect(10, 10, 300, 300);
        }
    }
}

FlashDevelop の開発途中版が早くも Flash Player 10 に対応しており、Vector とかのコードヒントとかもで出るのでオススメです。twitter での beinteractive 先生のコメントで知ったのですが、Flash Player 10 Debug 版もこっそりあるみたいなので合わせて使えばウハウハです。今回のサンプルに使ったプロジェクト(プリミティブ含む)を上げておきますので、参考にどうぞ。

プロジェクトファイルはこちら

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

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

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

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

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

続きを読む…

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

さくらインターネットに PHP5 を入れるメモ

突然ですが、 unbland.net はさくらインターネットのスタンダードプランなのです。で、僕は ZendFramework を試したかったのです。なのにさくらインターネットに昨年導入された PHP5 は、MySQL 用の PDO ドライバが入ってなかったりします。問い合わせてみても今のところ導入予定はないそうなので、PHP5 から自分で入れてみました。忘れないようにメモ。

続きを読む…

カテゴリー: PHP タグ:

[AS3D #1] 自作 3D ライブラリを Snippets にコミットしました

Papervision3D や Sandy など優秀な 3D ライブラリがある中、自学のため 3D ライブラリを作っているのですが、ある程度の形が出来たので Snippets にコミットしてみました。Snippets の AS3D からチェックアウトして試していただけるとありがたいです。

デモはこちら

まだまだ上手く動いてないところや未実装な部分も多く、実用的ではありませんが・・・。

コードは下記の通り。

続きを読む…

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

[Papervision3D #1] テクスチャとシェーディングの同時適用法

Papervision3D で少し遊んでみました。本来ならテクスチャとシェーディングは同時適用できない(どちらもマテリアルのため)ですが、BlendMode を活用して同時適用してみました。

1/27 追記:
嘘でした、ごめんなさい。ShadedMaterial で実現できるようです。今日も迷子さんで詳しく解説されていますので、そちらをご参照ください。あー、自分嘘ばっか。もう知ったかぶりはしません・・・。

デモはこちら

シェーディングを施すと一気に質感が良くなりますね。Papervision3D のシェーディングは多分擬似だと思うのですが(擬似じゃない?自分の頭じゃ分かんない)、それにしても良く出来てるなぁ。以下はドキュメントクラスのコード。モデルデータとテクスチャは各自ゲットしてください。あと、GreatWhite (3.12.07) でパブリッシュしています。

コードは下記の通り。

続きを読む…

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

[ASde3D #10] テクスチャマッピング

なかなか時間が取れずに進んでませんが、自作 3D にテクスチャマッピング機能を付けました。まだまだおかしいところがありますが、一応動いているので載せてみます。

デモはこちら

透視補正が出来ていないので平面の方はゆがみまくりですが、テクスチャ + グーローシェーディングです。Away3D は透視補正を実装してるので中身を覗いてみたんですが、複雑過ぎて何をしてるのかさっぱり・・・。カリングといい、透視補正といい、ピクセル処理が軽くなってくれれば、資料も多いしこんなに苦労しないんだろうなぁ。

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

[3D Tips #1] ベクトル

3D の基礎知識として絶対に欠かせない「ベクトル」や「行列」。今回はベクトルについて。

ベクトルは大きさと方向を持った量のこと。

2 次元のベクトルの場合は、<x, y> 2 つの成分を持ち(厳密には、どんな成分を持たせるかは実装者次第で、n 次元のベクトルは n 個の成分を持つというだけ)、 AS でいうところの Point クラスのようなもの。Point クラスでいえば、大きさは length メソッドで求まり、方向は x, y 成分の各数値になる。ただ、3D で扱うベクトルは 3 次元なので <x, y, z> 3 つの成分を持つ独自のクラスを作る必要がある。この時、持たせておくクラスメンバは下記の通り。

続きを読む…

カテゴリー: Other タグ:

[3D Tips #0] 始めに

AS で 3D をする際に必要な知識をエントリーしていきたいと思います。目的としては、自分用の備忘録として、副次効果で他の人の参考になればという感じです。僕自身は高校を中退して高校数学の基礎知識がほぼ皆無なため、数式等の詳しい説明は出来かねますが、参考サイトへのリンクを貼ってごまかすことにします。Math.sin の中でやってる計算なんて殆どの人が分からないのと同じで、必要なのは使えることだと思うので。間違いなどが結構出てくると思うので、詳しい方からの突っ込み大歓迎です。

カテゴリー: Other タグ: