ブラウザだけで魚群シミュレーション — Boidsの3ルールから三宮モデル(1993)の再現まで
この記事で解決する課題
「群れのシミュレーションを作ってみたいが、何から手を付ければよいか分からない」「Boidsは知っているが、実測データに基づくモデルや3D化の勘所を知りたい」という課題に答えます。ビルドツールもサーバーも使わず、HTMLファイル1枚から始めて、最終的にGitHub Pagesで公開するまでの実装知見をまとめました。
動作デモ:
(全デモがブラウザ内で動作します)
リポジトリ:
対象読者
- JavaScript / Three.js で可視化・シミュレーションを作りたい方
- エージェントベースモデル(ABM)の入門者
- ゲームや演出で群れ表現を実装したい方
目次
1. Boidsの3ルールとReynoldsステアリング
Boids(Reynolds, SIGGRAPH 1987)は、次の3つの局所ルールだけで群れが創発するモデルです。
- 整列: 近傍の速度ベクトルの平均へ向きを寄せる
- 結合: 近傍の重心へ向かう
-
分離: 近すぎる個体から
1/距離²の重みで離れる
各ルールは「望む方向 desired」を計算し、Reynoldsのステアリング則で旋回力に変換します。急旋回を防ぎ、生物らしい滑らかな軌道になります。
// steer = normalize(desired) * maxSpeed - velocity を maxForce でクランプ
function steer(b, desiredX, desiredY, weight) {
const mag = Math.hypot(desiredX, desiredY);
if (mag === 0) return;
let sx = (desiredX / mag) * maxSpeed - b.vx;
let sy = (desiredY / mag) * maxSpeed - b.vy;
const smag = Math.hypot(sx, sy);
const limit = Math.min(smag, maxForce);
b.ax += (sx / smag) * limit * weight;
b.ay += (sy / smag) * limit * weight;
}
更新は毎フレーム「加速度→速度(maxSpeedでクランプ)→位置」の順に足すだけです。
BoidsはΔtが式に現れない「フレーム単位の漸化式」です。微分方程式の数値解ではないため、パラメータは無次元で、フレームレート前提の設計になります。後述の三宮モデルとの本質的な違いです。
2. 近傍探索の高速化:空間ハッシュ
素朴に実装すると近傍探索が O(N²) になります。視界半径 R をセルサイズとするグリッドに毎フレーム個体を登録し、隣接セル(2Dで9、3Dで27セル)だけを走査すれば、R以内の個体を漏れなく高速に列挙できます。
function buildGrid(cellSize) {
const grid = new Map();
for (const b of boids) {
const key = Math.floor(b.x / cellSize) + "," + Math.floor(b.y / cellSize);
(grid.get(key) ?? grid.set(key, []).get(key)).push(b);
}
return grid;
}
この構成で数百〜2000体程度まで60fpsを維持できます。
グリッドがあっても安心はできません。画面サイズ固定のままNを増やすと密度が上がり、「半径R以内の仲間の数」自体がNに比例して増えるため、実質O(N²)に近づきます。
3. メトリック近傍からトポロジカル近傍へ
古典Boidsの近傍は「半径R以内の全個体」(メトリック距離)です。しかしBallerini et al.(PNAS 2008)は、ムクドリの群れ(最大2600羽)の3D計測から、実際の鳥は距離に関係なく近い順に6〜7羽(トポロジカル距離、実測値 n_c = 6.5±0.9)と相互作用していることを示しました。
トポロジカル相互作用は密度変動に頑健で、捕食者に襲われても群れが分裂しにくいことが同論文の数値実験で示されています。実装は、上位k個体の挿入型部分選択で十分です。
const k = Math.min(params.k, boids.length - 1); // 論文値に合わせてデフォルト7
for (let j = 0; j < k; j++) { knnD[j] = Infinity; knnB[j] = null; }
for (const other of boids) {
if (other === b) continue;
const d2 = (other.x - b.x) ** 2 + (other.y - b.y) ** 2;
if (d2 >= knnD[k - 1]) continue;
let j = k - 1;
while (j > 0 && knnD[j - 1] > d2) { // 挿入ソートで上位kを維持
knnD[j] = knnD[j - 1]; knnB[j] = knnB[j - 1]; j--;
}
knnD[j] = d2; knnB[j] = other;
}
デモでは両モードを実行中に切り替えられるので、捕食者アタック後の分裂数の違いを観察できます。
4. 三宮モデル(1993)の再現 (まだ途中)
三宮信夫「魚群の行動モデルとシミュレーション」(水産工学 Vol.30 No.1, 1993, doi:10.18903/fisheng.30.1_41)は、水産工学分野の魚群物理モデルです。J-Stageで全文が公開されており、運動方程式・力の関数形・水槽実験から推定した全パラメータが論文に揃っているため、そのまま数値化して再現できます。
質点のニュートン力学で、3種類の力の合成です。
m·v̇ = F1(前方推進力) + F2(個体間誘引力+成群力) + F3(壁・障害物の反発と誘引)
F1 = −a¹(‖v‖−a²)(‖v‖−a³)v … 固有速度a²(約11cm/s)へ自己調整
F2 = Σ b(r)·r̂ + Σ k_c(v_j−v_i)/M_c … b(r)は近距離で負・遠距離で正の区分線形
F3 = 反発(5cm以内で接近時)+ 誘引(20cm以内で離脱時)
Boidsと比較して特徴的な点が3つあります。
- パラメータが実測値: 係数はタイリクバラタナゴの水槽実験から最小2乗推定された値(質量2.58g、固有速度10.4〜11.9cm/s など)で、cm・g・秒の物理単位を持ちます
- 障害物への「誘引力」: 障害物から離れようとするときだけ引き戻される非対称な力で、魚が網地に沿って泳ぐ習性を表現します。定置網への入網・魚礁への蝟集という水産応用がこの項から生まれます
- 情報量パラメータ M_b / M_c: 「近い順に何尾から位置・速度情報を得るか」。トポロジカル近傍をBalleriniの15年前に採用しています。論文では、N=20の群れの秩序維持には M_b≥5, M_c≥1 で足りることが示されています
論文中の質疑応答まで含めて式の意図(成群力のみM_cで割る理由など)が解説されており、再現実装の資料として非常に親切な構成です。
5. まとめ
- Boidsの3ルールは、ステアリング則+空間ハッシュで依存ゼロの単一HTMLとして実装できます
- 近傍定義を「近い順k個体」に変えるだけで、実測(Ballerini 2008)に基づくトポロジカル相互作用へ拡張できます
- 三宮モデル(1993)は論文だけで完全再現が可能で、障害物への誘引・実測パラメータ・情報量パラメータという、Boidsにない水産工学的な視点を持っています
参考文献
- C. W. Reynolds, "Flocks, Herds, and Schools: A Distributed Behavioral Model", SIGGRAPH 1987
- M. Ballerini et al., "Interaction ruling animal collective behaviour depends on topological rather than metric distance", PNAS 2008
- 三宮信夫「魚群の行動モデルとシミュレーション」水産工学 Vol.30 No.1, pp.41-48, 1993


