ポリゴンの三角形分割

openFramworksのofPath、最近初めて使っているのだが、想像以上にいたれりつくせりでよかった。パスと言っても直線だけでなくベジェ等色々サポートしていてofでやりにくいと感じていたベクターグラフィックが思ったより簡単に扱える。ofxSvgでSVGパースもできるし。

ofPathにはofPath::getTessellation();で一撃でmesh面を形成する機能がある。しかしこの3角系分割は、平面走査法(?)みたいな分割が行われるため、ベジェを多用した図形をテッセレートすると、短いレンジで縦方向に大きな分割が入りまくる。これだとテクスチャを貼ったりする場合の歪の原因になるし、あまりに多くの縦ラインの密集は面の色すらうっすらと変えてしまうほど。ポリゴンの変形がやりにくい状態。

三角形分割のライブラリはいろいろあったので5,6個試したところこれが一番良かった。
https://code.google.com/p/poly2tri/
穴あきポリゴンにも対応していて、C++ですんなり使えた。
パスの分割もblenderとかにある機能みたいな感じでめっちゃ綺麗に、理想的な分割をしてくれます。

Jonathan Shewchukのtriangleっていうライブラリも良かったけど、
http://www.cs.cmu.edu/~quake/triangle.html
パスを分割と言うよりはグラフィックそのものを面として分割する機能に特化した感じで、こちらは用途違いで使えそうだが、アルゴリズムの特性上パスの分割には向いてなかった。

とりあえずこれで、2Dで作った図形を3Dに押し出した。
ライブラリ無いんかいと思いながら書いた。

流れとしては、
1.パスの面をpoly2triで三角形分割(前面)
2.背面形成
3.アウトラインから側面形成
4.法線計算

ofPath -> ofMesh の変換ですね。
ベジェとかを使っているので、30度未満の角のみスムーズ法線で、綺麗な押し出しが完成しました。addon化しよっと。

OpenMPでプチ高速化

久しぶりにOpenMPをやってみたのでメモ。GPUシェーダ、CUDAとか使ってみてるけど、OpenMPが一番簡単にできる並列コンピューティングの環境だなと。でもCUDAは体感がすごかったけどOpenMPではイマイチ早くなった気がしないよ。最適化が不十分なんだろうけど。

使い方のメモ。*VS2010
構成プロパティのC/C++、[言語]のなかのOpenMPサポート有効にする

mpsetting

ヘッダインクルード

#include <omp.h>

ソース多分こんなかんじになった。
ピクセル内部で何かを探す処理。Y移動を並列化するやつを抜粋。

	int y;
	const size_t height= 1024*2;
	const size_t width = 1024*2;
	bool founded=false;
#ifdef _OPENMP
	omp_lock_t myLock;
	omp_init_lock(&myLock);
#pragma omp parallel for
#endif
	for (y=0;y<height;y++) {
		int x;
		float rf,gf,bf;
		bool flg;
		for (x=0;x<width&&!founded;x++) {
			//処理
			if(発見)founded= true;
		}
#ifdef _OPENMP
		omp_set_lock(&myLock);
#endif
		if(!founded){
			founded=true;

#ifdef _OPENMP
			printf(" [OMP:%i]", omp_get_thread_num());
#endif
		}
#ifdef _OPENMP
		omp_unset_lock(&myLock);
#endif
	}

ソースの改修が少ないまま並列化できるのがメリット。並列スレッド数は多分最近のPCでも8とかだからCPUコア数依存かな?。色々試したところ、上記のようにループサイズが小さいとあまり効果がない気がした。割と処理大きめに並列化したほうが良さげだと感じてる。今回の並列で検索するロジックはどこかで見つかった場合処理を終了させるため、見つからないスレッドが破棄され無意味になっている。それぞれで別検索を行わせて各スレッドに結果が出せるように組んだほうが良いと思った。何ゆってるかわからないけどそういうことだと思う。あと、

・ループ外側で定義する変数は共通化されるので定義する場所に注意。
・共用変数の変更はロックが使える。
・goto,breakは内部では使えるけど、脱出はできない。
 なんかそれ専用のコマンドがあるっぽい。
・Forの終了条件は確実性が求められる。 

