More Related Content Similar to Media Art II 2013 第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム Similar to Media Art II 2013 第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム (14) More from Atsushi Tadokoro More from Atsushi Tadokoro (20) Media Art II 2013 第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム1. Media Art II 2013
第4回:openFrameworks
アニメーションを極める
動きを生みだす様々なアルゴリズム
2013年10月7日
多摩美術大学 情報デザイン学科 メディア芸術コース
田所 淳
7. 弾力、ばね、ばねの連結
‣ 式を整理
‣
springForce = stiffness * (restPositon - position)
バネの力 = バネの硬さ * (静止位置 - 現在位置)
‣ バネの力から、ばねの移動速度が導きだせる
‣
velocity = dumping * (velocity + springFroce)
速度 = 摩擦 * (速度 + バネの力)
9. 弾力、ばね、ばねの連結
‣ ばねの運動は、springクラスのupdateで計算
‣ spring.cpp - update()関数
‣ フックの法則から、2つのParticleにかかる力をそれぞれ計算
void spring::update(){
! if ((particleA == NULL) || (particleB == NULL)){
! ! return;
! }
!
! ofVec2f pta = particleA->pos;
! ofVec2f ptb = particleB->pos;
!
! float theirDistance = (pta - ptb).length();
! float springForce = (springiness * (distance - theirDistance));
! ofVec2f frcToAdd = (pta-ptb).normalized() * springForce;
!
! particleA->addForce(frcToAdd.x, frcToAdd.y);
! particleB->addForce(-frcToAdd.x, -frcToAdd.y);
}
10. 弾力、ばね、ばねの連結
‣ testAppからは、2つのparticleと、それに挟まれる1つの
springを指定する
‣ testApp.cpp - setup()関数
void testApp::setup(){!
!
! ofBackground(0,0,0);
!
! ofSetVerticalSync(true);
! ofSetFrameRate(60);
! //Particle A 初期設定
! particle_a.setInitialCondition(400, 400, 0, 0);
!
! //Particle B 初期設定
! particle_b.setInitialCondition(500, 500, 0, 0);
! //ばね(spring)を、パーティクル間に張る
! mySpring.distance = 100; //ばねの長さ
! mySpring.springiness = 0.1f; //ばねの硬さ
! mySpring.particleA = &particle_a;
! mySpring.particleB = &particle_b;
}
11. 弾力、ばね、ばねの連結
‣ testAppでは、2つのparticleとspringの更新をする
‣ testApp.cpp - update()関数
void testApp::update(){
!
! //力をリセット
! particle_a.resetForce();
! particle_b.resetForce();
!
! //バネを更新
! mySpring.update();
!
! //パーティクルの状態を更新 (壁でバウンド)
! particle_a.bounceOffWalls();
! particle_a.update();
!
! particle_b.bounceOffWalls();
! particle_b.update();
}
15. 弾力、ばね、ばねの連結
‣ 数珠繋ぎのばねを生成している箇所
‣ testApp - setup() 関数内
void testApp::setup(){!
! ofBackground(0,0,0);
! ofSetVerticalSync(true);
! ofSetFrameRate(60);
! ofSetBackgroundAuto(false);
! pimg.loadImage("particle32.png");
! //particleの配列を生成
! for (int i = 0; i < 20; i++){
! ! particle myParticle;
! ! myParticle.setInitialCondition(ofRandom(500,550),ofRandom(500,550),0,0);
! ! particles.push_back(myParticle);
! }
!
! //全ての配列を順番にspringで接続していく
! for (int i = 0; i < (particles.size()-1); i++){
! ! spring mySpring;
! ! mySpring.distance = 25;
! ! mySpring.springiness = 0.2f;
! ! mySpring.particleA = & (particles[i]);
! ! mySpring.particleB = & (particles[(i+1)%particles.size()]);
! ! springs.push_back(mySpring);
! }
}
16. 弾力、ばね、ばねの連結
‣ 数珠繋ぎになった、ばねとparticleの更新
‣ testApp - update() 関数内
void testApp::update(){
! //全てのparticleの力をリセット
! for (int i = 0; i < particles.size(); i++){
! ! particles[i].resetForce();
! }
! //全てのばねの伸縮を計算
! for (int i = 0; i < springs.size(); i++){
! ! springs[i].update();
! }
!
! //全てのparticleの状態を更新
! for (int i = 0; i < particles.size(); i++){
! ! particles[i].addDampingForce();
! ! particles[i].bounceOffWalls();
! ! particles[i].update();
! }
}
17. 弾力、ばね、ばねの連結
‣ 全てのばねとpatricleを描画
‣ testApp - draw() 関数内
void testApp::draw(){
! //全てのばねを描画
! ofSetColor(255, 255, 255, 127);
! for (int i = 0; i < springs.size(); i++){
! ! springs[i].draw();
! }
!
! //全てのparticleを描画
! ofSetColor(255, 255, 255);
! for (int i = 0; i < particles.size(); i++){
! ! particles[i].draw();
! }
!
}
22. ベクトル場 (Vector Field) とは
‣ ベクトル場 (Vector Field)
‣ 空間の広がりの中でベクトル的な量の分布
‣ 例えば…
‣ 動いている流体の早さと向き
‣ 磁力や重力などの力の強さと向きなど
‣ ベクトル場をシミュレーションできれば、流体は磁性体などの
動きを再現することが可能になるはず
23. ‣ ベクトル場 (Vector Field) のイメージ
‣ 向きと方向をもった力が、グリッド上に整列している
ベクトル場 (Vector Field) とは
26. vectorFirldクラスの設計
‣ vectorFirldクラス:メソッド
メソッド名と引数・戻り値 説明
vectorField(); コンストラクタ
virtual ~vectorField(); デストラクタ
void setupField(int innerW, int innerH,
int outerW, int outerH); ベクトル場の初期化
void clear(); ベクトル場を消去
void fadeField(float fadeAmount); 徐々にベクトル場の力が減衰するようにする
void randomizeField(float scale); 全てのベクトル場の力をランダムに生成
void draw(); ベクトル場の様子を描画
ofVec2f getForceFromPos(float xpos, float
ypos); 指定した座標にかかる力のベクトルを算出
27. vectorFirldクラスの設計
‣ vectorFirldクラス:メソッド (つづき)
メソッド名と引数・戻り値 説明
void addOutwardCircle(float x, float y,
float radius, float strength);
外向きの力を加える (噴出)
void addInwardCircle(float x, float y,
float radius, float strength);
内向きの力を加える (吸引)
void addClockwiseCircle(float x, float y,
float radius, float strength);
時計回りの渦巻
void addCounterClockwiseCircle(float x,
float y, float radius, float strength);
反時計回りの渦巻
void addVectorCircle(float x, float y,
float vx, float vy, float radius, float
strength);
円形の力を加える
29. ベクトル場を生成
‣ ベクトル場の初期化
‣ testApp.cpp - setup() 関数
oid testApp::setup(){!
!
! ofSetVerticalSync(true);
! ofSetFrameRate(60);
! ofBackground(0, 0, 0);
!
! //ベクトル場の初期化 (画面いっぱいに、横102コ、縦76コのベクトル)
! VF.setupField(102, 76, ofGetWidth(), ofGetHeight());
! //初期状態は、外向きの力
! addMode = 1;
}
30. ベクトル場を生成
‣ ベクトル場の描画
‣ testApp.cpp - draw() 関数
void testApp::draw(){
! //ベクトル場を描画
! ofEnableBlendMode(OF_BLENDMODE_ADD);
! ofSetColor(0,130,130, 200);
! VF.draw();
! ofDisableBlendMode();
!
}
33. ベクトル場にパーティクルを浮遊させる
‣ ベクトル場に配置するパーティクルの初期化
‣ testApp.cpp - setup() 関数
void testApp::setup(){!
!
! ofSetVerticalSync(true);
! ofSetFrameRate(60);
! ofBackground(0, 0, 0);
!
! //パーティクルを10000個生成
! for (int i = 0; i < 10000; i++){
! ! particle myParticle;
! ! myParticle.setInitialCondition
! ! (ofRandom(0,ofGetWidth()),ofRandom(0,ofGetHeight()),0,0);
! ! particles.push_back(myParticle);
! }
!
! //ベクトル場の初期化 (画面いっぱいに、横102コ、縦76コのベクトル)
! VF.setupField(102, 76, ofGetWidth(), ofGetHeight());
!
! //初期状態は、内向きの力
! addMode = 2;
}
34. ベクトル場にパーティクルを浮遊させる
‣ ベクトル場からパーティクルにかかる力を算出する
‣ testApp.cpp - update() 関数
void testApp::update(){
!
! for (int i = 0; i < particles.size(); i++){
! !
! ! //particleの力をリセット
! ! particles[i].resetForce();
! !
! ! //ベクトル場から、それぞれのparticleにかかる力を算出
! ! ofVec2f frc;
! ! frc = VF.getForceFromPos(particles[i].pos.x, particles[i].pos.y);
! !
! ! //Particleの状態を更新
! ! particles[i].addForce(frc.x, frc.y);
! ! particles[i].addDampingForce();
! ! particles[i].bounceOffWalls();
! ! particles[i].update();
! }
!
! //ベクトル場の力の減衰
! VF.fadeField(0.998f);
}
35. ベクトル場にパーティクルを浮遊させる
‣ あとは、全てのパーティクルを描画するのみ
‣ testApp.cpp - update() 関数
void testApp::draw(){
!
! ofEnableBlendMode(OF_BLENDMODE_ADD);
!
! //ベクトル場を描画
! ofSetColor(0,130,130, 127);
! VF.draw();
!
! //ベクトル場に配置されたparticleを描画
! ofSetColor(0, 127, 255)! ;
! for (int i = 0; i < particles.size(); i++){
! ! particles[i].draw();
! }!
!
! ofDisableBlendMode();
!
}
38. ベクトル場 + ドローイング
‣ マウスをドラッグすると、その方向と距離でベクトル場に力を
加えるようにする
‣ testApp.cpp - mouseDragged() 関数
void testApp::mouseDragged(int x, int y, int button){
!
! float diffx = x - prevMouseX;
! float diffy = y - prevMouseY;
!
! VF.addVectorCircle((float)x, (float)y, diffx*0.3, diffy*0.3, 60, 0.3f);
!
! prevMouseX = x;
! prevMouseY = y;
}
40. ベクトル場 + ドローイング
‣ 応用:iPadなどのマルチタッチのデバイスと組み合せ
‣ MSAFluid:Memo Akten氏による流体のシミュレーション
‣ http://www.msavisuals.com/msafluid
42. 鳥の群れをシミュレート (Boid)
‣ Boids 「鳥もどき(bird-oid)」
‣ 1987年にCraig Raynoldsによって発表された理論
‣ 3つのルールを規定するだけで鳥の群れをシミュレーションで
きるというもの
‣ 単純な規則を用いて群体としての複雑な振る舞いを再現できる
ことを示した
‣ Craig ReynoldsのBoidsの解説ページ
‣ http://www.red3d.com/cwr/boids/
43. 鳥の群れをシミュレート (Boid)
‣ Boidsのルール
‣ Separation(引き離し)
‣ 近くの鳥や物体に近づきすぎたらぶつか
らないように離れるルール
‣ Alingment(整列)
‣ 近くの鳥たちと飛ぶスピードや方向を合
わせようとするルール
‣ Cohesion(結合)
‣ 鳥たちが多くいる方へ向かって飛ぶルー
ル
45. ベクトル場にパーティクルを浮遊させる
‣ Boidsの3つのルールを、particle.cppに追加
void particle::addFlockingForce(){
! // seperation
! if(seperation.count > 0){
! ! seperation.sum /= (float)seperation.count;
! ! float sepFrc ! = seperation.strength;
! ! frc -= (seperation.sum.normalized() * sepFrc);
! }
!
! // alignment
! if(alignment.count > 0){
! ! alignment.sum /= (float)alignment.count;
! ! float alignFrc ! = alignment.strength;
! ! frc += (alignment.sum!! * alignFrc);
! }
!
! // cohesion
! if(cohesion.count > 0){
! ! cohesion.sum /= (float)cohesion.count;
! ! cohesion.sum -= pos;
! ! float cohFrc ! = cohesion.strength;
! ! frc += (cohesion.sum.normalized() * cohFrc);
! }
!
}
46. ベクトル場にパーティクルを浮遊させる
‣ Boidsの3つのルールを、particle.cppに追加 (つづき)
void particle::addForFlocking(particle &p){
!
! ofVec3f diff, diffNormalized;
! float distance;
!
! diff! ! ! = p.pos - pos;
! distance! ! = diff.length();
! diffNormalized! = diff;
! diffNormalized.normalize();
! if( distance > 0 && distance < seperation.distance ){
! ! seperation.sum += diffNormalized;
! ! seperation.count++;
! }
!
! if( distance > 0 && distance < alignment.distance ){
! ! alignment.sum += p.vel.getNormalized();
! ! alignment.count++;
! }
!
! if( distance > 0 && distance < cohesion.distance ){
! ! cohesion.sum += p.pos;
! ! cohesion.count++;
! }
}