人工言語入門 A 2010
Processingによる高度なモーション:バネの動きを作る
今日の内容
- 高度なアニメーション表現を身につける
- 物理法則を用いたアニメーションの表現
- ばね
- 万有引力
「ばね」を定義する
「ばね」を数学的に定義する
- 「ばね」を数学的に定義する
- フックの法則
- バネの伸びが x のとき、それによって生じる力を F とすると
- F = -kx ( k:ばね定数)
- フックの定理は以下のように書き直すことができる
- springForce = -stiffness * stretch
- バネの力 = -バネの硬さ x バネの伸び
- さらに「バネの伸び」の部分を解釈する
- springForce = -stiffness * (position – restPosition)
- バネの力 = -バネの硬さ x (現在位置 – ばねの静止位置)
- 式を整理
- springForce = stiffness * (restPositon – position)
- バネの力 = バネの硬さ x (静止位置 – 現在位置)
- この時、ばねの移動速度は下記のように表現される
- velocity = friction * (velocity + springFroce)
- 速度 = 摩擦 * (速度 + バネの力)
- この式を利用して、簡単なアニメーションをProcessingで作成してみる
ばね1:シンプルな「ばね」
- 「ばね」の公式(フックの法則)を利用して、シンプルな「ばね」の動きをプログラミングしてみる
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座標を目標位置に }
ばね2:重さ(mass)を付加
- もうひとつの要素を付加する – バネに付いている物体の重さ(mass)
- 重さと力の関係はニュートンの運動の第二法則から導きだされる
- F = ma
- F:力、m:質量、a:加速度
- 式を変換
- a = F / m
- これを「ばね」にあてはめると、下記のように解釈できる
- acceleration = springForce / mass
- 加速 = バネの力 / 重さ
- 先程のプログラムに重さの要素を付加する
- 重さの概念を追加した「ばね」
//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; //位置を算出 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); }
ばね3:2次元座標に展開、重力を付加
- Y軸方向だけでなくX軸方向にも動けるように
- 重力(gravity)の要素も付加
- 常に一定の力をY軸方向に付加する
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); float forceX = stiffness * (targetX - x); float accelerationX = forceX / mass; velocityX = damping * (velocityX + accelerationX); x += velocityX; float forceY = stiffness * (targetY - y); forceY += gravity; float accelerationY = forceY / mass; velocityY = damping * (velocityY + accelerationY); y += velocityY; noStroke(); fill(255); ellipse(x, y, 40, 40); stroke(127); noFill(); line(mouseX, mouseY, x, y); targetX = mouseX; targetY = mouseY; }
ばね4:「ばね」をクラスとして定義する
- ばねの動きを汎用的に使えるようにクラスとして定義する
- Spring2Dクラス
- メインプログラム
//Spring2Dクラスを利用して、ばねの動きを生成 Spring2D s1, s2; float gravity = 15.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); }
- 「ばね」を定義するクラス: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; 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); } }
ばね5:ばねを数珠繋ぎにしてみる
- Spring2Dクラスで定義した「ばね」を直列に繋いでいく
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); } }