丁寧にコーディングすればあまり間違いがおこならいので、ちょっとした並列化には効果ありそう。次回は色々ベンチマークとって効果的な書き方を検証していこうと思う。
タスクマネージャ。8コア全部が100%に。こうやって見ると仕事してる感は出てるよね。
でもやっぱGPGPUのがおもしろいなぁ。

mpsetting

GTX660TI導入

ブログ三日坊主になりつつあるので近況報告でも・・・
グラボを買った。

IMG_7006[1]

Windwowsエクスペリエンス。グラボ最高点。
SSDがボトルネック。

exp

いいわこれ。

けっきょくのところハード更新すんのもひとつの解決策です。
色々遊べそう。ブフフ

OpenNI2+NITE2を試す

会社でのお仕事。PrimeSense x Openframeworks で作ってる。
体の動きにあわせて文字が動く。みたいな。

2013-02-07 15.49.02

これ系のセンサーについてはこの一年かなり使い倒したなー。Kinectも。感覚的には、OpenNIよりWindowsSDKのほうが扱いやすいし安定感はある。でも使えるのはやっぱOpenNIだ。スケルトンの認識数で有利だし、ハードがごつくない。IRカメラは開発元同じっぽい(?)けどASUSのXTIONはKinectよりもRGBが綺麗だと思う。(kinectはなぜか標準でジャギが目立つ)

このセンサー認識精度も優秀なんだけど、こういう展示作品にする場合、プレイヤーの後ろに人だかりができてしまって、プレイヤーまで認識精度が落ちる。というのは、認識のトリガーのようなものはあくまで動きなので、カメラ的に背景が動いてるとやっぱ認識が悪くなる。一回精度が落ち始めるとなかなか復活しない。なのでセンサーを定期的にリセットしたいのだけど、そういうAPIがなかった。センサーを完全にシャットダウンすることはできるけど、時間がかかりすぎる。
で、今回OPENNI2+NITE2 という構成に載せ替えてみた。ofxアドオンになかったので、主要処理はサンプルから移植。NITE2ではのUserTrackerをいったん破棄して再構築することでセンサーのリセットが可能になってた。この場合のリセットは2秒ぐらいかかる。

で、様子をみてるけどnite2.dllがたまにエラーを吐いて落ちる見たい。悩ましいなー。

実験:unsigned char – float変換編

画像処理の高速化はshaderでやれというツッコミは置いておいて、(shaderでは色はそもそもfloat値なので関係ない。)unsigned char – float変換はよく使うし、出現頻度が多い。これは精度の都合で 0-255(8bit)を0.0f-1.0fとしてfloat精度で取り扱うことで画質ロスを無くし、かつ高速なfloat演算にあやかるというもの。で、今回は1.0f/255.0f-255.0f/255.0fの計算結果を配列にしておいてunsigned charをインデックスにして取得したら高速になるんじゃない?っていう仮説。あんま意味ないのでこのエントリーは読まないほうがいいwww

いわゆる下記のようなケース
この時点で掛算しか使ってないので、意味無さそうだよな・・・。
単純に掛算VS配列の結果呼び出しっていうテストになってる。


//byte から float
unsigned char b=128;
float f=b*0.003921568627451f; // *1.0f/255.0f

適当に配列を用意し、constで計算しておく。
一応if分岐しまくるfloat2Byteも作ったけど面倒なので貼らない。

#pragma once
class KCast
{
public:
 static float b2Float(unsigned char in);
 static unsigned char f2Byte(float in);
 static const float b2fMap[256];
};

