#はじめに
###概要
Houdini HIVE Gamedev onlineで紹介されていたLabsのWaveFunctionCollapse(以下WFC)ノードを使用方法&備忘録。
登場したてのノードなので、公式文章等が無く個人の使用感を基に書いているため所々間違っている可能性があるので、不明点等ありましたら指摘いただければ幸いです。
公式紹介
Houdini HIVE Gamedev online
https://www.sidefx.com/community/houdini-hive-gamedev/
WaveFunctionCollapse Supercharged with PDG for Level Generation
https://www.sidefx.com/contentlibrary/wfc-level-generation/
https://vimeo.com/400993662
↑HDAもDL出来るので確認してみてほしい。
4/15:追記
WFC Dungeon Generator
https://www.sidefx.com/tutorials/wfc-dungeon-generator/
公式のWFC使用チュートリアルが更新された。
###使用環境
Houdini 18.0.416
WFCノード群は18.0.400(2020/3/17 更新分)でSideFX Labsに追加されたので、使用する場合は更新する必要があるかもしれません。
#WFCについて
そもそもWFCとは、素材となるビットマップデータを基に画像をつなぎ合わせて元の素材感に似た画像を生み出す仕組みです。
https://github.com/mxgmn/WaveFunctionCollapse
↑多分この人のgithubに大体まとまっている。
Houdiniの場合はN×Nのタイルをサンプリングして、それに接続可能なタイルを自動で配置してくれるという考えが近いと思います。
#ノード説明
SideFX Labsに現在追加されているノードは3種類。すべてSOPです。
wfc_initialize
wfc_sample_paint
2d_wavefunctioncollapse
これらの紹介から。
ちなみに、WFCノードはざっくり説明すると、ポイントアトリビュートのnameに配置情報を割り当てて、そこから複製したり復元したりするよ!という感じです。
##wfc_initialize
基本的にはポイントを生成するorテクスチャを読み込むノード。
中身を見ると基本Gridで生成されているので、グリッドのポイントでも代用可能。生成されるポイントは縦横1の等間隔で生成される。
WFCはビットマップでテクスチャを扱うため、テクスチャを読み込んだ場合は1ピクセル単位でポイントが生成されるので注意。20×20ぐらいのビットマップを扱うことが多い(気がしている。)
オーバーライドに関しては2d_wavefunctioncollapseで説明する。
項目 | 説明 |
---|---|
GridResolution | ポイントのサイズを決める |
Rows Columns | 縦横に配置するポイントの数を決める |
From Texture | テクスチャを読み込む |
Texture | 読み込むテクスチャを選択 |
Overrides | nameに指定する項目を追加する |
さらに深堀り
ノードを展開すると構成はこのようになっている。![コメント 2020-04-05 031907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613929/12e2c794-8f9a-936d-aff3-b42ede9cbaf8.png) 赤:gridのpointモードでポイントを生成。wrangleはnameを作成。nameのデフォルトはWFC_Initialize(これはさほど重要ではない。) 青:Copでテクスチャを読み込みResolutionを取得し、それと同数のポイントをGridで1×1空間に生成。0-1でuvを作成してattributefrommapでテクスチャの色データを読み込み。左側は右と同数のポイントを縦横1の等間隔で用意して、そこにCdをコピー。最後のWrangleで色情報をnameに追加する。(Cd={0.2,1,0.5}の場合、name="0.2_1_0.5") 緑:指定された項目をConstraintの数分追加する。 ここからも分かるように無理にinitializeノードに頼る必要はそこまでないので、作りたい物によっては普通のGrid等で代用できることもある。##wfc_sample_paint
HoudiniのWFCノードはinitializeでテクスチャを読み込む他に、作成したオブジェクトを配置してテクスチャの代わりにすることが出来る。
処理としては、オブジェクトの持つnameデータをポイントに転写するAttribute Paintに近いかもしてない。
項目 | 説明 |
---|---|
1st INPUT | GridPointを入力 |
2nd INPUT | 配置したいオブジェクトを入力 |
Initialize Value Mapping with Input | 入力されたオブジェクトリストを表示する |
Brush | SceneViewで描きながら情報を書き込む |
Reset All Changes | 現在の書き込んだ情報を初期化する |
Value to Draw | 現在配置しているオブジェクトリストの番号を設定する |
注意点としてInitialize Value Mapping with InputはオブジェクトのPrim Attributeで設定されたname情報を基にリストを生成してくれる。警告文みたいなのは出るけど一応手動で追加することでPoint Attributeでも機能する。 | |
オブジェクトリストの番号は1からスタート。0とオブジェクト数以上の数値を設定するとオブジェクトが消える。マイナス値を設定するとエラーになるので、その時はリセットすると良い。 | |
ちなみにValue to Drawは入力中にSceneView上でセンターホイールで変更できるよ。これめっちゃ便利。 |
さらに深堀り
ノードを展開すると構成はこのようになっている。![コメント 2020-04-05 042916.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613929/afc4f97f-6296-40ed-66f9-daa136fbdca4.png) かなり複雑なのでよく分かってはいないが、ざっくり何をしているかというと上の方でストロークを入力して情報を更新、真ん中でストロークが更新されるごとに、前回のデータのキャッシュを作成して、加算情報になるように設定、下の方でプレビュー用のオブジェクトを複製、Pythonでプレビューさせている。(っぽい。) ちなみにこのノードは応用として3次元グリッドにも書き込めるので、ボクセル風の表現をしたい時には使えるかもしれない。ただし非破壊作成じゃないが。 追記:nameの扱いについてだが、プレビューを作成するところで、prim→pointにnameを転写/packしてpointのnameを扱うという工程があるため、転写取得出来ないエラーが出ることがある。##2d_wavefunctioncollapse
このノード群の主役で重役。設定された情報をWFCを使って再タイリングする。
項目 | 説明 |
---|---|
1st INPUT | GridPointを入力 |
2nd INPUT | ソースのWFCを入力 |
Automatic Input Size Detection | 2nd INPUTのサイズを自動で読み込む。 |
Sample Grid Size | 2nd INPUTで入力されたサイズをPT0を起点として設定できる。入力より大きいサイズを入力するとエラーになる。 |
Pattern Search Size | サンプリングする正方形のサイズを設定する。短辺の平方数より大きいサイズに設定するとエラーになる。 |
Find Wrapping Input Patterns | 2nd INPUTの規則性を反映させる。サーチ回数を減らせるため処理が軽くなるが、複雑な形状が生まれにくくなる。 |
Automatic Output Size Detection | 1st INPUTのサイズを自動で読み込み |
Output Grid Size | アウトプットサイズを手動で入力する。1st INPUTより大きいサイズを入力するとエラーになる。 |
Allow Rotations | サーチで回転を有効にする。処理は重くなるがより複雑な形状になりやすくなる。 |
Respect User Provided Constraints | 1st INPUTと2nd INPUTで一致するnameを比較して、パターンを固定する。 |
Produce Tileable Output | 上下左右にシームレスなタイルを設定する。パターンが均一化しやすいので、Find Wrapping Input Patternsと併用することで綺麗なタイルが出来やすくなる。 |
Seed | シード値。ここでランダム性を出す。 |
Use Observed Sample Pattern Frequency | 内部で作られたパターンを優先的に使用する。処理は重くなるが、より複雑な形状になりやすくなる。 |
Number Of Solve Attempts | 内部処理の最大回数を設定する。少なくするとエラーを出しやすくなる。 |
Starting Point | サーチの起点となるポイントナンバーを設定する。基本はランダム。 |
1st INPUTは正方形or長方形の2次元gridでしか対応してくれない。欠けていたりする場合は後から消すか、Respect User Provided Constraintsを設定すると良い。wfc_initializeSOPのオーバーライドはここでnameを反映させるために使用すると便利。一致してない場合エラーを出すことがある。※ここに関してはよい使い方を模索中。 | |
Sample Grid Sizeは3-4が適正値だと思う。小さすぎるとパターンとして不適になりやすく、過大すぎると処理に時間がかかる割に単調なパターンになりやすい。そうなるとわざわざWFCを使用するメリットが薄いと思う。設定項目でより欲しいパターンを探すと良いだろう。 |
アウトプットアトリビュートはnameとtransform(matrix3)なので、カラー情報が欲しい場合はAttribute Copyでnameを参照してソースから転写するとよい。
さらに深堀り
ノードを展開すると構成はこのようになっている。 ![コメント 2020-04-05 121308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613929/fa85f49f-8695-174c-63b7-48b62b2ee9a6.png) 左側でnameが設定されてないポイントに対して初期値を設定。 右側でサイズを取得して情報として設定 pythonで計算しているので、Hscriptに比べると少し重たいノードになっている。 その下のWrangleで90度ごとのROTをmatrix3に変換している。 現段階では2D平面でしか読み込みをしてくれないので、3次元に拡張して使いたいなぁと思うのであった。#おわりに
登場して1か月経ってないノードなので手探りなのですが、可能性を十分に含んだノードだと感じているので何かしらの手がかりになれれば幸いです。しゃーした~。