2011/06/27

Processing でマルチスレッド

最近ちょっと重たい記事が続いたので、今日は軽めにいきたいと思います。

Processing 等で大量のリソースを読み込む際、それらの処理をコンストラクタや初期化用メソッドに記述すると、フレームレートが激落ちくんになってしまいます。

例えば Cover Flow なんかも、読み込んだ画像から鏡面反射用のテクスチャを構築するため、多くの画像を表示させる場合は初期化の際のオーバヘッドが高くなってしまいます。

そこで今日は、ロード処理をバックグラウンドで動かし、表向きには『Now Loading...』的なアニメーションをぬるぬる表示させるためのちょっとした Tips をお話ししましょう。
ロード中は、進捗バーが表示されるよ

2011/06/26

いまさら DirectX10(なんちゃってオブジェクト指向篇)

昨日のソースコードが、あまりにもアレだったので、せめて DirectX の初期化関連だけでも別クラスに分けようと思いました。

本日はその成果報告です。

成果といっても、今日は簡単のためブルースクリーンを表示するだけ。昨日よりひどい
さて。

オブジェクト指向というからには、本来ならウィンドウもクラスにすべきところですが、OS からコールバックされる関数(ウィンドウプロシージャ)をメンバ関数にするにはちょっとしたトリックを仕込まねばなりません。

※ C++ において、static なメンバ関数は、暗黙のうちに自クラスへのポインタを引数として受け渡す性質があるので、コールバック関数をそのままクラスのメンバにしようとすると、『引数の数が合わないよ!』と叱られちゃうのです。

原因が判れば回避策を講じるのもそう面倒ではないのですが(たとえば追加のメッセージ処理関数を独自にフックさせるとか、あるいは思い切ってウィンドウプロシージャだけ static なメンバ関数にしちゃうとか)、それだけに極端な『オレ流ソース』になりやすく、あんまりよろしくないなぁと思ったので、ウィンドウに関してはそのまま放置にしました。

2011/06/25

いまさら DirectX10(はじめの一歩篇)

※ このブログはただのお勉強日記だよ! 参考になるような解説記事は一切ないよ!

今は昔。

ぼくもネイティブな 3D プログラミングなるものに憧れ、当時主流だった DirectX9 をつまみ喰いした事がありました。
当時、DirectX9 をあれこれ試したときに作ったプログラミングノート
あれから時代は移ろい、いつの間にか最新のトレンドも DirectX11 に代わってしまったようです。

そんなわけで、そろそろ最新の API を学び直す時期かなぁと思い立ったわけですが、残念ながらぼくのパソコン(のグラボ)は DirectX11 には対応していないので、仕方なく DirectX10 に手をつけてみる事にしました。

さてさて。

DirectX10 からは固定機能パイプラインが無くなり、プログラマブルシェーダの理解が不可欠となってしまいました。 Vista 時代を迎えてかなり思い切った仕様変更だと思います。

何を隠そう、ぼくはこのシェーダに手を付ける事が怖くて、DirectX9 の頃まではほぼ固定機能パイプラインに頼りっきりだったため、DirectX10 になって開発の敷居ががくんと上がってしまいました。

こうやってどんどん梯子を外されていくうちにゲイツ様への忠誠心が確実に薄らいでいますが、それはさておき。

今回は、おっかなびっくり DirectX10 なるものに触れてみようかと思います。

2011/06/20

Processing で Cover Flow

iTunes や iPod でおなじみの Cover Flow 効果を、Processing で再現してみました。

マウスのドラッグでフォーカスが移ります。

この Cover Flow のエフェクト、実はずっと作ってみたかったものです。

線型代数に不慣れだった頃なら、どうやって作ったらいいのか見当すらつかなかったでしょうが、今は多少なりとも理解しているつもりですので、作り始めて 30 分ほどでプロトタイプが完成しました。

かつてのぼくだったら、『たとえ汚くてもいいのでソースコードが欲しい』と願ったでしょうから、拙いながらこちらで公開しています。

