前回に引き続き、プロジェクションマッピングを試してみました。対象は前回と同じルービックキューブですが、今回は実物への投影を試してみました。
単に投影させるだけではおもしろくない、ということで、openFrameworks のAddonにある、ofxBullet という3Dの物理エンジンを用いていくつかギミックを入れてみることにしました。
投影環境はこんな感じです。
作成した映像はこちら。
実際に投影して改めて認識したことですが、、プロジェクションマッピングにおいてはキャリブレーション(マッピングのための調整)のための施策や考慮がかなり重要であるようです。
今回の場合は斜めから投影していることもあり、投影画像全体を変形して出力させるべきであったかと思いましたが、その方法が見つからなかったので、残念ながら次回までの課題となりました。実際、上面は全然合っていませんが、今回は見逃していただくということで。。
以下は映像での実現方法について説明します。映像では以下の項目の内容を試しています。
1. 投影 色変化
2. ブロックが下に落ちる(全体)
3. ブロックが下に落ちる(1つずつ)
4. ブロックの分解
5. 逆投影
27個の立方体のブロックを並べることでルービックキューブを実現しています。
最初に各ブロックの生成について説明しておきます。ブロックはvector配列で管理しています。
vector<ofxBulletBaseShape *> shapes;
以下の処理でブロックを1つ生成しています。
void testApp::addShapeBox(int x, int y, int z, float mass, float size) { shapes.push_back(new ofxBulletBox()); int i = shapes.size() - 1; ofQuaternion qt(0.0, 1.0, 0.0, 1.0); ((ofxBulletBox *)shapes[i])->create(world.world, ofVec3f(x, y, z), qt, mass, size, size, size); shapes[i]->setActivationState(DISABLE_DEACTIVATION); shapes[i]->add(); }
ポイントは mass の設定で、mass = 0.0; と設定することで、重力に影響しない固定のブロックになります。また、重力に影響する可変のブロックは mass = 1.0; で設定しています。
また、ofQuaternion を上記のように定義することで、Z軸を中心に45度回転したブロックを設置することができます。
ブロックの消去は以下の処理で行います。これでブロックの作成/消去が自在に行えます。
void testApp::deleteShape(int index) { delete shapes[index]; shapes[index] = NULL; shapes.erase( shapes.begin() + index ); }
また、映像では最初に透明の床を用意してあり、床の上にルービックキューブ状のブロックを置き、適切なタイミングで床の作成/消去を設定しています。
「2」では、全てのブロックを重力に影響する可変に設定して、床を消去することで実現しています。
「3」では、あらかじめ床を消去しておき、全てのブロックを重力に影響しない固定に設定して、ブロックを1つずつ可変な状態に生成し直すことを行っています。
「4」では、各ブロックに対して、瞬間的に力を加えることではじき飛ばされるようなアクションを実現しています。
void testApp::addShapeBox(int index) { shapes[index]->activate(); shapes[index]->applyForce(ofVec3f(100, -100, 100), ofVec3f(3, -50, 3)); }
最後の「5」ですが、可変のブロックの上から非常に重い球を落として、それに合わせて実物のボールを置くという、タイトルにもある「逆プロジェクションマッピング」というのを試してみようかと思いましたが、かなりズレてしまってますね。。まあ今回はこれでご勘弁ください。
個人的にはキャリブレーションの課題が心残りですが、それが解決すれば、いろいろおもしろいことが展開していけそうに思いました。