Bifrostではじめる位置ベース物理シミュ 第2回 ~力を加える・位置を補正する~

ハイどうもこんにちは！

[前回](https://qiita.com/akasaki1211/items/54f6009ed3389948f7f0)に引き続き位置ベースでなんちゃって物理をいじくっていきます。

```math
\begin{cases}
v(t) = \frac{x(t) - x(t - \Delta t)}{ \Delta t} \\ 
x(t + \Delta t) = x(t) + v(t) \Delta t +\frac{F}{m} \Delta t^2
\end{cases}
```

前回、見なかったことにした$\frac{F}{m} \Delta t^2$の部分と、さらにその後、得られた位置を強引に補正する工程を追加していきます。ベースのBifrostグラフは前回組んだものがあるのでちょい足しするだけです。

が、その前に、初期値をvalueノードで入力するのは面倒になってきたのでinputにつなぎ直しておきます。[前回の最後のグラフ](https://qiita.com/akasaki1211/items/54f6009ed3389948f7f0#%E4%BB%8A%E5%9B%9E%E3%81%AE%E3%82%B0%E3%83%A9%E3%83%95%E3%81%BE%E3%81%A8%E3%82%81)から始めます。
![img_02_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/f3f90412-4a06-e01b-9cd5-22190dcd7a62.png)

inputとoutput以外の全体をコンパウンド化し、以下のように修正します。入力側のフィードバックポートには何も接続してなくて大丈夫です。（接続してもすぐ上書きされます。）出力側のフィードバックポートはしっかりoutputへつないでおきます。

![img_02_01a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/1118c108-a597-9673-ce82-7a7c13c815f6.png)
▲bifrostGraphShape

![img_02_01b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/df35b123-fc43-7c90-4c46-c819e9f2d933.png)
▲bifrostGraphShape > pbd

![img_02_01c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/fd29fb1d-3f69-ef0d-df88-a14bbbe1a931.png)
▲Initial Positionへlocatorなどを接続し、初期位置を自由に動かせるようにしておきます

# 重力

では本題に戻って重力を足してみます。まず、$\frac{F}{m} \Delta t^2$の$m$は質量、$F$は力、$\Delta t$は前回も書きましたが1ステップの経過時間です。「力（チカラ）ってなんやねん…」と思うかもしれませんがこれも位置や速度と同じくベクトルで表されます。単位は$N[kg \cdot m/s^2]$ですが、まぁ細かいことは気にせず進めましょう。

重力による力は次のように表されます。

```math
F_{gravity} = mg
```

$g$は重力加速度です。このことから例の式の$\frac{F}{m} \Delta t^2$の部分は次のように置き換えられます。

```math
g \Delta t^2
```

$g$はどんな質量のものでも約$9.8 [m/s^2]$が標準値とされているので、Y軸下向きにこれをあてはめます。

```math
g = (0, -9.8, 0)
```

![fig_02_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/748b9d7e-bde2-71ad-fa44-cb60c3761ebc.jpeg)

ということで、Bifrostグラフに追加します。右下のGravityが追加した部分です。

![img_02_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/f3ee73a4-b69e-1e15-9573-9c3f128f346b.png)
▲bifrostGraphShape > pbd > Verlet（※現在シーンの単位がcentimeterなので-980にしてあります）

初期位置を上空5m（500cm）、初速度を0、dampingを0にして30fpsで再生してみます。
![gif_02_02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/05f21d86-75a9-8628-28f9-51301a1894f6.gif)

0Fから開始して30F前後の時、つまり約1秒後に地面に到達しました。念のため、物理の教科書に載っていそうな自由落下の公式  $y = \frac{1}{2} g t^2$ で5mの落下にかかる時間を確認してみます。

```math
\begin{aligned}
y &= \frac{1}{2} g t^2 \\
5 &= 4.9 t^2 \\
t^2 &= \frac{5}{4.9} \\
t &= 1.01015 \\
\end{aligned}
```

だいたいあってそうですね！

# バネ

前項の例では完全にフリーな点を落下させましたが、次は初期位置からバネやゴムのような何かで繋がれているような動きを追加してみます。バネモデルを用いた力は次のように表されます。

```math
F_{spring} = -k \{x(t) - x_0\}
```

$k$はバネ係数、$x_0$は初期位置です。初期位置から今の位置までのベクトルを$k$倍して反転させるような形になっています。この逆向きの力は初期位置から離れれば離れるほど大きくなります。で、例の式に入れ込むと次のようになります。

```math
x(t + \Delta t) = x(t) + v(t) \Delta t + (g + \frac{F_{spring}}{m}) \Delta t^2
```

![fig_02_02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/f562e947-d790-0674-1fd5-8c3bb979717d.jpeg)

これをBifrostグラフに足してみます。バネ係数$k$はelasticity、質量$m$はmassというパラメータにします。先ほどの重力も含めForceという括りでまとめ直しています。
![img_02_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/713be415-97a2-75d3-aaf1-879cea4fc10f.png)
▲bifrostGraphShape > pbd > Verlet

初速度を0、dampingを0.05、elasticityを30、massを1にして再生してみます。バネっぽい雰囲気が出てきました！
![gif_02_03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/090f4261-9100-c7ba-ea9b-c0dc8ab9e8ce.gif)

また、いくつかパラメータの組み合わせを変えて試してみました。
![gif_02_03_compare.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/1e8a2a58-773b-60ad-266d-4394a78fc4ec.gif)
左から順に
- damping: 0.05 / elasticity: 20 / mass: 1
- damping: 0.05 / elasticity: 100 / mass: 1
- damping: 0 / elasticity: 30 / mass: 1
- damping: 1 / elasticity: 30 / mass: 1
- damping: 0.05 / elasticity: 30 / mass: 0.1
- damping: 0.05 / elasticity: 30 / mass: 3

# 補正前の位置に戻す

ここまでの計算で得られた位置を補正前の位置の方向へｶﾞｯと戻します。ついさっきまで出来るだけ正しそうな重力やバネを表現してたのにお構いなし、強引にやっちゃいます。ﾅﾝﾃｺｯﾀｲ！

具体的には、補正後の位置から補正前の位置へ向かうベクトルを求め、stiffness値でスケーリングしてから補正後の位置に足します。stiffnessは0〜1の値を入力します。1の時には位置の変化が完全に打ち消され微動だにしなくなります。

```math
x(t + \Delta t)' = x(t + \Delta t) + \{x(t) - x(t + \Delta t )\} * stiffness
```

![fig_02_03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/c4fd0eee-5b1c-0f91-cb3b-bea026acba90.jpeg)

これをBifrostグラフに足してみます。
![img_02_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/876ede13-aa5d-853d-95d6-439607862fc3.png)
▲bifrostGraphShape > pbd

先ほどと同じく、初速度を0、dampingを0.05、elasticityを30、massを1、そしてstiffnessを0.15にして再生してみます。さっきよりだいぶ動きが鈍くなりました。
![gif_02_04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/58247119-b1e2-308f-0290-8af44089a2e6.gif)

第2回でやっとここまで来ました。次回は「制約条件」が加わり位置ベースの良いところが見えてきます。

# 今回のグラフまとめ

bifrostGraphShape
![img_02_05a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/0815c0f0-c7cb-63f0-79d8-53734373e985.png)

bifrostGraphShape > pbd
![img_02_05b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/3dab8251-d750-f70c-d116-0b05a15fe934.png)

重力とバネを加味して次の位置を決定（bifrostGraphShape > pbd > Verlet）
![img_02_05c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/541787f0-8cac-6e90-b867-240c98d39a83.png)

補正前の位置に戻す（bifrostGraphShape > pbd > Keep_position）
![img_02_05d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211093/d90825c0-f4e6-ea2c-477d-b1cb678b7271.png)

---

前の記事

https://qiita.com/akasaki1211/items/54f6009ed3389948f7f0

次の記事

https://qiita.com/akasaki1211/items/9d22075df1a51be1ed4c