2011/06/17

OpenProcessingはじめました

突然ですが、p5info さんに見習われてしまいました。非常に畏れ多いです。


私もたーせるさんを見習うべくブログを建てることにする。
今までコードはる場所なかったのが痛いな。2011年6月17日 10:8 via web


改めてご紹介すると、p5info さんは、Proce55ing.walker (Beta) で Processing 言語の情報提供に尽力されている方です。

当該サイトは日本語で読める貴重な情報源の一つですので、今後ブログが開設されたらぜひ入り浸りたいと思います。

2011/06/16

Processingで光の粒を飛ばしてみた

本日のがらくたはこちら。


一見、なんの変哲もない簡易的なパーティクルシステム。だけど、パーティクル用のテクスチャをプログラム中で動的に生成するのがちょっとしたオリジナリティだ。

ネットを適当に巡回すれば、似たようなものの作り方はいくらでも解説されているが、その殆どは予め画像処理ソフト等でテクスチャファイルを作成しておく必要がある。これを手間だと感じる人は意外に多い(と思う)。

しかし、ここでご紹介するサンプルは、そんなものをわざわざ作らなくてもソースコードをコピペするだけで動いてしまう。これを見ているよい子のみんなも手軽に試す事ができるぞ!

2011/06/15

Processingのカメラ行列にアクセスしたい

【何の役に立つか分からない技術コーナー】

Processing で 3D を扱っていて、地味に不便だなぁと感じるのが、カメラ行列(射影行列ではない)に直接アクセスできない事。

printCamera() メソッドでカメラ行列をコンソールに表示する事は可能だけど、これを眺めるだけでカメラの並進量や回転量を把握するのは、残念ながら普通の人には難しい。

加えて、そのカメラ行列をプログラム内で使う事は(現時点では)できないようである。

これができないと、たとえばデバッグカメラ(カメラ配置を第三者視点から確認する事)が多少やりづらい(工夫次第でなんとかなりそうだが)。

そこでひとまず、Processing 標準の camera() メソッドをエミュレートするものを作ってしまう事にした。

以下に当該メソッドのソースコードを示す。使い方は camera() メソッドと基本的に一緒。
// 世界座標を、カメラに合わせて動かす
// 引数の意味は、camera()メソッドと同じ
void worldToCamera() {
  worldToCamera(
    width/2.0, height/2.0, (height/2.0) / tan(PI*60.0 / 360.0), 
    width/2.0, height/2.0, 0,     
    0, 1, 0);
}
void worldToCamera(float eyeX, float eyeY, float eyeZ,
                   float centerX, float centerY, float centerZ, 
                   float upX, float upY, float upZ) {
  
  // カメラ座標空間の3軸
  PVector r3 = new PVector(eyeX-centerX, eyeY-centerY, eyeZ-centerZ);
  PVector r2 = new PVector(upX, upY, upZ);
  PVector r1 = r2.cross(r3);
  r2 = r3.cross(r1);
  
  // 正規化
  r1.normalize();
  r2.normalize();
  r3.normalize();
  
  /* ================================================== */
  /*  各軸まわりの回転量、および並進量を個別に求める例  */
  /* オイラー角表現はヘディング・ピッチ・バンクに準ずる */
  /* ================================================== */
  float h, p, b;
  p = asin(-r2.z);
  if (cos(p) != 0) {
    h = atan2(r1.z / cos(p), r3.z / cos(p));
    b = atan2(r2.x, r2.y);
  } else {
    b = 0;
    h = atan2(-r3.x, r1.x);
  }

  resetMatrix();
  rotateY(h);  // ヘディング角
  rotateX(p);  // ピッチ角
  rotateZ(b);  // バンク角
  translate(-eyeX, -eyeY, -eyeZ);

  /* ================================================== */
  // 別解:applyMatrix による一括変換の例
  /* ==================================================
  
     // 並進成分の計算
     PVector t = new PVector(
       -(eyeX * r1.x + eyeY * r1.y + eyeZ * r1.z),
       -(eyeX * r2.x + eyeY * r2.y + eyeZ * r2.z),
       -(eyeX * r3.x + eyeY * r3.y + eyeZ * r3.z)
     );
     // 変換行列の作成・適用
     resetMatrix();
     applyMatrix(r1.x, r1.y, r1.z, t.x,
                 r2.x, r2.y, r2.z, t.y,
                 r3.x, r3.y, r3.z, t.z,
                  0.0,  0.0,  0.0, 1
     );

     ================================================== */
}

