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

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

on

  • 3,641 views

 

Statistics

Views

Total Views
3,641
Views on SlideShare
2,082
Embed Views
1,559

Actions

Likes
6
Downloads
49
Comments
0

7 Embeds 1,559

http://yoppa.org 1286
http://bussorenre.hatenablog.jp 230
http://cloud.feedly.com 29
https://twitter.com 8
http://webcache.googleusercontent.com 4
http://digg.com 1
http://feedly.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

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