Media Art II 2013  第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Media Art II 2013 第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム

  • 5,137 views
Uploaded on

 

More in: Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
5,137
On Slideshare
2,886
From Embeds
2,251
Number of Embeds
8

Actions

Shares
Downloads
67
Comments
0
Likes
8

Embeds 2,251

http://yoppa.org 1,594
http://bussorenre.hatenablog.jp 611
http://cloud.feedly.com 29
https://twitter.com 8
http://webcache.googleusercontent.com 5
http://www.google.co.jp 2
http://digg.com 1
http://feedly.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Media Art II 2013 第4回:openFrameworks アニメーションを極める 動きを生みだす様々なアルゴリズム 2013年10月7日 多摩美術大学 情報デザイン学科 メディア芸術コース 田所 淳
  • 2. 動きを生みだす様々なアルゴリズム ‣ 乱数や単純な運動だけでなく、より複雑で有機的な動きを生み だすための手法を紹介 ‣ 手持ちの表現の持駒を増やす ‣ 今後の作品制作の表現の幅を拡げる基礎体力に
  • 3. サンプルファイルのダウンロード ‣ 前回から引続き、サンプルファイルは以下のGithubからダウン ロードしてください ‣ https://github.com/tado/tau_ma2_13
  • 4. 弾力、ばね、ばねの連結
  • 5. 弾力、ばね、ばねの連結 ‣ 「ばね」を数学的に定義する ‣ フックの法則 - バネの伸びが x のとき、それによって生じる力 を F とすると ‣ F = -kx ‣ ( k:ばね定数) 振動を繰り返す(単振動) 0 x F = -kx ma = -kx x = -sin m k t x = Csin(ωt + θ)
  • 6. 弾力、ばね、ばねの連結 ‣ フックの定理は以下のように書き直すことができる ‣ springForce = -stiffness * stretch ‣ バネの力 = -バネの硬さ * バネの伸び ‣ さらに「バネの伸び」の部分を座標として解釈する ‣ springForce = -stiffness * (position - restPosition) ‣ バネの力 = -バネの硬さ * (現在位置 - ばねの静止位置)
  • 7. 弾力、ばね、ばねの連結 ‣ 式を整理 ‣ springForce = stiffness * (restPositon - position) バネの力 = バネの硬さ * (静止位置 - 現在位置) ‣ バネの力から、ばねの移動速度が導きだせる ‣ velocity = dumping * (velocity + springFroce) 速度 = 摩擦 * (速度 + バネの力)
  • 8. 弾力、ばね、ばねの連結 ‣ まずは、単体のバネを実現してみる ‣ ばねの性質をクラスとしてまとめる → springクラス ‣ 「ばね」は、2つのparticleの間に張られる ‣ Particle A と Particle B Particle A Particle B Spring
  • 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(); }
  • 12. 弾力、ばね、ばねの連結 ‣ あとは、描画するのみ!! ‣ testApp.cpp - draw()関数 void testApp::draw(){ ! ofSetColor(255, 255, 255); ! ! //ばねを描画 ! mySpring.draw(); ! ! //particleを描画 ! particle_a.draw(); ! particle_b.draw(); }
  • 13. 弾力、ばね、ばねの連結 ‣ 実行結果:空間を漂うバネが描画される ‣ マウスドラッグで操作可能
  • 14. 弾力、ばね、ばねの連結 ‣ 次に、ばねを数珠繋ぎにしてみる ‣ spring と particle をそれぞれ動的配列(vector)として作成 ‣ 全てのばねの伸縮と、それに伴なう全てのパーティクルにかか る力を計算する
  • 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(); ! } ! }
  • 18. 弾力、ばね、ばねの連結 ‣ 実行結果:数珠繋ぎになったばね
  • 19. 弾力、ばね、ばねの連結 ‣ 応用1:ばねを、円弧に数珠繋ぎにして力を加える
  • 20. 弾力、ばね、ばねの連結 ‣ 応用2:パーティクル同士をすべて接続して「筋肉」のように
  • 21. ベクトル場 (Vector Field) - 流体、磁性体の表現
  • 22. ベクトル場 (Vector Field) とは ‣ ベクトル場 (Vector Field) ‣ 空間の広がりの中でベクトル的な量の分布 ‣ 例えば… ‣ 動いている流体の早さと向き ‣ 磁力や重力などの力の強さと向きなど ‣ ベクトル場をシミュレーションできれば、流体は磁性体などの 動きを再現することが可能になるはず
  • 23. ‣ ベクトル場 (Vector Field) のイメージ ‣ 向きと方向をもった力が、グリッド上に整列している ベクトル場 (Vector Field) とは
  • 24. vectorFirldクラスの設計 ‣ まずは、ベクトル場を生成してみる ‣ vectorFieldクラス ‣ ベクトル場を生成し、座標を指定すると、その位置に働く力の 向きと方向を算出する ‣ 座標を指定して新たにベクトル場に力を加えることも可能 ‣ 外側に向う力 (噴出?) ‣ 内側に向う力 (吸引?) ‣ 渦巻のように回転する力 (時計回り、反時計回り) ‣ vectorFieldクラスのプロパティとメソッドを整理する ‣ vectorFieldの実装の詳細は省略…
  • 25. vectorFirldクラスの設計 ‣ vectorFirldクラス:プロパティ 型 変数名 内容 int fieldWidth ベクトルの数、横 int fieldHeight ベクトルの数、縦 int fieldSize ベクトルの総数 int externalWidth ベクトル場の幅 int externalHeight ベクトル場の高さ 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); 円形の力を加える
  • 28. ベクトル場を生成 ‣ testAppクラスからvectorFieldクラスをインスタンス化して、 画面にベクトル場を生成し描画する ‣ キーをタイプすると、様々な方法でベクトル場に力を付加でき るようにする ‣ 1:外向きの力 ‣ 2:内向きの力 ‣ 3:時計回りの渦巻 ‣ 4:反時計回りの渦巻 ‣ ベクトル場の力は、徐々に減衰していく
  • 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(); ! }
  • 31. ベクトル場を生成 ‣ 完成!! : 1∼ 4 のキーで加える力の向きを決定し、マウスをド ラッグしてベクトル場に力を加えてみる
  • 32. ベクトル場にパーティクルを浮遊させる ‣ 生成したベクトル場にパーティクルを配置してみる ‣ ベクトル場から、それぞれのパーティクルの座標にかかる力を 算出して、空間の力を受けて浮遊するようにしてみる ‣ 座標上にあるパーティクルにかかる力は getForceFromPos() 関数で算出することが可能
  • 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(); ! }
  • 36. ベクトル場にパーティクルを浮遊させる ‣ 完成:マウスをドラッグするとパーティクルが浮遊する
  • 37. ‣ 最初のサンプルで使用した、マウスの軌跡でドローインングす るアルゴリズムと、ベクトル場を融合する ‣ マウスをドラッグすると、ベクトル場を自由に描くことができ るように ベクトル場 + ドローイング
  • 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; }
  • 39. ベクトル場 + ドローイング ‣ 完成:空間上の粒子を指でなぞるように動かすことが可能
  • 40. ベクトル場 + ドローイング ‣ 応用:iPadなどのマルチタッチのデバイスと組み合せ ‣ MSAFluid:Memo Akten氏による流体のシミュレーション ‣ http://www.msavisuals.com/msafluid
  • 41. 生物の動き 鳥の群れをシミュレート (Boids)
  • 42. 鳥の群れをシミュレート (Boid) ‣ Boids 「鳥もどき(bird-oid)」 ‣ 1987年にCraig Raynoldsによって発表された理論 ‣ 3つのルールを規定するだけで鳥の群れをシミュレーションで きるというもの ‣ 単純な規則を用いて群体としての複雑な振る舞いを再現できる ことを示した ‣ Craig ReynoldsのBoidsの解説ページ ‣ http://www.red3d.com/cwr/boids/
  • 43. 鳥の群れをシミュレート (Boid) ‣ Boidsのルール ‣ Separation(引き離し) ‣ 近くの鳥や物体に近づきすぎたらぶつか らないように離れるルール ‣ Alingment(整列) ‣ 近くの鳥たちと飛ぶスピードや方向を合 わせようとするルール ‣ Cohesion(結合) ‣ 鳥たちが多くいる方へ向かって飛ぶルー ル
  • 44. 鳥の群れをシミュレート (Boid) ‣ このサンプルでは、particleクラス自身にBoidsのルールをメ ソッドとして追加している ‣ addForFlocking() ‣ addFlockingForce()
  • 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++; ! } }
  • 47. 鳥の群れをシミュレート (Boid) ‣ 驚くほどリアルな群れの動きが再現される