始めに
ここ最近は個人開発でQuest向けの魚群シミュレーションを開発しています。現状の進捗としては入れたい機能をある程度実装して動作確認して、Questでどれだけ動かせそうかの上限が見えてきたところです。
そんな中、テストプレイをしていただいた方からよく言われることは「魚群を操れないの?」です。 言われる私としては、魚群を作るだけでも大変なのに簡単に言ってくれるなって感じです。
ですが、そんな夢物語を叶えたいのは私も同じなので、魚群を操る方法の一つとして水流を作成する方法を試した話です。
水流の実装
ここからはどのように実装をしたのかを簡単にまとめていきます。 今回の記事は日記程度の内容を想定しているので、詳細な実装方法(ソースコードなど)は提示しないのでご了承ください。
水流のデータ構造について
空間に水流を保持させる方法として、空間を格子上に分割してそのマス目に力を設定する方法を取りました。
コード上では NativeParallelHashMap<int3, float3>
で表現しました。こうすることで、シミュレーション空間すべてを含められるデータ量を含める必要はなくなり、水流を作成した範囲のみを保持できました。
水流の書き込み
水流を作るときはオブジェクトの速度を求めて、空間上のマス目にその速度を書き込みます。 オブジェクトの速度は数フレーム中の平均速度を求めるようにしています。
マス目に速度を書き込むときに、水流の力が大きくなりすぎないように
水流に沿うよう流れを作る
ただオブジェクトの速度を所属するマス目上に書き込んだ場合、水流の流れは粗くなる問題が発生します。
この問題を解決するために、以下の方法を取りました。
- 所属するマス目の周りにも力を書き込む
- 周囲のマス目に力を書き込む場合、流れの向きに沿うように力を変化させる
1. 所属するマス目の周りにも力を書き込む
所属するマス目に水流を書き込むときに、周りのマス目にも同様の力を加えます。 こうすることで、水流の粗さを減らすことができます。
2. 周囲のマス目に力を書き込む場合、流れの向きに沿うように力を変化させる
出来るだけ魚群を水流に沿って動作してほしいため、水流へ集まるような力を周囲へ書き込みます。 周囲のマス目に力を書き込むときに、中心のマス目に書き込んだ力の先に集まるような力を求めます。
集まる力は次のようになりました。
- 中心のマス目に書き込んだ力を直線と考えて、周りのマス目の座標から直線へのベクトルを求める
- 周りのマスにて直線との垂線ベクトルを求める
- 垂線ベクトルと中心のマス目に書き込んだ力から、水流の進行方向へ集まる力を求める
また、周囲のマスから中心へ向かうベクトルや中心のマス目に書き込んだ力に係数を掛けて、水流へ集まる力をある程度コントロールできるようにしました。
魚群の個体にて水流から受ける力を求める
最後に水流の力を個体に適用していきます。個体に力を適用するとき、個体が所属するマス目とその周囲のマス(図の2Dですと2x2=4マスですが、3Dでは2x2x2=8マス)から線形補完をして力を求めます。
実行結果
ここからは実際に書き込んだ水流がどのようになったのか、魚群がどのように動くのかを実行して確認します。 ここでは、Sceneビューからオブジェクトを動かしたり、単純な円運動をするプログラムを使ったりして水流を作って確認します。
水流の表示
書き込んだ水流を実際に矢印にして表示を行います。矢印の向きで水流の方向、長さで水流の力の大きさを表します。
以下は手動と円運動するするで水流を作ったものになります。やはりマス目上に書き込むので粗くはなってしまいますが、流れが作られていることが確認できます。
水流による魚群の動き
では実際に水流を魚群に適用してどのように動くかを見ていきます。
以下の動画では水流を密に作っており、細長く水流に乗って動く魚群が確認できました。 この場の水流ではすべての個体を水流に乗せるには小さすぎました。
次に、水流を作るときに書き込む幅を増やして、かつ書き込む格子を飛ばし飛ばし書くようにパラメータを調整しました。
このようにすることで、すべての個体を水流に乗せることができました。
まとめ
自分が作りたいと考えていた水流をやっと実装できてすっきりしました。
実装して最初に動作確認をしたときは、パラメータの調整方法がまだはっきりしておらず失敗と感じておりました。
しかし、パラメータの調整方法がわかるにつれて想定した群れが作れました。 計算量やデータ量もそこまで多くはない実装なので、今後この方法を使って何かを出来そうです。
また、今のところ水流以外にも別の魚群制御方法を考えているので、これも後ほど試していく予定です。
参考
参考と言えるほどではありませんが、この方法の発想は以下からでした。
また、今回の水流から受ける力の計算では前に書いた記事から持ってきました。(もともとこれに使うために書いた)