0から始めるUnity物理演算①物理シミュレーションを"書く"
今日のブログはネクサスではなく、私 Milo がお送りします!
この連載では、Unity道場で勉強したことを元に物理演算の基本を解説します。
今回は第1回。積分の理解と、簡単なコードでの物理シミュレーション実装にチャレンジしてみましょう!
この連載のバックナンバー
数は多いけどそれぞれ読みやすいです。
第3回:力と加速度(公開待ち)
- 運動方程式って何?
- 日本一わかりやすい&詳しい「質量」の話(まぁ、ホーキング大先生には負けるがね)
第4回:浮力(執筆中)
- 浮力の実装は難しい!
- 世界一簡単な浮力の実装!
第5回:衝突と力積(公開待ち)
- ちょっと厄介な衝突
- Impulseで解決!
第6回: 慣性テンソル(執筆中
なお、本記事で使用するデータの権利はユニティ・テクノロジーズ・ジャパンhttps://unity3d.com/jpに帰属します。
問題があれば記事はすぐに削除させていただきます。
いざ会場へ
1月25日、会場は六本木。地下鉄に乗るのは久しぶりだったので乗り換えに失敗しつつ、やっと到着!
ほとんどが男性で、しかもmac使いが圧倒的多数!やはりUnityはMacユーザーが多いんですね。
ざっと見た感じ大学生は全くおらず、若干のアウェー感。
時間になると、Unity teamsの宣伝の後、講師の安原裕二さんが登壇されました!
積分がキホン!
いよいよ本題!ここからは安原さんが話していたことも書いていくので、講義のスライドを見ながらですと理解しやすいです!
講義はいきなりクイズから始まりました。
「純銀の玉と純金の玉を区別するにはどうしたら良いか」
ただし条件として、色、形、大きさが同じ。そして、金の方が比重が重いので、その分中身をくりぬいてある。つまり質量も同じ!
安原さんの「あっ、溶かしちゃダメですよ!」で会場は和やかなムードになりましたww
答えの発表は講義の後!とのことで、皆さんも考えてみてね。
安原さんは「数学に苦手意識を持たないで」と強調し、「皆さん、小学校の時にすでに積分の難しさはスルーしてるんです。面積を求める計算が長さ×長さ。よくわからないけどスルーしたでしょ。だから、積分もそんな感じで!」とおっしゃってました。
そして「微小ながさ」であるが初登場。講義ではこの「微小な量」が何回も登場します。
積分とは、小さい部分をいっぱい集めて足すこと。球の体積を求める時は、うす〜いの厚みの円を集めればいい。その時の計算はコンピュータにお任せ!と言う感じの内容でした。ちょうど予備校で高校生に微分積分を教えているのですが、安原さんの説明を参考にしようと思いましたww
物理シミュレーションのスクリプティング
積分が終わると、テーマは「物理シミュレーションの最小実装」に。なんとRigidBodyを使わずに、C#のスクリプトで物理シミュレーションを実現しよう!とのこと。
ここで加速度、速度、位置と積分の関係が出てきます。
積分の凄さ
なんで積分するかと言うと、加速度がわかれば積分計算によって速度も位置もわかるからです。
そして、実は僕たち人間が物体の運動を予想する時、「加速度」って言う一番聞きなれないものしか役に立たないからです。
例えば車🚘、アクセル全開の車が、3分後にどこの位置にいるか?を考えましょう。
「今」の位置は定規で測ればわかるけど、3分後どこにいるかは速度がないとわからない。「今」の速度をはかっても、3分の間にアクセル踏んで加速しちゃうので意味がない。ところが加速度をゲットしてそれを積分すれば、速度が増える分も考慮して、3分後の位置がわかるんです。
加速度をゲットすれば、速度も位置もわかるというのが大事なポイントです!
物理シミュレーションのスクリプト
さて、実際の物理シミュのコードがスライド25枚目にあります。自分でも実装したかったのでコードを書き写しました。これをRigidbodyコンポーネントの代わりに任意のObjectに追加するだけで最小の物理シミュレーションとなります!
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MyRigidbody : MonoBehaviour { public Vector3 acceleration; //加速度。これがないと物理シミュレーションは始まらない。 public Vector3 velocity; //速度。微小時間dtの間の加速度を、積分でいっぱい集めると速度になる public Vector3 position; //位置は速度の時間積分 //追加部分始め---------------------------------------- public float mass; //質量に相当。 public Vector3 gravityScale; //重力加速度 //追加部分終わり--------------------------------------- const float dt = 1f/60f; //微小時間dtに相当する部分 public void AddForce(Vector3 force) { acceleration += force; //加速度を増やすには、力を加えれば良い! } void FixedUpdate () { //追加部分始め--------------------------------------- acceleration += mass * gravityScale; //重力を発生させる。重力は質量と重力加速度の掛け算で求まる力! //追加部分終わり--------------------------------------- velocity += acceleration * dt; //加速度を時間積分 position += velocity * dt; //速度を時間積分 //地面と接触したら、跳ね返る表現。 //地面との衝突判定の代わりに、地面に近いところまで落ちたら速度を反転している。 if(position.y < 0.5f) { velocity = -velocity; } transform.position = position; acceleration = Vector3.zero; //加速度をリセット。加えた力の影響を最後にリセット } }
なお、コードの追加部分は重力の実装となっています!
このコードには2箇所だけインチキが含まれているのですが、第3回でちゃんと訂正します。
図のようにinspectorから初期位置、質量mass、重力加速度gravityScaleの値を設定すると、バウンドするオブジェクトを作れますよ!
今日のまとめ
- 物理シミュレーションは、計算の賜物。
- 積分は、細かいものをたくさん集めること。
- 物体の位置や速度を求めるには、加速度がわかれば良い!
次回はFixedUpdateについて、
- 処理落ちが発生した時Unityはどうなっているのか?
- deltaTimeとfixedDeltaTimeの意味と違い
について説明します。