const float KCast::b2fMap[256]={
 0.0f/255.0f,1.0f/255.0f,2.0f/255.0f,3.0f/255.0f,4.0f/255.0f,
 5.0f/255.0f,6.0f/255.0f,7.0f/255.0f,8.0f/255.0f,9.0f/255.0f,
 10.0f/255.0f,11.0f/255.0f,12.0f/255.0f,13.0f/255.0f,14.0f/255.0f,
 15.0f/255.0f,16.0f/255.0f,17.0f/255.0f,18.0f/255.0f,19.0f/255.0f,
 20.0f/255.0f,21.0f/255.0f,22.0f/255.0f,23.0f/255.0f,24.0f/255.0f,
 25.0f/255.0f,26.0f/255.0f,27.0f/255.0f,28.0f/255.0f,29.0f/255.0f,
 30.0f/255.0f,31.0f/255.0f,32.0f/255.0f,33.0f/255.0f,34.0f/255.0f,
 35.0f/255.0f,36.0f/255.0f,37.0f/255.0f,38.0f/255.0f,39.0f/255.0f,
 40.0f/255.0f,41.0f/255.0f,42.0f/255.0f,43.0f/255.0f,44.0f/255.0f,
 45.0f/255.0f,46.0f/255.0f,47.0f/255.0f,48.0f/255.0f,49.0f/255.0f,
 50.0f/255.0f,51.0f/255.0f,52.0f/255.0f,53.0f/255.0f,54.0f/255.0f,
 55.0f/255.0f,56.0f/255.0f,57.0f/255.0f,58.0f/255.0f,59.0f/255.0f,
 60.0f/255.0f,61.0f/255.0f,62.0f/255.0f,63.0f/255.0f,64.0f/255.0f,
 65.0f/255.0f,66.0f/255.0f,67.0f/255.0f,68.0f/255.0f,69.0f/255.0f,
 70.0f/255.0f,71.0f/255.0f,72.0f/255.0f,73.0f/255.0f,74.0f/255.0f,
 75.0f/255.0f,76.0f/255.0f,77.0f/255.0f,78.0f/255.0f,79.0f/255.0f,
 80.0f/255.0f,81.0f/255.0f,82.0f/255.0f,83.0f/255.0f,84.0f/255.0f,
 85.0f/255.0f,86.0f/255.0f,87.0f/255.0f,88.0f/255.0f,89.0f/255.0f,
 90.0f/255.0f,91.0f/255.0f,92.0f/255.0f,93.0f/255.0f,94.0f/255.0f,
 95.0f/255.0f,96.0f/255.0f,97.0f/255.0f,98.0f/255.0f,99.0f/255.0f,
 100.0f/255.0f,101.0f/255.0f,102.0f/255.0f,103.0f/255.0f,104.0f/255.0f,
 105.0f/255.0f,106.0f/255.0f,107.0f/255.0f,108.0f/255.0f,109.0f/255.0f,
 110.0f/255.0f,111.0f/255.0f,112.0f/255.0f,113.0f/255.0f,114.0f/255.0f,
 115.0f/255.0f,116.0f/255.0f,117.0f/255.0f,118.0f/255.0f,119.0f/255.0f,
 120.0f/255.0f,121.0f/255.0f,122.0f/255.0f,123.0f/255.0f,124.0f/255.0f,
 125.0f/255.0f,126.0f/255.0f,127.0f/255.0f,128.0f/255.0f,129.0f/255.0f,
 130.0f/255.0f,131.0f/255.0f,132.0f/255.0f,133.0f/255.0f,134.0f/255.0f,
 135.0f/255.0f,136.0f/255.0f,137.0f/255.0f,138.0f/255.0f,139.0f/255.0f,
 140.0f/255.0f,141.0f/255.0f,142.0f/255.0f,143.0f/255.0f,144.0f/255.0f,
 145.0f/255.0f,146.0f/255.0f,147.0f/255.0f,148.0f/255.0f,149.0f/255.0f,
 150.0f/255.0f,151.0f/255.0f,152.0f/255.0f,153.0f/255.0f,154.0f/255.0f,
 155.0f/255.0f,156.0f/255.0f,157.0f/255.0f,158.0f/255.0f,159.0f/255.0f,
 160.0f/255.0f,161.0f/255.0f,162.0f/255.0f,163.0f/255.0f,164.0f/255.0f,
 165.0f/255.0f,166.0f/255.0f,167.0f/255.0f,168.0f/255.0f,169.0f/255.0f,
 170.0f/255.0f,171.0f/255.0f,172.0f/255.0f,173.0f/255.0f,174.0f/255.0f,
 175.0f/255.0f,176.0f/255.0f,177.0f/255.0f,178.0f/255.0f,179.0f/255.0f,
 180.0f/255.0f,181.0f/255.0f,182.0f/255.0f,183.0f/255.0f,184.0f/255.0f,
 185.0f/255.0f,186.0f/255.0f,187.0f/255.0f,188.0f/255.0f,189.0f/255.0f,
 190.0f/255.0f,191.0f/255.0f,192.0f/255.0f,193.0f/255.0f,194.0f/255.0f,
 195.0f/255.0f,196.0f/255.0f,197.0f/255.0f,198.0f/255.0f,199.0f/255.0f,
 200.0f/255.0f,201.0f/255.0f,202.0f/255.0f,203.0f/255.0f,204.0f/255.0f,
 205.0f/255.0f,206.0f/255.0f,207.0f/255.0f,208.0f/255.0f,209.0f/255.0f,
 210.0f/255.0f,211.0f/255.0f,212.0f/255.0f,213.0f/255.0f,214.0f/255.0f,
 215.0f/255.0f,216.0f/255.0f,217.0f/255.0f,218.0f/255.0f,219.0f/255.0f,
 220.0f/255.0f,221.0f/255.0f,222.0f/255.0f,223.0f/255.0f,224.0f/255.0f,
 225.0f/255.0f,226.0f/255.0f,227.0f/255.0f,228.0f/255.0f,229.0f/255.0f,
 230.0f/255.0f,231.0f/255.0f,232.0f/255.0f,233.0f/255.0f,234.0f/255.0f,
 235.0f/255.0f,236.0f/255.0f,237.0f/255.0f,238.0f/255.0f,239.0f/255.0f,
 240.0f/255.0f,241.0f/255.0f,242.0f/255.0f,243.0f/255.0f,244.0f/255.0f,
 245.0f/255.0f,246.0f/255.0f,247.0f/255.0f,248.0f/255.0f,249.0f/255.0f,
 250.0f/255.0f,251.0f/255.0f,252.0f/255.0f,253.0f/255.0f,254.0f/255.0f,
 255.0f/255.0f
};

