トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

独り言日記(2007/03)

独り言日記

破壊(2007/03/30)

某所で「破壊」についての質問が乗っていたので、面白そうなので実験してみました。

ムービー(1.3MB)

http://ft-lab.ne.jp/files/shade/teapot_cracker.mov

Shade9のプラグインで、形状に亀裂を入れるプラグインを作って実験中です。モーションはパーティクルフィジックス使ってます。まだポリゴン単位の分解しかしてないのですが、表面材質の継承や直方体でもガタガタのメスを入れる、みたいにすると使い物になるかもしれません。

たぶん来週にはできると思いますので、Shade9用のプラグインとしてWin/Macともに公開しますね。ただ、このへんはまじめに研究すれば結構面白い破壊シミュができるのかもしれません。どの位置から亀裂が入るのか、どのように裂けていくのか、、、。たぶんこうかも、というアイデアはあるのですが、今回は単純に分解するのみにとどめておきます。

オブジェクトの面のうちで弱い部分から亀裂が入るとすると、曲面(つまり法線)が薄いところかなぁと想像しています。直方体では角っこは割けにくい、卵の上下は割けにくい、とか。

ShadeでのDXFインポータ高速化(2007/03/27)

Winのみですが、Shade9用のDXFインポータをテスト的に作ってみました。ソースごとアップです(Macはプロジェクトにちょこちょこ加えてビルドすれば使えるかと)。

http://ft-lab.ne.jp/files/shade/DXFImporter_shade9_src_20070327_2.zip

読み込めないDXFもあるのですが、私は3Dアトリエからしか使わないので問題なし!ということで。

先ほどの日記で試した「14,786,898 バイト、108590三角形」のdxfファイルの読み込みがShade9にて3秒くらいで完了しています。約23倍速です。Shadeの機能でボトルネックがあるわけじゃなくてプラグイン実装の問題ですね。

