Top Banner
人工言語入門 A 第10回 高度なモーション:バネと引力 2009年6月22日 千葉商科大学政策情報学部 担当:田所淳
47
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Proga 0622

人工言語入門 A 第10回高度なモーション:バネと引力2009年6月22日千葉商科大学政策情報学部担当:田所淳

Page 2: Proga 0622

今日の内容

• 高度なアニメーション表現を身につける• 物理法則を用いたアニメーションの表現

• ばね• 万有引力

Page 3: Proga 0622

「ばね」を定義する

• 「ばね」を数学的に定義する• フックの法則

• バネの伸びが x のとき、それによって生じる力を F とすると• F = -kx • ( k:ばね定数)

振動を繰り返す(単振動)

0

x

F = -kxma = -kx

x = -sinmk t

x = Csin(!t + ")

Page 4: Proga 0622

「ばね」を定義する

• フックの定理は以下のように書き直すことができる• springForce = -stiffness * stretch

- バネの力 = -バネの硬さ x バネの伸び

• さらに「バネの伸び」の部分を解釈する• springForce = -stiffness * (position - restPosition)

- バネの力 = -バネの硬さ x (現在位置 - ばねの静止位置)

Page 5: Proga 0622

「ばね」を定義する

• 式を整理• springForce = stiffness * (restPositon -

position)

- バネの力 = バネの硬さ x (静止位置 - 現在位置)

• この時、ばねの移動速度は下記のように表現される• velocity = friction * (velocity + springFroce)

- 速度 = 摩擦 * (速度 + バネの力)

• この式を利用して、簡単なアニメーションをProcessingで作成してみる

Page 6: Proga 0622

float stiffness = 0.1; //ばねの強度float damping = 0.9; //摩擦float velocity = 0.0; //速度float targetY; //目標位置float y; //現在位置

void setup() { size(400, 400); noStroke();}

void draw() { fill(0, 12); rect(0, 0, width, height); fill(255); float force = stiffness * (targetY - y); //フックの法則 f = -kx velocity = damping * (velocity + force); //速度を計算 y += velocity; //速度分を座標に rect(10, y, width - 20, 10); //四角を描画 targetY = mouseY; //マウスのY座標を目標位置に}

ばね1:シンプルなばねを定義

• シンプルな「ばね」

Page 7: Proga 0622

ばね1:シンプルなばねを定義

Page 8: Proga 0622

ばね2:重さ(mass)を付加

• もうひとつの要素を付加する• バネに付いている物体の重さ(mass)

• 重さと力の関係はニュートンの運動の第二法則から• F = ma

• F:力、m:質量、a:加速度

• 式を変換• a = F / m

• これを「ばね」にあてはめると、下記のように解釈できる• acceleration = springForce / mass

• 加速 = バネの力 / 重さ

• 先程のプログラムに重さの要素を付加する

Page 9: Proga 0622

//2つの重さの異なる物体で、ばね運動を作成float y1, y2; //現在位置float velocity1, velocity2; //速度float mass1 = 1.0; //物体1の重さfloat mass2 = 6.0; //物体2の重さfloat stiffness = 0.1; //バネの剛性float damping = 0.9; //摩擦係数

void setup() { size(400, 400); noStroke();}

void draw() { fill(0, 12); rect(0, 0, width, height); fill(255); float targetY = mouseY; //目標位置 //物体1 float forceA = stiffness * (targetY - y1); //フックの法則 float accelerationY1 = forceA / mass1; //重さから加速度を算出 velocity1 = damping * (velocity1 + accelerationY1); //加速度を加味して速度を計算 y1 += velocity1; //位置を算出

ばね2:重さ(mass)を付加

• 重さの概念を付加した「ばね」(1 of 2)

Page 10: Proga 0622

rect(0, y1, width/2, 15); //物体2 float forceB = stiffness * (targetY - y2); //フックの法則 float accelerationY2 = forceB / mass2; //重さから加速度を算出 velocity2 = damping * (velocity2 + accelerationY2); //加速度を加味して速度を計算 y2 += velocity2; //位置を算出 rect(width/2, y2, width/2, 15);}

ばね2:重さ(mass)を付加

• 重さの概念を付加した「ばね」 (1 of 2)

Page 11: Proga 0622

ばね2:重さ(mass)を付加

Page 12: Proga 0622

ばね3:2次元座標に展開、重力を付加

• Y軸方向だけでなくX軸方向にも動けるように• 重力(gravity)の要素も付加

• 常に一定の力をY軸方向に付加する

Page 13: Proga 0622

float stiffness = 0.05;float damping = 0.9;float mass = 3.0;float gravity = 0.0;float velocityX = 0.0, velocityY = 0.0;float targetX, targetY;float x, y;

void setup() { size(600, 600); smooth();}

void draw() { background(0); //X軸方向 float forceX = stiffness * (targetX - x); float accelerationX = forceX / mass; velocityX = damping * (velocityX + accelerationX); x += velocityX; //Y軸方向 float forceY = stiffness * (targetY - y); forceY += gravity; float accelerationY = forceY / mass; velocityY = damping * (velocityY + accelerationY); y += velocityY;

ばね3:2次元座標に展開、重力を付加

• Y軸方向だけでなくX軸方向にも動けるように

Page 14: Proga 0622

//物体を円で表現 noStroke(); fill(255); ellipse(x, y, 40, 40); //ばねの接続に線を引く stroke(127); noFill(); line(mouseX, mouseY, x, y); //マウス座標を目標にする targetX = mouseX; targetY = mouseY;}

ばね3:2次元座標に展開、重力を付加

• Y軸方向だけでなくX軸方向にも動けるように

Page 15: Proga 0622

ばね3:2次元座標に展開、重力を付加

Page 16: Proga 0622

ばね4:「ばね」をクラスとして定義する

• ばねの動きを汎用的に使えるようにクラスとして定義する• Spring2Dクラス

Page 17: Proga 0622

//Spring2Dクラスを利用して、ばねの動きを生成Spring2D s1, s2;float gravity = 5.0;float mass = 2.0;

void setup() { size(400, 400); smooth(); fill(0); //入力:x座標, y座標, 摩擦, 重力 s1 = new Spring2D(0.0, width / 2, mass, gravity); s2 = new Spring2D(0.0, width / 2, mass, gravity);}

void draw() { background(204); s1.update(mouseX, mouseY); s1.display(mouseX, mouseY); s2.update(s1.x, s1.y); s2.display(s1.x, s1.y);}

ばね4:「ばね」をクラスとして定義する

• メインプログラム

Page 18: Proga 0622

// class:Spring2D//「ばね」の動きをシミュレートするclass Spring2D { float vx, vy; float x, y; float gravity; float mass; float radius = 10; float stiffness = 0.2; float damping = 0.7; //コンストラクタ Spring2D(float xpos, float ypos, float m, float g) { x = xpos; y = ypos; mass = m; gravity = g; } //位置を計算 void update(float targetX, float targetY) { float forceX = (targetX - x) * stiffness; float ax = forceX / mass; vx = damping * (vx + ax); x += vx; float forceY = (targetY - y) * stiffness;

ばね4:「ばね」をクラスとして定義する

• 「ばね」を定義するクラス:Spring2D (1 of 2)

Page 19: Proga 0622

forceY += gravity; float ay = forceY / mass; vy = damping * (vy + ay); y += vy; } //表示 void display(float nx, float ny) { noStroke(); ellipse(x, y, radius*2, radius*2); stroke(255); line(x, y, nx, ny); }}

ばね4:「ばね」をクラスとして定義する

• 「ばね」を定義するクラス:Spring2D (2 of 2)

Page 20: Proga 0622

ばね4:「ばね」をクラスとして定義する

Page 21: Proga 0622

ばね5:ばねを数珠繋ぎにしてみる

• Spring2Dクラスで定義した「ばね」を直列に繋いでいく• Spring2Dクラスを配列として定義する

Page 22: Proga 0622

//ばねを数珠繋ぎにint numSprings = 10; //ばねの数Spring2D[] s = new Spring2D[numSprings];float gravity = 5.0;float mass = 5.0;float stiffness = 0.2;float damping = 0.8;void setup() { size(600, 600); smooth(); fill(0); for (int i = 0; i < numSprings; i++) { s[i] = new Spring2D(width / 2, i*(height / numSprings), mass, gravity, stiffness, damping); }}void draw() { background(204); s[0].update(mouseX, mouseY); s[0].display(mouseX, mouseY); for (int i = 1; i < numSprings; i++) { s[i].update(s[i-1].x, s[i-1].y); s[i].display(s[i-1].x, s[i-1].y); }}

ばね5:ばねを数珠繋ぎにしてみる

• Spring2Dクラスで定義した「ばね」を直列に繋いでいく

Page 23: Proga 0622

ばね5:ばねを数珠繋ぎにしてみる

Page 24: Proga 0622

Physicsライブラリを利用する

• 「ばね」や「引力」などを、一からプログラミングするのは大変• 既存のライブラリを活用することで、物理演算を簡単に行うことができる• Processingで利用できる物理演算ライブラリ

• Physics• JBox2D

• 今回はPhysicsを利用してみる

Page 25: Proga 0622

Physicsライブラリを利用する

• Physics Webページ• http://www.cs.princeton.edu/~traer/physics/• ここからダウンロードして、Sketchフォルダのlibrariyにインストール

Page 26: Proga 0622

Physicsライブラリを利用する

• Physicsの構成• 4つのパート

• ParticleSystem:物理演算のための環境を生成• Particles:空間を動きまわる粒(パーティクル)• Springs:2つのパーティクルを接続する「ばね」• Attractions:2つのパーティクルの間にはたらく引力

Page 27: Proga 0622

Physicsで「ばね」を表現1

• Physicsでばねの数珠繋ぎを再現する• Particleの配列を用意• Springの配列を用意• ParticleSystemを新規に生成• 指定した数だけParticleを生成し、配列に追加• Particle間をSpringで接続し、配列に追加• Particleの位置に円を描く• Springを線で描く

Page 28: Proga 0622

import traer.physics.*;ParticleSystem physics;Particle mouse;Particle[] p;Spring[] s;

void setup(){ size( 400, 400 ); smooth(); //Physicsの環境を生成 physics = new ParticleSystem( 1.0, 0.05 ); p = new Particle[10]; s = new Spring[10]; //指定した数だけバネを数珠繋ぎにする for(int i = 0; i < p.length; i++){ p[i] = physics.makeParticle( 1.0, width/2, 20 * i, 0); if(i > 0){ s[i] = physics.makeSpring( p[i], p[i-1], 1.0, 0.1, 20); } } //先頭のパーティクルを固定 p[0].makeFixed();}

Physicsで「ばね」を表現1

• Physicsでばねの数珠繋ぎを再現する

Page 29: Proga 0622

void draw(){ background(0); physics.tick(); //先頭のパーティクル位置をマウスの位置に p[0].moveTo(mouseX, mouseY, 0); //パーティクルの位置に円を配置、バネを線で描画 for(int i = 0; i < p.length; i++){ noStroke(); fill(128); ellipse( p[i].position().x(), p[i].position().y(), 10, 10 ); if(i > 0){ stroke(255); line(p[i].position().x(), p[i].position().y(), p[i-1].position().x(), p[i-1].position().y()); } }}

Physicsで「ばね」を表現1

• Physicsでばねの数珠繋ぎを再現する

Page 30: Proga 0622

Physicsで「ばね」を表現1

Page 31: Proga 0622

ノードガーデン1

• Jared TarbelのNodeGardenをPhysicsで再現• http://levitated.net/bones/nodeGarden/index.html

• Particleを多数生成し、画面上にランダムにちりばめる• それぞれのParticle同士を全てSpringで接続• Particle間の距離に応じて、Spring接続を表現する線の濃度を変化させる

Page 32: Proga 0622

ノードガーデン1

• N個のParticle同士を全てをSpringで結ぶには?• p[0]からは

• → p[1], → p[2], → p[3]... p[n]• p[1]からは

• → p[2], → p[3], → p[4]... p[n]• p[n]までこれを繰り返し

• この法則は、以下のfor文で実現可能

• for(int i = 0; i < n; i++){• for(j = i + 1; j < n; j++){

• 処理内容• }

• }

p[0] p[1]

p[2]

p[3]

...

p[n]

p[1] p[2]

p[3]

p[4]

...

p[n]

p[2] p[3]

p[4]

p[5]

...

p[n]

...

p[n]

Page 33: Proga 0622

import processing.opengl.*;import traer.physics.*;ParticleSystem physics;Particle[] particles;int num = 80;

void setup(){ size(800, 800, OPENGL ); fill(255); smooth(); rectMode(CENTER); physics = new ParticleSystem(0, 0.0); particles = new Particle[num]; for (int i = 0; i < num; i++){ particles[i] = physics.makeParticle(0.2, random(width), random(height), 0); for (int j = i + 1; j < num; j++){ particles[j] = physics.makeParticle(0.2, random(width), random(height), 0); particles[j].setMass(0.5); physics.makeSpring(particles[i], particles[j], 0.1, 0.0, width/2); } }}

ノードガーデン1

Page 34: Proga 0622

void draw(){ physics.tick(0.01); background(0); for (int i = 0; i < num; i++){ rect(particles[i].position().x(), particles[i].position().y(), 8, 8); }}

ノードガーデン1

Page 35: Proga 0622

ノードガーデン1

Page 36: Proga 0622

ノードガーデン2

• 全てのSpring接続を線で描画する• 先程の2重のfor文で、生成可能

Page 37: Proga 0622

import processing.opengl.*;import traer.physics.*;ParticleSystem physics;Particle[] particles;int num = 80;

void setup(){ size(800, 800, OPENGL ); fill(255); smooth(); rectMode(CENTER); physics = new ParticleSystem(0, 0.0); particles = new Particle[num]; for (int i = 0; i < num; i++){ particles[i] = physics.makeParticle(0.2, random(width), random(height), 0); for (int j = i + 1; j < num; j++){ particles[j] = physics.makeParticle(0.2, random(width), random(height), 0); particles[j].setMass(0.5); physics.makeSpring(particles[i], particles[j], 0.1, 0.0, width/2); } }}

ノードガーデン2

Page 38: Proga 0622

void draw(){ physics.tick(0.01); background(0); for (int i = 0; i < num; i++){ fill(255); noStroke(); rect(particles[i].position().x(), particles[i].position().y(), 8, 8); stroke(127,50); //Spring間をlineで結ぶ for (int j = i + 1; j < num; j++){ line(particles[j].position().x(), particles[j].position().y(), particles[i].position().x(), particles[i].position().y()); } }}

ノードガーデン2

Page 39: Proga 0622

ノードガーデン2

Page 40: Proga 0622

ノードガーデン3

• 全てのSpring接続を線の濃度を距離によって変化させる• Spring間の距離はdist関数で得ることができる

• dist(x1, y1, x2, y2);• 距離が近いほど線のアルファ値を濃くする

Page 41: Proga 0622

import processing.opengl.*;import traer.physics.*;ParticleSystem physics;Particle[] particles;int num = 80;

void setup(){ size(800, 800, OPENGL ); fill(255); smooth(); rectMode(CENTER); physics = new ParticleSystem(0, 0.0); particles = new Particle[num]; for (int i = 0; i < num; i++){ particles[i] = physics.makeParticle(0.2, random(width), random(height), 0); for (int j = i + 1; j < num; j++){ particles[j] = physics.makeParticle(0.2, random(width), random(height), 0); particles[j].setMass(0.5); physics.makeSpring(particles[i], particles[j], 0.1, 0.0, width/2); } }}

ノードガーデン3

Page 42: Proga 0622

void draw(){ physics.tick(0.01); background(0); for (int i = 0; i < num; i++){ rect(particles[i].position().x(), particles[i].position().y(), 4, 4); for (int j = i + 1; j < num; j++){ float l = dist(particles[j].position().x(), particles[j].position().y(), particles[i].position().x(), particles[i].position().y()); stroke(255, 100 - l); line(particles[j].position().x(), particles[j].position().y(), particles[i].position().x(), particles[i].position().y()); } }}

ノードガーデン3

Page 43: Proga 0622

ノードガーデン3

Page 44: Proga 0622

ノードガーデン4

• Particle間の接続を、SpringではなくAttraction (引力) におきかえる

Page 45: Proga 0622

import processing.opengl.*;import traer.physics.*;ParticleSystem physics;Particle[] particles;int num = 80;

void setup(){ size(800, 800, OPENGL ); smooth(); fill(255); rectMode(CENTER); physics = new ParticleSystem(0, 0.0); particles = new Particle[num]; for (int i = 0; i < num; i++){ particles[i] = physics.makeParticle(0.2, random(width), random(height), 0); for (int j = i + 1; j < num; j++){ particles[j] = physics.makeParticle(0.2, random(width), random(height), 0); particles[j].setMass(0.5); physics.makeAttraction(particles[i], particles[j], 1000, width); } }}

ノードガーデン4

Page 46: Proga 0622

void draw(){ physics.tick(1); background(0); for (int i = 0; i < num; i++) { rect(particles[i].position().x(), particles[i].position().y(), 3, 3); for (int j = i + 1; j < num; j++) { float l = dist(particles[j].position().x(), particles[j].position().y(), particles[i].position().x(), particles[i].position().y()); stroke(255, 100 - l); line(particles[j].position().x(), particles[j].position().y(), particles[i].position().x(), particles[i].position().y()); } }}

ノードガーデン4

Page 47: Proga 0622

ノードガーデン4