float KCast::b2Float(unsigned char in){
 return *(b2fMap+in);
}

実験。
適当にたして割るだけのループ。関数キャストと普通の掛算による計算を各10回ずつ。
関数のオーバヘッドもありそうなのでメモリを直接読むテストも加える。


int main(){
  const float div=1.0f/255.0f;
  unsigned long long start;
  float res;
  unsigned char i;

  puts("start");
  for(int x=0;x<10;x++){

    //キャスト関数で処理
    start= ofGetSystemTime( );
    res=0.0f;
    for (int m=0;m<1000000;m++){
      i=0;
      while (i<254){
        res+=KCast::b2Float(i);
        i++;
      }
      res*=div;
    }
    printf("キャスト TIME=%llu:RESULT=%e\n",ofGetSystemTime( )-start,res);

    //直接メモリ読む
    start= ofGetSystemTime( );
    res=0.0f;
    for (int m=0;m<1000000;m++){
      i=0;
      while (i<254){
        res+=*(KCast::b2fMap+i);
        i++;
      }
      res*=div;
    }
    printf("直接メモリ TIME=%llu:RESULT=%e\n",ofGetSystemTime( )-start,res);

    //掛算のみ
    start= ofGetSystemTime( );
    res=0.0f;
    for (int m=0;m<1000000;m++){
      i=0;
      while (i<254){
        res+=i*div;
        i++;
      }
      res*=div;
    }
    printf("かけざん TIME=%llu:RESULT=%e\n",ofGetSystemTime( )-start,res);
  }
  return 1;
}

結果

start
キャスト TIME=2459:RESULT=4.960788e-001
直接メモリ TIME=729:RESULT=4.960788e-001
かけざん TIME=724:RESULT=4.960788e-001
キャスト TIME=2435:RESULT=4.960788e-001
直接メモリ TIME=722:RESULT=4.960788e-001
かけざん TIME=716:RESULT=4.960788e-001
キャスト TIME=2396:RESULT=4.960788e-001
直接メモリ TIME=721:RESULT=4.960788e-001
かけざん TIME=747:RESULT=4.960788e-001
キャスト TIME=2419:RESULT=4.960788e-001
直接メモリ TIME=718:RESULT=4.960788e-001
かけざん TIME=716:RESULT=4.960788e-001
キャスト TIME=2398:RESULT=4.960788e-001
直接メモリ TIME=717:RESULT=4.960788e-001
かけざん TIME=718:RESULT=4.960788e-001
キャスト TIME=2395:RESULT=4.960788e-001
直接メモリ TIME=716:RESULT=4.960788e-001
かけざん TIME=718:RESULT=4.960788e-001
キャスト TIME=2403:RESULT=4.960788e-001
直接メモリ TIME=726:RESULT=4.960788e-001
かけざん TIME=721:RESULT=4.960788e-001
キャスト TIME=2411:RESULT=4.960788e-001
直接メモリ TIME=717:RESULT=4.960788e-001
かけざん TIME=715:RESULT=4.960788e-001
キャスト TIME=2397:RESULT=4.960788e-001
直接メモリ TIME=717:RESULT=4.960788e-001
かけざん TIME=720:RESULT=4.960788e-001
キャスト TIME=2395:RESULT=4.960788e-001
直接メモリ TIME=715:RESULT=4.960788e-001
かけざん TIME=717:RESULT=4.960788e-001