このままでは camera() と一緒だけど、たとえば MyCamera クラスとかで包んでやって、カメラの並進量・回転量(あるいは行列そのもの)に対するアクセサを定義してやれば、もうちょっと高度なカメラ制御が可能になると思う。

2011/06/09

遺伝的アルゴリズムとか

ちょっと興味があったので、小高 知宏 著 『はじめての機械学習』 を読んでみた。

で。 5 章 2 節 「遺伝的アルゴリズムによる知識獲得」には、簡単な GA (SGA: Simple GA)の実装例が掲載されている。

今回は、その挙動を Processing で可視化してみた。

完成品はこんな感じ。
各世代における適応度の推移グラフをProcessingで可視化したもの。
赤はエリート個体の適応度、青は当該世代における適応度の平均値。

2011/06/06

くだけちるエフェクト(改訂篇)

先月作ったくだけちるエフェクトの改良版。

破片の形状生成アルゴリズムを Delaunay 分割に変更し、さらに各破片の飛び散り方を 3 次元的にしてみた。

2011/06/03

ProcessingでDelaunay分割(解説篇)

今日は、前回実装した Delaunay 分割のアルゴリズムをわかりやすく解説したいと思う。

まずは、前知識として 『詳解 OpenCV』 の記述をふたたび引用しよう。
  1. 外部三角形を作り、その頂点の 1 つを開始点とする(これにより、必ず外側の点から開始されることになる)。

  2. 内部の点を追加する。その後、すべての三角形の外接円を探索し、追加した点を含むような三角分割を削除する。

  3. 今削除した三角分割の外接円の内部にある、新しい点も含めて、グラフを三角分割し直す。

  4. 追加する点がなくなるまで、ステップ 2 に戻って繰り返す。
これをいかに解釈し、ソースコードに落とし込んでいくか。

計算幾何に興味がある方はもちろん、普段ネット上のソースをコピペして『動きさえすればそれでよい』と思っている方にも、この記事がプログラミングの楽しみを知るきっかけになれば幸いである(偉そうなこと言ってごめんなさいごめんなさい)。

ProcessingでDelaunay分割(ジェネリクス対応篇)

昨日まで、Processing のプログラムは、プログラマの性善説に基づいて組んでいた。

つまり、function(ArrayList pointList) とかいうメソッドがあったら、それを使う側は、間違いなく引数に PVector オブジェクトが格納されたリストを渡してくるだろうと想定していたのだ。

万一にもおかしなものが渡された場合、ClassCastExceptionNullPointerExceptionthrow されるので、それを catch するようにプログラムしてはいたけれど、やはりコレクションフレームワークに何が入れられてくるのか判らない事に対する気持ち悪さは拭えずにいた。

さてさて、そんなうららかな金曜日の昼下がり。暇だったので、Processing の最新版(1.5.1)を落として遊んでいたら、ある事に気付いた。

なんと、Processing の言語仕様がジェネリクスに対応しているではないか。

これなら、明示的に List や Map などのコレクションフレームワークに格納できる型を明示的に指定する事が可能である。

というわけで、昨日の Delaunay 分割のうち、コレクションフレームワークを駆使した DelaunayTriangles クラスを、新仕様に合わせて改訂してみた。それ以外のクラスについてはいじる必要なし。

2011/06/02

ProcessingでDelaunay分割(実装篇)

前々回のあらすじ砕け散るエフェクトを作った。

