yoppa.org


人工言語入門 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:シンプルな「ばね」

  • 「ばね」の公式(フックの法則)を利用して、シンプルな「ばね」の動きをプログラミングしてみる

[code language=”java”]
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座標を目標位置に
}
[/code]

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

  • もうひとつの要素を付加する – バネに付いている物体の重さ(mass)
  • 重さと力の関係はニュートンの運動の第二法則から導きだされる
    • F = ma
    • F:力、m:質量、a:加速度
  • 式を変換
    • a = F / m
  • これを「ばね」にあてはめると、下記のように解釈できる
    • acceleration = springForce / mass
    • 加速 = バネの力 / 重さ
  • 先程のプログラムに重さの要素を付加する
  • 重さの概念を追加した「ばね」

[code language=”java”]
//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);
}
[/code]

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

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

[code language=”java”]
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;
}
[/code]

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

  • ばねの動きを汎用的に使えるようにクラスとして定義する
    • Spring2Dクラス
  • メインプログラム

[code language=”java”]
//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);
}
[/code]

  • 「ばね」を定義するクラス:Spring2D

[code language=”java”]
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);
}
}
[/code]

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

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

[code language=”java”]
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);
}
}
[/code]

  • Morizono

    楽しく勉強させていただいてます。
    「ばね5」では Spring2D のクラス定義を少し変更しないといけませんね。コンストラクタの引数にstiffnessとdampingを追加する必要があります。