トリプルスコアで完敗www

結論 :

掛算は早いから計算したほうがよっぽど良い。まず関数のオーバーヘッドは大きい印象。inlineとかでこのへん少しは改善できるのかな。メモリ読み込みも検討しているけど、そもそもポインタのリードは遅い。このテストでは1-255まで順に読ませているけど連続するメモリ読み出しはかなり高速になるので、ランダムにアクセスされた場合はほぼ使えないと考えられる。

まぁ、こういう実験するとポインタ呼び出しの速度とか、身にしみて覚えるからいいよっていう話でした。
m9(^Д^)プギャー

OpenGL-Assimp-Bullet 座標系マトリクスのコンバート

進まない。ハマり気味です・・・。

マトリクス演算のクラスって便利だけど、種類が多い。
4×4のマトリクスだと、OpenGLではGlfloat[16]で始まり、assimp(3Dモデルローダライブラリ)ではaiMatrix4x4,bullet(物理演算ライブラリ)ではbtTransform。ちなみにopenFrameworksではofMatrix4x4となる。各ライブラリが独自の実装を行なっているから面倒なんだけど、回転移動スケーリング、算術オペレータなど、同じ機能があって同じ使い方ができる。色々使う場合、相互変換がちゃんとできないと困るので、下記にまとめておく。

とにかくGLfloat[16] をベースに変換していけば分かりやすい。内部的に何らかのかたちで4×4で値を保持しているわけだが、OpenGLのマトリクスをtransposeしないと使えないケースが多いので注意が必要。assimpやmascotcapsleなどもtransposeが必要だった。

まず、OpenGLの現在の状態を得る場合下記のようにする。

GLfloat m[16];
glGetFloatv(GL_MODELVIEW_MATRIX, m);

assimpに変換Transposeが必要。a1-d4の並びに注意

aiMatrix4x4 aim= aiMatrix4x4(m[0], m[1], m[2], m[3],
m[4], m[5], m[6], m[7],
m[8], m[9], m[10], m[11],
m[12],m[13], m[14],m[15]);
aim.Transpose();

もしくは

aiMatrix4x4 aim= aiMatrix4x4(m[0], m[4], m[8], m[12],
m[1], m[5], m[9], m[13],
m[2], m[6], m[10], m[14],
m[3],m[7], m[11],m[15]);

bulletに変換。関数があるので楽勝

btTransform btm;
btm.setFromOpenGLMatrix(m);

逆の場合。

assimpからGLfloat[16]

m[0]=aim.a1;
m[1]=aim.b1;
m[2]=aim.c1;
m[3]=aim.d1;
m[4]=aim.a2;
m[5]=aim.b2;
m[6]=aim.c2;
m[7]=aim.d2;
m[8]=aim.a3;
m[9]=aim.b3;
m[10]=aim.c3;
m[11]=aim.d3;
m[12]=aim.a4;
m[13]=aim.b4;
m[14]=aim.c4;
m[15]=aim.d4;

bulletからGLfloat[16]

btm.getOpenGLMatrix(m);

でもってOpenGlに適用する。

glPushMatrix();
glMultMatrixf(m);
/*描画*/
glPopMatrix();

これでbtTransformからのaiMatrix4x4とか、自由自在にできる。

Geometory Shader でB-スプライン曲線を描いてみる

3Dでスプライン曲線を描きたいというお題。

いいサンプルが見つからなかったので、とりあえずofx3DSplineをつくってみた。基本的には頂点配列を更新するとスプライン描画用頂点配列を更新してくれるクラス。でも、重かった。60fpsだと256頂点で20分割の補完が限界。これはリアルタイムに曲線をアニメーションさせ続けた場合の負荷。描画はVBOで高速にやってるのでCPUでやってるスプラインの計算がイケてないことは間違いない。他にもいろいろ計算させたいのでこれでは使い物にならない。

