地図/創発/グリッド

整数から連続値へ — 反応拡散

セルの状態を整数でなく 0〜1 の実数にして、2種類の物質の濃度として持たせる。読む面と書く面を分けて、近傍を見て、ルールで次を決める。近傍の使い方は、立っている数のカウントから「隣の平均と自分の差」に変わる。

反応拡散は 1952 年、アラン・チューリングが化学物質の濃度差だけで動物の体表模様が決まるのではと論じた枠組み(Turing パターン)に遡る。拡散は普通ものを均一にする向きに働くのに、2種類の物質で拡散の速さが違うと、かえって不均一な模様を安定して保つ。グレイ・スコットはその数値モデルの一つで、供給量 feed と除去量 kill の平面のどこに立つかで、斑点・縞・迷路・分裂する細胞と相が変わる。

連続値の格子を一枚用意する。b は物質 B の濃度で、GW × GH のセルを1本の Float32Array に詰めたもの。実数の箱なので、整数でない濃度がそのまま入る。中央に正方形の種を撒いて、濃度をそのまま明るさに写す。

四角い種が中央に静止している。更新ルールがまだ入っていないので動かない。拡散だけを入れると、各セルの値が近傍の平均と自分の差ぶんだけ近傍へ寄る。この近傍の平均と自分の差がラプラシアン。DB がにじみの強さ。

// 上下左右の平均と自分の差。濃度の差を読む
const lap = (f, x, y, i) => {
  const xm = x > 0 ? i - 1 : i + GW - 1
  const xp = x < GW - 1 ? i + 1 : i - GW + 1
  const ym = y > 0 ? i - GW : i + len - GW
  const yp = y < GH - 1 ? i + GW : i - len + GW
  return (f[xm] + f[xp] + f[ym] + f[yp]) * 0.25 - f[i]
}

x > 0 ? i - 1 : i + GW - 1 の三項は、左端のセルが反対の右端を隣として読む巻き込みで、面が筒状に繋がる。読む面 b を見ながら書く面 b2 に書いて、最後に入れ替える。

種の角が取れて丸くにじみ、中心の濃さが薄れて周りへ散る。濃淡が連続にぼやけるだけで、拡散しかないと B は薄まって消えていく。

二枚目の場 A を足して、補充・除去・反応を入れると Gray-Scott になる。A は外から feed の率で補充され、B は kill の率で抜かれる。反応 A·B·B で A が減って B が増える。A の式は拡散 DA·lap(a)、反応で減る - A·B·B、補充 + feed·(1-A)。B の式は拡散 DB·lap(b)、反応で増える + A·B·B、除去 - (kill+feed)·B。両方の場を毎フレーム更新する。

種が増殖して分裂し、迷路のように伸びていく。一フレームに step を 6 回回しているのは、一回の更新の変化が小さく、模様が育つまで時間がかかるため。feed0.055kill0.062 にすると斑点が分裂を続け、feed0.026kill0.051 にすると線が太く繋がって珊瑚状になる。整数の生死がにじむ濃淡に変わって、止まらない模様が定常状態として立つ。