ということで、これくらいは速度アップしてくれると助かります(^_^;;。

おっと、SJISの文字列をUTF-8に変換していないので、日本語の形状名があると化けるか形状名がでないですね。ちとメンテしてみます。日本語処理を入れました(グローバル関数のget_text_encodingにて「plugin_interface::japanese_encoding」を返すように(SJISにしている))。DXFのエンコーティングはどのような規約なんだろう・・・。

ShadeでのDXFのインポート速度(2007/03/27)

まだ途中ではありますが、歴代のShadeでのdxfファイルを読み込む速度を計測。計測はタイマーを立ち上げて目分で計っているのでかなりおおざっぱです。

テスト環境は、Windows XP + SP2のPentium4 2.8Gz、メモリ512MBの環境です。読み込んだdxfは「dragon.dxf」で14,786,898 バイト、108590三角形です。

Shadeバージョン読み込み時間
Shade6 REV20b62 sec
Shade7.559 sec
Shade8.559 sec
Shade9.0.270 sec

やはり、体感でもShade9が遅いです。ただ、どう考えても時間がかかりすぎな感じがしますので、さくっと自前でdxfインポータ作ってみます。

ちなみに自分のレンダラ(not Shade)に同dxfを読み込むときの速度は、上と同じ環境にて「1.8 sec」、レンダラに三角形情報を渡す時間は「1.2 sec」くらいです。まとめても3秒くらいでしょうか。Shadeの場合は20倍以上は速度アップできそうな気がしますが・・・。実験してみます。

ShadeプラグインSDKでの歴代パフォーマンスチェック(2007/03/27)

Shadeのフォーラムの検証のため、パーティクルフィジックスのサンプルムービーを作ったのですが気になった点があったのでテストしてみました。

Shade9のCD-ROMについているshdファイル「Object/07_Implement/car_mori09.shd」を使って、この車形状をポリゴンにコンバートする時間を計測。Shade9でのボトルネックを探ります。

ソースコード(ただし、古いバージョンで動作させるためShade6のプラグインSDK用):

http://ft-lab.ne.jp/files/shade/ShapeConvertTest_shade6_src_20070327.zip

ポリゴンメッシュ形状の場合は

polygon_mesh_class *pMesh = (polygon_mesh_class *)&(pShape->get_polygon_mesh());
compointer<shape_saver_interface> shapeSaver(pMesh->create_shape_saver_interface());

を使って「shapeSaver->get_anchor_point(loop);」にて頂点座標を取得、

自由曲面の場合(ポリゴンメッシュ以外)は

compointer<polygon_mesh_interface> mesh(pShape->create_converted_polygon_mesh_interface());
polygon_mesh_class *pMesh = &(mesh->get_polygon_mesh());
compointer<shape_saver_interface> shapeSaver(pMesh->create_shape_saver_interface());

を使ってポリゴンに変換しています。

一応、ダミー的に頂点および面の頂点インデックスは取得してます。そのときの車データがすべて変換し終わるまでの時間を計測します。

テスト環境は、Windows XP + SP2のPentium4 2.8Gz、メモリ512MBの環境です。

Shadeバージョンコンバート時のオブジェクト数頂点総数面総数処理時間
Shade6 REV20b283個4127229377562 ms
Shade7.5283個4127129377416 ms
Shade8.51個3002227969964 ms
Shade9.0.21個29828557513181 ms

考察

  • Shadeバージョンによって変換の挙動が違う。
  • Shade8以降は、「create_converted_polygon_mesh_interface」にてパート内の形状がひとまとめにされている(仕様が変わっただけ?)。
  • コンバートの速度がShade9では(9.0.1でもほぼ同じでした)、Shade7.5からみて7倍以上遅くなっている。

ちなみにShade9「パーティクルフィジックス」にて「物理設定」のカスタム情報を選択した直後に、このコンバート処理を行っているのですが(レンダリング前も同様)大部分がこのコンバート処理で時間がかかってます。つまり、このポリゴンコンバート機能がボトルネックになっていると思われます。

ということで、思い出したようにShadeのパフォーマンスチェックを行うことにします。今のところ気になる点として、

  • DXFの読み込み(インポート)が異常に遅い
  • ハイパースレッド環境だとShade9ではちらつきが激しい?
  • Shade6にくらべてShade9はもっさりしている(たぶんGDI+部。以前ちらっと調査したのですが基本的にもっさりしてるので使わないのが吉です。)。

などがあります。

一応ですが、表に出せるShade情報なども気が向いたら出していきます。

IPA関連のサイトを更新(2007/03/27)

IPA2006年下期関連のプロジェクトサイトを更新しました。

http://hbbox.net/pubwiki/wiki.cgi

日記が往々にして進まないため、Wikiです(ここと同じFreeStyleWiki)。誰に対して言うわけでもないですが、私は代表でなくて共同開発者です。ただ、失敗はゆるさねぇ!!それだけ宣言しておきます(苦笑)。

続続続続続続・AS3.0でのポリゴン描画(2007/03/26)

テクスチャ貼り付けました。パースペクティブ補正も行ってます(なんで、ピクセル単位の処理です)。これも重いので別ページに退避(>>テスト置き場(2007/03/26))。テクスチャあり・なし、であんまり速度低下はないですね。というよりも、やはりボトルネックは「new」(というかガベージコレクション?)かなぁ。

ということで、ソースコードを公開します。

http://ft-lab.ne.jp/files/flash/FlashRender_src_20070326.zip

煮るなり焼くなり好きなようにご利用ください(重いから使えないか(^_^;;)。Flash(Flex)関連で盛り上がってほしいなぁ、というのが本心としてありますのでこのあたりはできるかぎり積極的に公開していきます。「beginBitmapFill」は使ってないのですが、使う場合はnewの使用に気をつければ(というよりも、極力newの使用は避ける)たぶんもうちとパフォーマンスは得られるかな?ただし、テクスチャのゆがみはなんともしがたいかもしれませんが。。。

http://faces.jp/

によると、ColorMatrixFilterにて面白い効果を出せるようです。なんかできそう、と思ってたのですがこいつでポリゴン関連の処理は高速化できないかな?

と、Flex2で3Dを掘っても先に進みませんので(これはパフォーマンスチェックのためのテストですので)、そろそろFlashゲームのほうを進めていきます。3Dではなくて、2Dのシューティングなので今までやってきたのとは別方向です(^_^;;。

東京に戻ってきました(2007/03/25)

新潟から戻ってきました。そのことの日記はmixiに。

さて、来月4月から会社のblogにてFlex2でのゲーム開発奮闘記を書いていく予定なのですが、まだネタ仕込ができてないっす(^_^;;。シューティングを予定してるのですが、そもそも本職の仕事との関係で安定して書いていけるだろうか?ここのft-lab.ne.jpの日記と並列できるのか、本職とFlex2ゲーム、IPAと3つ巴の両立ができるか、などなどなんか課題が多いです(苦笑)。

そうそう、そろそろIPAの技術情報ページは公開予定にしてます(日記ではネタがなかなか出せないので、結局技術情報を出す都合上FreeStyleWikiで管理)。

田舎に帰省します(2007/03/21)

時にはプログラムの話題をし、ときにはある意味掲示板になるこの日記(実は、ひそかに分かる人にはわかる連絡手段になってたり。裏を読んだら、仕事の内容や戦略も薄っすら分かってしまうという(^_^;;)。

田舎のおばあちゃんが亡くなったため、今週末急遽田舎に帰ります。たぶん来週には東京に戻ってくるかと思います(仕事が滞ることはないと思ふ)。

で、場所なんですが「新潟」なんです。親曰く、私は小さいころ万景峰(マンギョンボン)号(未だにつまらずにこの言葉を言えない・・・)のよく着く港に何回か行っていたらしい。たしかに港で散歩に連れられた覚えはあるのですが、あんまり記憶にないかもしれん。あのへんが近いです(^_^;;。佐渡島も近いので、落ち着いたときに行ってみたいなぁ。

続続続続続・AS3.0でのポリゴン描画(2007/03/20)

2248ポリゴンの形状をShade9 ==> ASに書き出して速度チェック(そんなプラグインをテスト的に作りました)。さすがに重いので別ページに退避(>>テスト置き場(2007/03/20))。celeron 1GHzマシンにて、ブラウザ実行で300ms/frame 200ms/frame 140ms/frame(速度アップしました)くらいでした。FlashPlayerでは以下な感じ。

なんだかんだいって、はじめのアップから二倍くらいは速度アップ。これが限界な感じ、かな。テクスチャ貼ってみて速度チューンしてからbeginBitmapFillでもチェック。で、一通りは調査完了の予定です。それをソースアップします(速度的に使えるかどうかは微妙・・かも)。

速度アップは、あいかわらず「newを徹底的に消す」です。ベクトルの正規化も以下のようにして、newで生成したベクトルをreturnしないように。

static public function normalize2(v:RVector3) : void {
    var fx:Number, fy:Number, fz:Number, a:Number;
    fx = v.x;
    fy = v.y;
    fz = v.z;

    a = Math.sqrt(fx * fx + fy * fy + fz * fz);
    if(a != 0.0) {
        a = 1.0 / a;
        fx *= a;
        fy *= a;
        fz *= a;
    } else {
        fx = fy = fz = 0.0;
    }
    v.x = fx;
    v.y = fy;
    v.z = fz;
}

たぶん、「Math.sqrt」も排除したほうがいいかもしれません。なんか、昔々のPC-98時代に高速化を試みていたときみたいで、懐かしいというか、なにやってんだ自分、とか思ってしまいます(^_^;;。

Apollo α(2007/03/19)

Adobe関連で。Apollo α版がリリースされてるみたいです。

http://www.itmedia.co.jp/news/articles/0703/19/news039.html

単純に言えば、クライアントサイドで動作するアプリケーションを(ブラウザをかまさずに)実行できる環境みたいですね。めぐりめぐって、クロスプラットフォームのウィジット機能を提供している、って言うとおおげさか・・・。なんとなく、原点回帰な気もしてます。動いている画面のキャプチャを見ると、たしかに普通のアプリケーション(ブラウザアプリでない)ように見えます。しかし、AdobeはWebアプリに力入れてきてますね。個人的に、ブラウザ(特にHTML)をベースにしたスタイルから解放されたいです(^_^;;。なんで、Apolloには注目してます。

beginBitmapFill関連のテクスチャ変形。

http://www.gotoandplay.it/_articles/2006/01/textureDistortion.php

続続続続・AS3.0でのポリゴン描画(2007/03/19)

グローシェーディングを行ってみました。

速度はフラット時とあんまり変わりません(自前で計算しているだけですので)。残すところはUVのみ!!同じページで複数swfはさすがに重いので、過去のは生リンクに変えました。右クリックで保存してくださいませ(サイズは256x256です。リサイズには未対応です)。

FlashPlayer9とブラウザ上での速度差(2007/03/18)

ブラウザ上のswf再生のほうが処理速度が速いのは、考えれば当たり前のことでした。ローカル実行している(Flex2に付属していた)FlashPlayer9はDebug版でしたね。なんか、ピクセル処理をしてるとこの差が大きくなるので気になってました。

関係ないですが、IPAのプロジェクトの仕様がころころ変わっているのでアレなんですけど(^_^;;、どうやらP2Pを使うことで固まりそうです(私は分散ハッシュテーブル(DHT)を勧めております)。ということで、Flash(Flex2)を使う話はボツに(<クロスドメインで通信できないので)。

でも、Flex2は個人的に続行です(会社では今勧めているところですしね)。Flex2で3D関連はまだまだ実験ものですので、クリッピング処理・UVマップ・グローシェーディングあたりがまともに出せる段階になったらソース公開しますね。

続続続・AS3.0でのポリゴン描画(2007/03/16)

コツがつかめたかもしれない・・・。Zバッファもしてるよ、ということでそのサンプル。クリッピングが実はうまいこといってないので、画面中央に収まるようにしています(処理をスキップしてるわけじゃないです。バグってるだけ(^_^;;)。

http://ft-lab.ne.jp/cgi-bin/wiki.cgi?action=ATTACH&page=%C6%C8%A4%EA%B8%C0%C6%FC%B5%AD%A1%CA2007%2F03%A1%CB&file=FlashRender%5F20070316%5F2%2Eswf

以前より2倍以上高速化。どうも、newを徹底的に排除するのがコツのような感じでした。懲りずに1ピクセルごとに計算入れてます。たぶん、beginBitmapFillのほうが速いと思いますが、一度この方法でどこまでできるか掘ってみることにします。

beginGradientFill 〜 endFill(2007/03/15)

「beginGradientFill」にて、三角形の頂点ごとにRGBを指定できるかと思って実験していたのですが・・・。

難しい・・・。これが、グレイスケールのZ値用であれば使えるのは、三頂点のZ値の最小と最大を求めておき、それを一辺を構成する2頂点に割り当て、残る頂点はZ値の中間に合うように行列を変形するからそれっぽくなるのかな、と。しかし、明示的に色が存在した場合は3点でのグラデーション自体をせん断だけでは表現できない(ゆがませられない)ってのがありそうです。

なにか手段がないかなぁと思ってますが、頂点カラーなんてある(光源処理をする)ポリゴン描画は、一ピクセルごと(補間で)処理するしかないのだろうか。

http://blog.papervision3d.org/tag/demos/
http://svn1.cvsdude.com/osflash/papervision3d/

のソースを見る限りは「beginBitmapFill」で三角形の頂点にUVを割り当てて描画してますね。「beginBitmapFill」でググると、英語のサイトで参考になりそうなのがちらほらありました(行列をいかに作るかがミソみたいです)。

でも、papervision3dを見ても光源移動のサンプルがないのを見ると、、、まだFlashで3Dはどこでも実験レベルなのかもしれませんね。速度チェックのためについつい3Dっぽいことをしてみたのですが、そろそろ仕事場のページのブログネタも更新していかないと(^_^;;。

続続・AS3.0でのポリゴン描画(2007/03/14)

ポリゴン描画を1ピクセルごと処理するのは、立方体で速いかなと思ってたのですが、ほかの形状だとえらい重い・・・(ので、キャプチャのみ。ポリゴン数が増えたのでほかのボトルネックが見えてきたのかもしれない)。

後の手段はFlashでのグラデーション塗りを使うことくらいでしょうか(だと、テクスチャを貼る場合のゆがみは避けられない問題かも)。

続・AS3.0でのポリゴン描画(2007/03/12)

http://psyark.jp/

よりヒントを得て、高速化。1フレームが40msから30msくらいに。ZバッファをBitmapDataのAlphaに割り当てて、Z情報を256段階で表現しています(なんで、RGB/Zバッファのクリア処理はBitmapDataのfillRect、およびgetPixelsでOK)。後、グラデーションの描画機能でそれなりの速度になるかな。

http://ft-lab.ne.jp/cgi-bin/wiki.cgi?action=ATTACH&page=%C6%C8%A4%EA%B8%C0%C6%FC%B5%AD%A1%CA2007%2F03%A1%CB&file=FlashRender%5F20070314%2Eswf

ちなみにポリゴン描画は1ピクセルごとに行ってます。UVを貼る場合のゆがみ回避のためにこのまま進めたほうがよいか、Flashのグラデーション描画に頼るか・・・・。

下の日記のswfは重くなるので除外してます。貼りすぎもいかんですね。

追加:2007/03/14 上記swfにて、裏面のカリングを入れました。23msくらいに。ブラウザ上のほうが、FlashPlayer9で実行するよりも速い気がする。

AS3.0でのポリゴン描画(2007/03/11)

あいかわらずBitmapDataでゴリゴリ書いてます。そろそろ速度的に厳しいか・・・。Zバッファに対応して、ポリゴン描画。マウスドラッグで回転させることができます(3/12で更新したのでswfは消しました)。

これの速度を食ってる部分の約半分は

pos = 0;
for(y = 0; y < m_height; y++) {
    for(x = 0; x < m_width; x++) {
        m_ZBuffer[pos++] = 1.0;
    }
}

のようにZバッファをクリアしてる部分だったりします。まとめてArrayに値をセットできるとか、やはりポインタが使えれば、と思ったり。BitmapData内のピクセル処理でなくて、ZソートでFlashのポリゴン描画関数を使うほうが速度的に有利なのかもしれないですね。う〜ん、Zバッファはあきらめるか・・。

しかし、HTMLの1ページ内にswf貼りすぎると、さすがに重くなりますね(汗)。

追加。

http://psyark.jp/

の方がActionScriptで3Dやってました。参考にしよう。

靖国神社(2007/03/10)

打ち合わせの帰り際に靖国神社に行ってきました。

鳥居がでかいです。一応、お賽銭してきました。公園っぽくなっているのかな、と思ったのですが意外とこじんまりとしてるんですね。

絵馬があったのですが、とあることが気になって眺めてました。絵馬にはたまにですが見たこともない字が使われていることがあります。ネットで調べると「神代文字」というものなのかな。なんか、あれは不思議な感じがします。未だに受け継いでいる人はいるのだろうか・・・。ただ、靖国神社の絵馬には神代文字はありませんでした。ハングルの絵馬がわりとありますね(ハングルって神代文字(うろ覚え、数年前に見たきり最近は見てないです)に似てるよなぁ、なにかつながりがあるのかな?)。

Flex2(AS3.0)でリアルタイムレンダラが作れるか(2007/03/08)

近々の実験テーマ。とりあえず、3次元行列・ベクトル関連はクラス化。以下、マウスドラッグで回転できます。

はじめ、1フレームが30msで、画面の消去だけで22msくらいとってました(Celeron 1.0GHzのノートPCにて)。

画面クリアはByteArrayを

public function clear(col:RColorRGBA) : void {
   var x:int, y:int, pos:int;
   var rr:int, gg:int, bb:int, aa:int;

   rr = Math.floor(col.red   * 255.0);
   gg = Math.floor(col.green * 255.0);
   bb = Math.floor(col.blue  * 255.0);
   aa = Math.floor(col.alpha * 255.0);

   pos = 0;
   for(y = 0; y < m_height; y++) {
       for(x = 0; x < m_width; x++) {
           m_Buff[pos] = aa; pos++;
           m_Buff[pos] = rr; pos++;
           m_Buff[pos] = gg; pos++;
           m_Buff[pos] = bb; pos++;
       }
   }
}

な感じで塗りつぶしていたのですが、この二重ループがネックです。

で、BitmapDataのfillRectでの塗りつぶしとgetPixelsを使うことで、このクリア処理が5msに。

合計で、バッファクリア処理(5ms) + 描画処理(3ms) + setPixels(5ms)で約13msくらいまで短縮。

一応、Zバッファも考慮できるようにしました(まだ実装が途中ですがポリゴン描画もできてます)。ただ、、、ピクセル操作がネックだなぁ。ループと代入処理は負荷が高い気がするので、どう回避しようか・・・。ポインタが使えればいいんだけど、う〜む。

ActionScriptの参照(2007/03/07)

たとえば、「import flash.geom.*;」でPointクラスを使えるようにして以下のようにしたとします。

var v1:Point = new Point(1, 2);
var v2:Point;

v2 = v1;
trace(String(v2.x) + ", " + String(v2.y));

この場合は、v2はv1の参照になり、traceの出力は「1, 2」と出ます。

ここで、

v1.x = 4;

とするとどうなるでしょう?v2はv1の参照であるのでv2のx自体が変化するはずです。結果は想像通り「4, 2」と出ます。

では、

var v1:Point = new Point(1, 2);
var v2:Point;

v2 = v1;
v1 = null;
trace(String(v2.x) + ", " + String(v2.y));

として、参照の元をnullにするとどうなるでしょう?これも「1, 2」となります。これは、v1という入れ物にnullを入れただけで、参照元はまだ消えていないのですね。きちんと解放するには、

v1 = null;
v2 = null;

とします。これで、ガベージコレクションでの破棄対象となるようです。これは実はJavaと同じ動きですが、このへんをきちんと把握しておかないとどんどんメモリを食ってしまうなぁと。とりあえずはきっちりと解放したい場合は、参照元も参照先もnull入れたれ、ですね。

var v1:Point = new Point(1, 2);
var v2:Point;

v2 = v1;               // v2 = (1, 2)
v1 = new Point(3, 4);  // v1 = (3, 4)
                       // v2 は (1, 2)のまま残る。

みたいにすると、v2はv1の内容が残って事実上クラスの中身をコピーしたように扱えます。クラスを使いまわす場合は、とりあえず問題ない、かな?(なんか、解放し忘れでカオスになる気もしないでもないですが)

fcsh(2007/03/07)

仕事場の人が探してくれた情報ですが、Flex2のコンパイルは遅いです。高速にコンパイルするツールとして「fcsh」というのがあります。

http://labs.adobe.com/wiki/index.php/Flex_Compiler_Shell

コンパイルをかなりアクセラレートできます。ということで、手放せないものになりました(笑)。

今は仕事の都合上(というよりもIPAのプロジェクトですけど。と、趣味の矛先がここにある)、Flex2にどっぷりはまってます。もう構文はある程度把握できていて、後は組むだけ。ちょっと面白いものを先駆けて公開しようかと(ゲームじゃないよ。というか、ゲームも作りたいので近々手を出す予定です)。

Flex2でのコンポーネントの配置(2007/03/04)

Flex2でのコンポーネント(コントロール)は、リファレンスを見る限りパッケージの「mx.controls」に含まれています。一通りそろってるので、たとえば

var my_button:Button = new Button();
my_button.text = " ぼたん ";
addChild(my_button);

として使えるか、というとこれが使えませんでした。

どうやら、AS3.0では「MXML」というXMLファイルでデザインするのが推奨のようです。ただ、「それじゃあ使えねぇ!!」という場合が多いです。

自由に配置がしたい(プログラム内で)!!ということで、その方法を調べてみました。

http://uenon.jp/blog/archives/2006/08/flex2componenta.html

ここに記事がありますが、天邪鬼的に実装してみましょう。

プッシュボタンを使いたい!

MXMLを記述します。これに関してはネットでも資料が豊富ですので。ボタンを配置するだけのもの。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    viewSourceURL="src/LayoutAutomatic/index.html"
    horizontalAlign="center" verticalAlign="middle" 
    width="380" height="150"
>
       <mx:Button id="myButton" label="ぼたん" />
</mx:Application>

これを「MyTest.mxml」みたいなファイル名で保存(UTF-8で保存のこと)。

mxmlc --strict=true  --keep-generated-actionscript --file-specs MyTest.mxml

で、コンパイルします。このとき「--keep-generated-actionscript」のオプション指定により、generatedディレクトリに中間的なASファイルが吐き出されます。このmxmlファイルは、あくまでもデフォルトのstyleを取るためだけに今回は使いますので、一回ASファイルからスタイル設定を取り出せば後は不要です。

この生成されたファイルのうち「_globalStyle.as」「_ButtonStyle.as」ファイルを見て、スタイル設定が羅列されているのが分かるかと思います。これを使います。長いけど、ほとんどがsetStyleです。なお、開始クラスは「extends Application」としてください。Spriteだとその上にUIコンポーネントをaddChildできませんので。

package {
   import flash.display.*;
   import flash.utils.*;
   import flash.events.*;
   import flash.text.*;
   import mx.controls.*;
   import mx.core.*;
   import mx.events.FlexEvent;
   import mx.skins.halo.HaloBorder;
   import mx.styles.StyleManager;

   public class UIControlTest extends Application {
       private var m_button:Button;
       
       public function UIControlTest() {
           // thisに値するApplicationクラスの初期設定
           // これがないと、コンポーネントは配置できない(エラーになる)
           super();
           
           this.layout = "absolute";   // 子のコンポーネントは絶対位置指定
           this.setStyle("borderSkin",mx.skins.halo.HaloBorder);
           this.addEventListener(FlexEvent.APPLICATION_COMPLETE, doInit); 
       }

       /**
        * アプリケーションの初期化処理を記載
        */
       private function doInit(e:FlexEvent) : void {
           m_button = new Button();
           
           // グローバルスタイル(_globalStyle.asより抜粋)
           m_button.setStyle("fontWeight", "normal");
           m_button.setStyle("modalTransparencyBlur", 3);
           m_button.setStyle("verticalGridLineColor", 0xd5dddd);
           m_button.setStyle("borderStyle", "inset");
           m_button.setStyle("buttonColor", 0x6f7777);
           m_button.setStyle("borderCapColor", 0x919999);
           m_button.setStyle("textAlign", "left");
           m_button.setStyle("stroked", false);
           m_button.setStyle("fillColors", [0xffffff, 0xcccccc, 0xffffff, 0xeeeeee]);
           m_button.setStyle("fontStyle", "normal");
           m_button.setStyle("borderSides", "left top right bottom");
           m_button.setStyle("borderThickness", 1);
           m_button.setStyle("modalTransparencyDuration", 100);
           m_button.setStyle("useRollOver", true);
           m_button.setStyle("strokeWidth", 1);
           m_button.setStyle("filled", true);
           m_button.setStyle("borderColor", 0xb7babc);
           m_button.setStyle("horizontalGridLines", false);
           m_button.setStyle("horizontalGridLineColor", 0xf7f7f7);
           m_button.setStyle("shadowCapColor", 0xd5dddd);
           m_button.setStyle("fontGridFitType", "pixel");
           m_button.setStyle("horizontalAlign", "left");
           m_button.setStyle("disabledColor", 0xaab3b3);
           m_button.setStyle("modalTransparencyColor", 0xdddddd);
           m_button.setStyle("borderSkin", mx.skins.halo.HaloBorder);
           m_button.setStyle("dropShadowColor", 0x000000);
           m_button.setStyle("paddingBottom", 0);
           m_button.setStyle("indentation", 17);
           m_button.setStyle("fontThickness", 0);
           m_button.setStyle("verticalGridLines", true);
           m_button.setStyle("embedFonts", false);
           m_button.setStyle("fontSharpness", 0);
           m_button.setStyle("shadowDirection", "center");
           m_button.setStyle("selectionDuration", 250);
           m_button.setStyle("bevel", true);
           m_button.setStyle("fillColor", 0xffffff);
           m_button.setStyle("focusBlendMode", "normal");
           m_button.setStyle("dropShadowEnabled", false);
           m_button.setStyle("textRollOverColor", 0x2b333c);
           m_button.setStyle("textIndent", 0);
           m_button.setStyle("fontSize", 10);
           m_button.setStyle("openDuration", 250);
           m_button.setStyle("closeDuration", 250);
           m_button.setStyle("kerning", false);
           m_button.setStyle("paddingTop", 0);
           m_button.setStyle("highlightAlphas", [0.3, 0]);
           m_button.setStyle("cornerRadius", 0);
           m_button.setStyle("horizontalGap", 8);
           m_button.setStyle("textSelectedColor", 0x2b333c);
           m_button.setStyle("paddingLeft", 0);
           m_button.setStyle("modalTransparency", 0.5);
           m_button.setStyle("roundedBottomCorners", true);
           m_button.setStyle("repeatDelay", 500);
           m_button.setStyle("selectionDisabledColor", 0xdddddd);
           m_button.setStyle("fontAntiAliasType", "advanced");
           m_button.setStyle("focusSkin", mx.skins.halo.HaloFocusRect);
           m_button.setStyle("verticalGap", 6);
           m_button.setStyle("leading", 2);
           m_button.setStyle("shadowColor", 0xeeeeee);
           m_button.setStyle("backgroundAlpha", 1.0);
           m_button.setStyle("focusAlpha", 0.4);
           m_button.setStyle("borderAlpha", 1.0);
           m_button.setStyle("focusThickness", 2);
           m_button.setStyle("themeColor", 0x009dff);
           m_button.setStyle("backgroundSize", "auto");
           m_button.setStyle("indicatorGap", 14);
           m_button.setStyle("letterSpacing", 0);
           m_button.setStyle("fontFamily", "Verdana");
           m_button.setStyle("fillAlphas", [0.6, 0.4, 0.75, 0.65]);
           m_button.setStyle("color", 0x0b333c);
           m_button.setStyle("paddingRight", 0);
           m_button.setStyle("errorColor", 0xff0000);
           m_button.setStyle("verticalAlign", "top");
           m_button.setStyle("focusRoundedCorners", "tl tr bl br");
           m_button.setStyle("shadowDistance", 2);
           m_button.setStyle("repeatInterval", 35);

           // ボタンのスタイル(_ButtonStyle.asより抜粋)
           m_button.setStyle("paddingLeft", 3);
           m_button.setStyle("fontWeight", "bold");
           m_button.setStyle("upSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("verticalGap", 2);
           m_button.setStyle("overSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("selectedDisabledSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("textAlign", "center");
           m_button.setStyle("cornerRadius", 4);
           m_button.setStyle("selectedDownSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("paddingRight", 3);
           m_button.setStyle("selectedUpSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("selectedOverSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("downSkin", mx.skins.halo.ButtonSkin);
           m_button.setStyle("horizontalGap", 2);
           m_button.setStyle("disabledSkin", mx.skins.halo.ButtonSkin);
           
           m_button.label = " UIぼたん ";
           m_button.x = 20;
           m_button.y = 30;
           addChild(m_button);
           
           // イベント処理
           m_button.addEventListener(MouseEvent.CLICK, clickButton, false, 0, true);
       }

       /**
        * ボタンが押されたときに呼ばれるコールバック
        */
       private function clickButton(event:Event) : void {
           trace("Push OK!");
       }
   }
}

コンストラクタでボタンをnewしてはいけません。Applicationのコンストラクタ呼び出し(super() にて)、layoutおよびsetStyleの指定、そして、addEventListenerにてアプリケーションの初期化完了イベント時に呼び出すコールバック関数を指定します。

super();
this.layout = "absolute";   // 子のコンポーネントは絶対位置指定
this.setStyle("borderSkin",mx.skins.halo.HaloBorder);
this.addEventListener(FlexEvent.APPLICATION_COMPLETE, doInit); 

コールバック(doInit)内で、コンポーネントを生成します。

m_button = new Button();
m_button.setStyle("fontWeight", "normal");
...

と「setStyle」の嵐ですね。ですが、これは先ほどmxmlより中間的に吐き出されたasファイルからとってきて関数の引数に当てはめるだけです。ボタン以外を使う場合は、mxmlで記述してasファイル内のデフォルトスタイルをチェックをしてみましょう。

これらを記述したら、ようやく本来のxやyによる位置指定、およびaddChildへの追加が使えます。

実行結果(コンポーネントを使うと一気に100KBくらいになるので、以下はキャプチャした画像です)

いちいちsetStyleを書くのは面倒ですので、extendsで基本のUIコンポーネントをラップしたほうがいいかもしれませんね。

でも、なんでmxml推奨にして 今まで簡単に扱えた自由なコンポーネント配置を破棄してしまったのだろう・・・。(mxmlにて)型に当てはめるスタイルは当然あってもいいと思いますが、自由なスタイルは特にWebページなどではよく使うので(後、ゲームのUIとか)ターゲットとしては入れておいてほしいかなぁと。

BitmapDataのsetPixels(2007/03/03)

以下、画像のようでFlashのswfを貼り付けてます(こっちのほうが、画像を貼るよりもサイズが小さかったり。たった1KBです。jpegにしたら7KBくらいでした)。

package {
    import flash.display.*;
    import flash.text.*;
    import flash.utils.*;
    import flash.geom.*;

    public class BitmapDataTest2 extends Sprite {
        private var m_bmp:BitmapData;   // BitmapData
        
        public function BitmapDataTest2() {
            var stTim:int, endTim:int;
            var i:int;
            var x:int, y:int;
            var m_Buff:ByteArray;
            
            // テキストフィールドの作成
            var m_Text:TextField = new TextField();
            m_Text.x = 0;
            m_Text.y = 270;
            addChild(m_Text);       // シーンに追加
            
            // BitmapDataの作成(引数は幅と高さとアルファ有効フラグ)
            var m_bmpD:BitmapData = new BitmapData(256, 256, false, 0xffffff);
            var m_bmp:Bitmap;

            m_bmp = new Bitmap(m_bmpD);
            addChild(m_bmp);            // シーンに追加

            // 256 x 256ピクセル分の配列を作成
            var rec:Rectangle = new Rectangle(0, 0, 256, 256);
            m_Buff = m_bmpD.getPixels(rec);  // ARGBの32ビットで1ピクセル。
                                             // 一度読み込み(ByteArrayのnewも行われる)

            stTim = getTimer();

            i = 0;
            for(y = 0; y < 256; y++) {
                for(x = 0; x < 256; x++) {
//                  m_Buff[i] = 255;                // Alpha
                    i++;
                    m_Buff[i] = x;  i++;            // Red
                    m_Buff[i] = y;  i++;            // Green
                    m_Buff[i] = 80; i++;            // Blue
                }
            }
            m_Buff.position = 0;                // 位置を先頭にする必要がある
            m_bmpD.setPixels(rec, m_Buff);      // recの矩形領域にまとめてコピー

            endTim = getTimer();

            m_Text.textColor = 0xff0000;
            m_Text.text = "Calc : " + String(endTim - stTim) + " ms";
        }
    }
}

で、約18 msくらいの実行速度に。setPixelsはsetPixelで1ピクセルずつ繰り返すよりも速いね。もうひとつ速度アップに貢献したのが、ループの

var x:Number, y:Number;

としていた部分を

var x:int, y:int;

としました。Numberは浮動小数点値も扱える汎用数値型なので当然といえば当然でした。ということで、ループやカウンタで明示的に整数を使う場合の変数の型はintにしましょう。

BitmapDataでsetPixelsの第一引数にRectangleで範囲を指定、第二引数にByteArrayのバッファを渡すのですが、ByteArrayのpositionを先頭に持ってくる(0を入れる)、というのが必要なようです。これをしてなくて、実行時にエラーになってました(getPixelsを呼んだときに、positionが終端に来てしまってるようでした)。

BitmapDataで確保する画像領域は、アルファを使う、使わないにかかわらず「ARGB」の32ビット/ピクセルで色が表現されています。ビット操作ができるということは、3D表現も可能でしょうね。というか、すでに3Dにチャレンジしているプロジェクトはあったりします。

http://gigazine.net/index.php?/news/comments/20070212_papervision3d/

なんか、パースペクティブ補正してないのでは、というのとZソートっぽいのが気になりました。Flash内で独自でZバッファ作ってフルスクラッチするとどれくらい現実的な速度になるんだろうか・・・。少なくとも、AS3.0(Flex2)で格段にFlashで3Dは現実味をおびてきたかも。

無駄なnewはしない(2007/03/03)

先日のFlex2でのサンプルですが、Bitmapを描画する部分にて

var pos:Matrix = new Matrix();

というのを200回のループ内でいちいち行っていました。これは3 x 3行列をあらわしています(flash.geom.Matrixで定義)。

[ a b tx]
[ c d ty]
[ 0 0  1]

となっており、それぞれの要素は出し入れできます。

var pos:Matrix = new Matrix();
pos.tx = X方向の移動量
pos.ty = Y方向の移動量

みたいな感じに。で、newするのをループの外に出して

pos.tx = m_itemInfo[loop].pos.x;
pos.ty = m_itemInfo[loop].pos.y;
m_back.draw(m_image, pos);

とすることで、問題なく動作しますね。これで15 msくらいの描画間隔に。BitmapDataのdrawでのMatrixは単に引数に値を渡すだけの入れ物みたいに使ってるようですので、使いまわしてもOKのようで。Javaだと引数もnewしてあげないと同じ値になったりしたと記憶していたのですが(処理するタイミングを遅らせている(キューに積んでいっている)のかな)、その心配はなさそうです。

Flex2のBitmapDataへのdraw(2007/03/02)

Flex2での描画は、Sprite(昔のMovieClip。Flex2ではSprite推奨、かな?)を使うのとBitmapDataを使うのはどっちが一般的なんだろう・・・。ゲームなどで多重スクロールするときなどはSpriteかBitmapDataでレイヤ化して、一枚一枚に(層ごとに)背景チップ、複数のキャラを分けてdrawしたほうが楽かな。幸いBitmapDataではスクロール機能があるので、シューティングは実装しやすそうです。

以下は、200個の48 x 48pixelの画像をdrawした例。

こちらの環境では、18〜20 msということで十分使えるかも。ブラウザ上では20ms〜22msくらいで若干FlashPlayer実行よりも遅いかな(というか、誤差範囲?)

http://ft-lab.ne.jp/files/flash/ImageDrawTest_flex2_src_20070302.zip

が上記のasソースとswf、および画像リソースになります。とりあえず描画関連を実験中です。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.