……それはよいのだが、いかんせんやっつけ仕事だったため、砕け散る破片の形状生成がびっくりするほど適当だった。

もうちょっとうまく破片を作るために、今回は計算幾何のアルゴリズムの中でも比較的有名な Delaunay 分割に挑戦してみた。

まずはじめに、結果から示そう。

Delaunay 分割は、ランダムに与えられた点を結び、下のような無数の三角形を作る手法である。


さて。

Delaunay 三角分割法に関しては、Gary Bradski, Adrian Kaehler 著、松田 晃一 訳『詳解 OpenCV』にこんな解説がある。
Delaunay 三角分割法は、空間内の点を連結して三角形のグループにし、その三角形のすべての角に対する最小角度が最大になるようにするテクニックで、1934年に発明されました。 (中略) 与えられた任意の三角形の頂点に接する任意の円の内部には、その他の頂点が含まれないようにして三角分割が行われています。これは、外接円特性と呼ばれています。
正直、さっぱり意味がわからない。Delaunay 分割を全くご存知ない読者がこれを一度読んだだけで完全理解できたら大した読解力だと思う。少なくともぼくは数日間悩んだ。

2011/06/01

Processing でイテレータ

昨日、超てきとうにあんな記事を書いたところ、Processing 日本語コミュニティサイト p5info.com の方の目に留まり、激しく恐縮していますこんにちはこんにちは。


おお、面白い RT @tercel_s: Processingで画面遷移効果(くだけちるエフェクト) http://bit.ly/mHXM0e2011年5月31日 22:53 via web

で。

p5info.com さんの他のツイートを見ていたところ、ちょうど 『Processing で学ぶデザインパターン』 とかオブジェクト指向的な話がでてきていて、『おぉっ』と思ってしまった。

個人的に、Processing はオブジェクト指向色の薄い言語だと思うけれど、それでも時と場合によってはデザインパターンを採り入れた方がプログラムしやすくなったり安全になったりするし、そういった経験則を通して設計面の楽しさを知る機会はあったほうがうれしい。

実際、たとえ意識しなくても Processing で void setup() とか void draw() を書いている時点で、Template Method パターンを利用している事になるわけで、やっぱりぼくらは知らず知らずのうちにデザインパターンの恩恵を受けている。



というわけで、今日の話題は GoF のパターンの一つである『イテレータ』について。

ただし、『イテレータを一から設計するにはどうすればよいか』という話はできないのでしない。代わりに、『それを使うと何が便利なのか』という動機づけの話をしよう。

ArrayList とか LinkedList とかを使用していて、『ある条件に一致する要素すべてをリストから削除したいなあ』というシチュエーションを考える。

たとえば、以下のようなリストから、「要素が3であるもの」をすべて除去したいとしよう(実際はもっと複雑な状況を想定している)。

intList
 3   1   2   3   3   3   7   0 

こんなとき、初心者(というか僕)が真っ先に思い浮かぶのがこんな方法だ。
// リストを作って
ArrayList intList = new ArrayList();

// 要素を設定
intList.add(new Integer(3));
intList.add(new Integer(1));
intList.add(new Integer(2));
intList.add(new Integer(3));
intList.add(new Integer(3));
intList.add(new Integer(3));
intList.add(new Integer(7));
intList.add(new Integer(0));

// 最初の中身を表示
println("intList:");
for(int i = 0; i < intList.size(); i++) {
  print(intList.get(i) + " ");
}
println();

// 3を削除?
for(int i = 0; i < intList.size(); i++) {
  Integer element = (Integer)intList.get(i);
  if(element.intValue() == 3) {
    intList.remove(element);
  }
}

// 削除後の中身を表示
println("intList:");
for(int i = 0; i < intList.size(); i++) {
  print(intList.get(i) + " ");
}
println();

しかし、実行してみると分かるが、明らかに「削除漏れ」が起きている。
【実行結果】
intList:
3 1 2 3 3 3 7 0
intList:
1 2 3 7 0
この現象は、削除すべき要素が連続しているところで発生している。