Creating Procedural Modular Level for Unreal Engine
https://www.udemy.com/course/draft/2503572/
UdemyのHoudiniチュートリアルをコツコツ進めます。
Houdiniでパスを書いただけで自動的に迷路を生成してUnrealEngineに最適な状態のモッシュを作るらしいです。
通路部分の生成の途中まで。角の判定はでき、角が外向きか内向きかをこれから取得しようというところです。
以下、発見した工夫や知らなかったノードやコードをメモしていきます。
通路とは別に、同じ大きさのグリッドを作るのですが、グリッドが常に通路を覆うように設定します。これはよくやる処理ですね。
bboxでバウンディングボックスの大きさ
centroidでセンターの位置を取得
グリッド平面と通路の面の交差を判定して、共通部分だけを残す処理をVEXで書きます。
int inter = 0;
vector P, uvw;
inter = intersect(1, @P - set(0, 0.1, 0), set(0, 0.2, 0), P, uvw);
if (inter == -1)
removeprim(0, @primnum, 1);
https://www.sidefx.com/ja/docs/houdini17.5/vex/functions/intersect.html
光線とジオメトリの最初の交差を計算
起点から最大距離分までを計算して、光線が何も交差しなかった場合は-1をかえします。
removeprim
https://www.sidefx.com/ja/docs/houdini17.5/vex/functions/removeprim.html
ジオメトリからプリミティブを削除
Primitoveのrun overなのでプリミティブごとに距離を測って、何もなければ削除します。
これも随所に見られる輪郭以外のエッジを消す処理
DividSOPのUnshared Edge
本来、分割するはずのディバイドにエッジ削除があるので忘れがち。
不要な頂点を消すのはFacetSOP
Remove Inline Points
ファセットはポリゴンのクリーンナップ系の機能を多く持つ
上記の2つを組み合わせて使うことが多い
角かどうかを判定する処理
右側の流れでは、天井と床の不要な頂点を消したもの(角以外にポイントがない)を作っているので、これともともとの壁を比較して、ポイントが近くにあるかどうかを見れば良い。
int handle = pcopen(1, "P", @P, 0.1, 1);
if(pcnumfound(handle) > 0)
i@corner =1;
ポイントクラウドファイルのハンドル
ここでは半径0.1のポイントを1つだけ取得、あった場合はポイントナンバーが入るので、0ではなくなる
コーナーを含むプリミティブだけを取り出す
コーナーを含まないプリミティブだけにするのは簡単(コーナーのポイントを消せば良い)だが、コーナーを含むプリミティブにするのが案外めんどくさい。
もっといい方法がありそうな気がするんだけど。
int prim_pts[] = primpoints(0, @primnum);
int corner = 0;
for(int i=0; i<len(prim_pts); i++)
if(corner == 0)
corner = point(0, "corner", prim_pts[i]);
if(corner == 0)
removeprim(0, @primnum, 1);
コーナーを含むプリミティブ以外を消す
run overがprimitiveなので、プリミティブごとにprim_pts[] という配列が作られて、プリミティブのポイントリストは入る
primpoints
https://www.sidefx.com/ja/docs/houdini17.5/vex/functions/primpoints.html
プリミティブ上のポイントのリスト
for(int i=0; i<len(prim_pts); i++)
if(corner == 0
corner = point(0, "corner", prim_pts[i]);
ちょっと詰まったのが、”corner”以外のcornerはプリミティブが持つ別のチャンネルということ。あんまりよろしくない名前の付け方だと思う。
この値には最初は0を代入しているが、もし0だったらポイントリストの”corner”が順番に代入される。つまりポイントリストに1以外の値があると、プリミティブのcornerも0ではなくなる。
その後、プリミティブのcornerが0のものは消す。