見出し画像

BlenderのGeometryNodesでライフゲームを作る

Blender 3.5 の開発中のバージョンにシミュレーションが行えるGeometryNodesの機能が追加されていたので、とりあえずサクッとライフゲームを作りました

なんとたった33ノードで作ることができました。

512×512セル程度であれば1フレーム30msぐらいで動作させることができます

ノードの画像見ただけでは何してるか若干わかりづらい部分もあると思うので、少し解説します。

環境について

今回「Simulation Input」「Simulation Output」という2つのノードを使用するのですが、2022年12月4日現在このノードは開発中の機能で、正式リリースされている機能ではありません。

以下の記事などを参考に Blender 3.5.0 の Geometry Nodes Simulation のブランチのBlenderをダウンロードする必要があります。

https://3dnchu.com/archives/b3d-3-5a-gn-simulation/

ポイントをランダムにグリッド状に配置する

今回は次のようにジオメトリをライフゲームの要素とみなして実装を行っていきます。

  • XY平面上に並べたポイントを「セル」とみなす

  • ポイント半径が1のときは「

  • ポイント半径が0のときは「

まず、サイズ(整数)を指定してポイントをグリッド状に配置するノードを組みます。

サイズはとりあえず100とかを指定しておく

これでグリッド状に配置できるのですが、xy座標がそれぞれ1以上の整数になっているとこの先の工程において都合が良いので、ちょっと座標をずらしておきます。

以後、新しく追加したノードは囲んで表示します

次の世代を計算する

次の世代を計算するのですが、(コンウェイの)ライフゲームにおいて次の世代がであるための条件は、

  • そのセルの現在の状態が生であり、周囲に2~3つの生のセルがある

  • そのセルの現在の状態が死であり、周囲に3つの生のセルがある

のいずれかであり、いずれも満たさない場合は次の世代はとなります。

上記を愚直に実装すると少なくとも2回の条件分岐が発生するのですが、少し工夫をすることで生死判定を1回で行うことができ、

具体的には「生死判定対象のセルに該当するポイント半径の0.5倍と周囲8セルに該当するポイント半径の合計」が2.5~3.5の範囲内であれば、生です。

というのを組むと次のようになります。

上の画像のノードでは次のような工程で生死判定を行っています。

  • 生死判定対象のポイントを0.5倍してジオメトリ統合につなぐ

  • XY座標をずらした8つのジオメトリ統合につなぐ

  • XY座標とベクトル(1, 10000, 0)の内積をグループインデックスとしてフィールド蓄積を行い、これが3から0.75以内かどうかでポイント半径を1か0に決定する

  • 増やしたぶんのジオメトリの削除

このとき、今後の工程の都合に生死判定対象セルに該当するポイントはジオメトリ統合する際に一番上に来るようにしておく必要があることに注意してください。

Simulation Input/Outputノードを使う

これで0世代目から1世代目の遷移だけ実装できたので、あとは Simulation Input ノードSimulation Output ノードを、生死判定部分を挟むように配置し、フレームを再生するだけで2世代以降の世代計算も行うことができるようになります。

これで完成

パフォーマンス改善

生死判定時に周囲の死セルは値が0なので合計する必要がありません。

また、ライフゲームおけるほとんどの場面で生セルよりも死セルのほうが多くなります。

そのため予め周囲の死セルのジオメトリ自体を削除することで計算に使うジオメトリが少なくなり、ほとんどの場面で高速化が期待できます。

自分の環境ではだいたい3倍ぐらい速くなりました

おわりに

このように Simulation Input / Output ノードを使うことで前フレームの情報を参照して新しいフレームを計算することができます。

今回はシミュレーションのHello Worldとしてライフゲームを実装しましたが、うまく利用すればなんでも作れると思います。

なんなら頑張ればゲームとかも作れそうだなと思っています。

この記事が気に入ったらサポートをしてみませんか?