文字+レンダラー+ofxBullet

スクリーンショット 2014-10-09 02.37.49

レンダラーで表示する表示オブジェクトはofNodeの継承で、下記の情報を持たせた。

・マテリアル情報(マテリアルシェーダー、テクスチャ:Diffuse,Speclar,Normal,Detail)
・メッシュ(ofMeshから生成できる拡張メッシュ )
・RigidBody(ofBulletのshapeのいずれか)

このオブジェクトをFlashみたいにaddChildでレンダラインスタンスに追加できるようにしてみた。動作はofっぽくnodeで動かせるようになったし、rigidbodyを追加すれば物理空間にぶっこめる。メッシュ形状から衝突形状が生成できるofxBulletCustomShapeを使ったらいい感じになった。

スクリーンショット 2014-10-09 02.58.37

GTX660TIだと文字たくさん出しても60fpsでてたけど、 MBAだと15fpsくらいが限界・・・。

無題

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とか、自由自在にできる。

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でてれば結構気持ちがいい。なんか楽しいことはできそうだ。

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するみたいな処理をがっつり書いたら落ちなくなった。この辺も時間があれば見なおしておきます。