そこで、最近ハマってるシェーダーの登場。今回はあまり使ったことのないGeometryシェーダを使ってみる。ちなみにスプラインをやりたいのにB−スプライン曲線になってるのは力不足のため。本当にやりたいのは指定点を必ず通過するほうのスプライン曲線。こちらのほうがアニメーションでは制御しやすそうな気がしてる。あとこの分割ってところはTessellation シェーダーの役割のような気がしていて、実際できるみたいなんだけど、情報が少なかったのとATIとNvidiaで違うところがあるらしいので、今回はGeometryで。

スプラインの参考にしたのはこのドキュメント

以下、GLSL4でB-スプラインを描くジオメトリシェーダー。uniformで頂点の分割数を変更可能。


layout( lines_adjacency ) in;
layout( line_strip, max_vertices=200 ) out;
uniform int division;

vec4 w_bspline(float alpha){
 vec4 tmp;
 float a2=alpha*alpha;
 float a3=alpha*alpha*alpha;
 tmp.x = -a3 + 3.0*a2 - 3.0*alpha + 1.0;
 tmp.y = 3.0*a3 - 6.0*a2 + 4.0;
 tmp.z = -3.0*a3 + 3.0*a2 + 3.0*alpha + 1.0;
 tmp.w = a3;
 return tmp;
}

void main(void)
{
 int i;
 vec4 w;
 for (i=0; i<=division; i++)
 {
 w = w_bspline(float(i)/float(division));
 gl_Position.xyzw =
 w.x * gl_PositionIn[0].xyzw +
 w.y * gl_PositionIn[1].xyzw +
 w.z * gl_PositionIn[2].xyzw +
 w.w * gl_PositionIn[3].xyzw;
 EmitVertex();
 }
}

注意点はOPENGLのほうで、GL_LINE_STRIP_ADJACENCYを指定すること、これによってシェーダーが隣接含め4点を受け取り補完を行える。こんなかんじで。


 glEnableClientState(GL_VERTEX_ARRAY);
 glVertexPointer(3, GL_FLOAT, 0, mSplineVtx);
 glDrawArrays(GL_LINE_STRIP_ADJACENCY,0,mSplineVtxNum);
 glDisableClientState(GL_VERTEX_ARRAY);

ちなみにopenframeworksのofShaderはジオメトリシェーダーにもちゃんと対応してて、以下のように読み込めるようになってた。Tessellation はいまのところ未対応。


shader.load("myShader.vert","myShader.frag","myShader.geom");

以上でベジェ曲線の描画は上手く行ったんだけど、やっぱり重かったw。CPUでやるのとパフォーマンスそんなに変わってない。やはり若干滑らかさを犠牲にするしか無いかな。そもそもB-スプラインじゃだめだしw

参考:

Bulletでsoftbody

ソフトボディをやってみたかったので、とりあえ本買ってみた。

この本、泣けるぐらいSoftBodyの解説は少なかったわ( 3ページぐらい)w
けど、モデル(wavefront*.obj)のメッシュからsoftbody生成するサンプルがあった。まぁbulletライブラリのサンプルでもsoftbodyのサンプルいくつかあるんだけどね・・・。この本のサンプルはCode::Blocks+MinGWという構成だが、とりあえずVisualStudioで動かしてみた。

なんか表示は上手く行ってないっぽかったけど、上は柔軟体と鋼体のteapot。ぐにゃぐにゃしてる。(っぽい)
softbodyを使うためにはいつも使ってるbtDiscreteDynamicsWorld じゃなくて btSoftRigidDynamicsWorldを使う。当然RigidBodyも使えるワールドだが、softの計算もやるのでパフォーマンスをちょっと心配したけど、軽く試したところRigidについてはそんなに悪くなさそうだった。が、物体をすり抜けてしまうことが多い気がした。通常の物理演算が鋼体の衝突で実現されているのに対してこっちはMeshで頂点の当たり判定を細かくやってるイメージ。ただし、softbodyのオブジェクトの自分自身の当たり判定はほとんど突き抜けてしまっているので、判定が無いか、甘い印象。

で、いつもどおりopenframeworksで使ってみたかったので、ofxBulletで移植を始めたんだけど例のごとく先駆者がいらっしゃいました。

https://github.com/damiannz/ofxBullet/

