モデリング無しでエコに済ませる
ゲーム、プロジェクションマッピング、WEBコンテンツなどの空間の演出において雰囲気作りのために、ちょうちょを飛ばしたくね?という時がごくたまにあると思います。私はありました。
サクラの花びらとか、雪とかならば、パーティクルエンジンをつくって効率よく飛ばすことが考えれれます。しかし、ちょうちょは羽ばたくし、ある程度目的を持つ自律した動きを表現する必要があります。
これを実現するには3Dモデリングをしてボーン仕込んでキーフレームのアニメをつくって…と考えるかもしれません。
ただそれはやはり手間です。
そこでどうするかですが、コードによって単純なちょうちょの形をつくり、それをコードで動かすということを考えます。
コードといっても単純な手続き的な記述を除けば、三角を何個か描いて、動きを考えるだけなのでシンプルです。
頂点数も少ないので、リソース的にもエコでしょう。
「動き」をいかに単純化してシミュレートするかといったところのみ、ちょっとだけプログラマの腕の見せ所かもしれません。
以下、冒頭の動画での実装したソースコードになります。openFrameworks を用いています。
seek()の引数にマウス座標を設定することでマウスに追従するように動かすこともできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include "ofMain.h" class Butterfly { public: ofVec3f location; ofVec3f velocity; ofVec3f acceleration; float maxspeed; float maxforce; float wingTheta; bool wingUp; float wingSpeed; float size; Butterfly(); void seek(ofVec3f target); void applyForce(ofVec3f force); void update(); void draw(); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
#include "butterfly.hpp" Butterfly::Butterfly() { location = ofVec3f(ofRandom(800)-400, ofRandom(800)-400, 0); velocity = ofVec3f(0, 0, 0); acceleration = ofVec3f(0, 0, 0); maxspeed = ofRandom(1) + 2; maxforce = ofRandom(0.002) + 0.001; wingSpeed = ofRandom(1) + 1; wingTheta = 0; wingUp = true; size = ofRandom(15.0) + 15.0; } void Butterfly::seek(ofVec3f target) { ofVec3f desired = target - location; desired.normalize(); desired *= maxspeed; ofVec3f steer = desired - velocity; steer.limit(maxforce); applyForce(steer); } void Butterfly::applyForce(ofVec3f force) { acceleration += force; } void Butterfly::update() { velocity += acceleration; velocity.limit(maxspeed); location += velocity; acceleration *= 0; if (wingTheta < -60) { wingUp = true; } if (wingTheta > 60) { wingUp = false; } if (wingUp) { wingTheta += wingSpeed; } else { wingTheta -= wingSpeed; } } void Butterfly::draw() { ofPushMatrix(); ofTranslate(location); float theta; if (velocity.x < 0) theta = - velocity.angle(ofVec3f(0, -1, 0)); else if (velocity.x > 0) theta = velocity.angle(ofVec3f(0, -1, 0)); else theta = 0; ofRotateZ(theta); // -- left wing -- ofSetColor(255, 200); ofPushMatrix(); ofRotateY(wingTheta); ofBeginShape(); ofVertex(0, 0, 0); ofVertex(- size * 0.4, - size * 0.7, 0); ofVertex(- size, - size, 0); ofVertex(- size * 0.8, size * 0.1, 0); ofEndShape(); ofBeginShape(); ofVertex(0, 0, 0); ofVertex(- size * 0.8, size * 0.3, 0); ofVertex(- size * 0.4, size * 0.75, 0); ofEndShape(); ofPopMatrix(); // -- rigtht wing -- ofPushMatrix(); ofRotateY(-wingTheta); ofBeginShape(); ofVertex(0, 0, 0); ofVertex(size * 0.4, - size * 0.7, 0); ofVertex(size, - size, 0); ofVertex(size * 0.8, size * 0.1, 0); ofEndShape(); ofBeginShape(); ofVertex(0, 0, 0); ofVertex(size * 0.8, size * 0.3, 0); ofVertex(size * 0.4, size * 0.75, 0); ofEndShape(); ofPopMatrix(); ofPopMatrix(); } |
こういった類の演出上の小ネタを、クラスとして持っておいていつでも再利用できる状態をつくっておくと良いのかもしれません。今回のデモはopenFrameworksで作成しましたが、WebGL、Unityなどでも同様に実現できると思います。
他の方法で、調べてみて何やら可能性を感じたのは「シェーダを割り当てたパーティクルを使う」というものがありました。修行して試してみたいと思います。
参考
自律的な動きをもったクラスの実装については、上記の書籍の「Capter6 自律エージェント」を参考にさせていただきました。動きをシュミレートする基本的なアイディアとして素晴らしい内容の書籍です。