【BlenderとPython】単振動のアニメーション

2023-09-21開発

BlenderとPython(bpy)を使ってアニメーションを作ってみたかったので単振動に挑戦しました

導出

単振動

摩擦や空気抵抗がない時、ある一つの物体が安定な平衡点の近くで行う運動

例:ばねにつるされた重りの運動

直線上を運動する質量mの物体について

x軸上を運動すると考える

物体は原点からの距離に比例する力を受けるとする

ばねにつるされた物体について考えるときkはばね定数

$$F=-kx$$

運動方程式を用いる

$$F=ma$$

よってこの時の運動方程式は

$$m\frac{d^2x}{dt^2}=-kx$$

移項して計算すると

$$\frac{d^2x}{dt^2}+\frac{k}{m}x=0$$

ここで角振動数を用いる

$$\omega_0=\sqrt{\frac{k}{m}}$$

よって

$$\frac{d^2x}{dt^2}+\omega_0^2x=0$$

これは2階の斉次線形微分方程式なので解の形は次になります

$$x=e^{\lambda t}$$

これを代入して

$$(\lambda^2+\omega_0^2)e^{\lambda t}=0$$

よって

$$(\lambda^2+\omega_0^2)=0$$

$$\lambda=\pm i \omega_0 $$

解は

$$x=e^{i\omega_0 t}$$

$$x=e^{-i\omega_0 t}$$

2階の斉次線形微分方程式の一般解は2つの解の線形結合になるので

運動方程式の解は次になります

$$x=C_1 e^{i\omega_0 t}+C_2 e^{-i\omega_0 t}$$

オイラー公式を用います

$$e^{i\omega_0 t}=\mathrm{cos}{\omega_0 t}+i\mathrm{sin}{\omega_0 t}$$

$$e^{-i\omega_0 t}=\mathrm{cos}{\omega_0 t}-i\mathrm{sin}{\omega_0 t}$$

よって

$$x=C_1(\mathrm{cos}{\omega_0 t}+i\mathrm{sin}{\omega_0 t})$$

$$+C_2(\mathrm{cos}{\omega_0 t}-i\mathrm{sin}{\omega_0 t})$$

$$x=(C_1+C_2)(\mathrm{cos}{\omega_0 t})+i(C_1-C_2)\mathrm{sin}{\omega_0 t})$$

ここで

$$B_1=C_1+C_2$$

$$B_2=i(C_1-C_2)$$

とすると次の式になる

$$x=B_1\mathrm{cos}{\omega_0 t}+B_2\mathrm{sin}{\omega_0 t}$$

ここで三角関数の合成公式を用いる

$$a\mathrm{sin}{\theta}+\mathrm{cos}{\theta}=\sqrt{a^2+b^2}\mathrm{sin}({\theta+\alpha})$$

よって一般解を次のように書くことができる

$$x(t)=A\mathrm{sin}({\omega_0 t+\alpha})$$

また、この運動の周期は

$$f=\frac{2\pi}{\omega_0}$$

$$T=\frac{1}{f}=\frac{2\pi}{\omega_0}$$

BlenderとPython(bpy)

位置の時間変位を「Cube1」

単振動を表現する球を「Cube2」

円上を等速運動する「Cube3」をy軸に射影したものが「Cube1」である

Cube1,2,3をBlenderで「追加」→「メッシュ」→「UV球」から作成

それぞれ名前を付ける

それぞれの球に「マテリアル」から「ベースカラー」を選択し色を付ける

x軸,y軸,z軸はお好みで作成してください

角振動数の単位はrad(ラジアン)なので次の式を用います

$$\mathrm{rad}=\frac{2\pi}{N}t$$

フレーム数は自由に変更してください

Blenderの「Scripting」→「新規」からテキストエディタを表示できます

右にある「▶」をクリックすると実行できます

#bpyとmathを使えるようにする
import bpy
import math

#開始時の座標を指定する
start_pos = (0,0,0)

#変数obに3D viewportにあるオブジェクトを代入する
ob1 = bpy.data.objects["Cube1"]
ob2 = bpy.data.objects["Cube2"]
ob3 = bpy.data.objects["Cube3"]

#分割数を入力
N=12

#開始のフレームを指定する
frame_num = 0

#目標の座標に移動する処理を繰り返す
for i in range(N+1):
    rad = 2* math.pi * i /N

#それぞれ球の位置を求める    
    p1=(0,i,math.sin(rad))
    p2=(0,0, math.sin(rad))
    p3=(0,math.cos(rad), math.sin(rad))

#開始のフレームを設定する
    bpy.context.scene.frame_set(frame_num)
    
#変数locationに目標の座標の値を代入する
    ob1.location = p1
    ob2.location = p2
    ob3.location = p3

#キーフレームの挿入を行う
    ob1.keyframe_insert(data_path = "location",index = -1)
    ob2.keyframe_insert(data_path = "location",index = -1)
    ob3.keyframe_insert(data_path = "location",index = -1)

#フレームを10ずらす
    frame_num += 10

まとめ

単振動の解を出し、bpyを書き、Blenderを操作しアニメーションをレンダリンング

結構時間がかかり苦労しました

今回は動かすことに主力を置いたため、数式など理論に不適切な点があるかもしれません

軸や着色、ライティング、レンダリンングなど今後は工夫したいと思います

開発

Posted by neruma