このライブラリではassimpでロードしたメッシュをもとにsoftbodyを作るとことまでやってくれる。とてもいい。

手前のteapodがぐにゃんぐにゃんしてる。やっぱsoftbodyは突き抜けがおおい。このアドオンの調整も色々必要になりそう。あとはこれを動かしたいわけだけど、ノードがわかれば鋼体と同じ要領で特定の頂点に対して力を加えることができるようだ。

softbody ->addForce(const btVector3& forceVector,int node);

パフォーマンスは少し心配。teapotだと、最近のマシンでも10個も入れるとFPSが結構落ちてくる。あと、柔軟体をワールドに投下するタイミングでも、頂点が多いからか一瞬固まってしまうのも気になる。動きは60FPSでてれば結構気持ちがいい。なんか楽しいことはできそうだ。

Realtime slit scanの実装 (openFrameworks)

やってる途中でofxslitscanというopenFrameworks用のslitscanアドオンが見つかった。
http://jamesgeorge.org/ofxslitscan/
なんか想像してたのと違う実装方法があるっぽい。ひとまずソース読ませていただこう思う。

とりあえず、以前のエントリで書いた方法でリアルタイムのスリットスキャン実装をやってみた。
https://github.com/kentaroid/ofVideoSlitScan


うねうね動きます。

プログラムでは下記の変更ができる。
・スリットの数の調整
・スリット間のSmoothing強度(0~1)
・ミラーモード
・スキャン方向のきりかえ、(Up|Down)
・フルスクリーン表示

実際やってみてわかったのは、Smoothingのためにちょっとだけアルファ合成してもぜんぜんきれいにつながらないということ。もっと合成の方法を工夫しなければだめっぽいぞ・・・。

ofxBulletをWindowsで動かす

最近は勉強のためにofxBulletじゃなくて直bulletもやってるよー。

ちょっと前に会社のWorksでopenframework+ofxBullet+OpenNIみたいなインスタレーションを作った。その時にこの素敵addonがWindowsに対応していなくて困った。MacのSTBとかありえないし、LINUXはパフォーマンスが不安だし。とりあえずWindowsへの導入やってみたら、思ったより普通にできた。

せっかくなので、すでにありそうな気がするけど、改めて最新のbullet(2.81-rev2613)でビルドしなおして、サンプルのsln(vs2010)も作った。巷で話題のGitHubとかいうものを使ってみたかったのでこちらで公開しておきます。

https://github.com/kentaroid/ofxBullet

以下、簡単に手順をメモ。

1.bulletをwindowsでビルド
http://code.google.com/p/bullet/downloads/list から最新ソースをダウンロードしてVisualStudioでコンパイル。

2. NickHardeman/ofxBullet をfork
forkしてみたかったんです。ofxBulletのlibフォルダの所定の位置に生成された*.libとかsrcをコピー。これでライブラリの設定はほぼ完了。ただしMacとlinuxの bulletライブラリのリビジョンは違ってるので、ライブラリもコンパイルしなおさないと多分動かなくなる。その場合は元のやつ使ったら良いです。

3. サンプルのビルド
ofxBulletのサンプルの main.cpp,testApp.h,testApp.cpp を使ってopenFrameworksプロジェクトを作成。アドオンソースとかリンカにパスを通しまくる。debugも、releaseも。これが毎度のこと面倒である・・・。いい方法ないのかっていつも思うけど、最近ではライブラリ作った人に感謝しながらこの作業を行うことにしてる。(あなたのおかげでぼくはこんなたんじゅんなさぎょうでこのきのうをつかうことができますありがとうございます。) なんかマクロとかで上手くやってる人がいるらしいよ・・・。

4. ちょっとしたfix
addon、サンプルともに少しのエラーを吐く。
・キャスト方法を明示。 static_cast  -> const_cast
・ちょくちょく出てくる引数の btTransform を明示的に参照渡し。

なんだかMacでみた時と色(light)が違う気がするけど一応動いてる。ちなみに一箇所バグがあって、joint使うとアプリの終了時にAssertionされる。これは終了時に物体だけ破棄されるのにjointが開放されてないとかが原因だった気がする。前使った時は終了時にちゃんとjointでつながった物体をdeleteする前にjointをdeleteするみたいな処理をがっつり書いたら落ちなくなった。この辺も時間があれば見なおしておきます。