この記事では、Houdini を活用した「事前に分割したメッシュを Niagara でピースごとに動かす方法」を紹介します。
リアルタイムに VAT を作るような処理をしています。
対象読者
・エフェクトデザイナー
・Niagara or Houdini を学習中の方
環境
・Houdini 22.0.368
・SideFXLabs 22.0
・Unreal Engine 5.8.2
前提
Houdini Niagara Plugin を使用
導入については以下記事を参照ください。
解説範囲
情報量を完結にするため、以下で動作するものを紹介します。
・Niagara は Local Space = False
・配置した Niagara の 回転/拡縮 は考慮しない
今回紹介する手法の概要
UE でリアルタイムに VAT を作り、対応するメッシュのピースを WPO で動かしています。
メリットは「多様な形状に分割されたメッシュを簡易的なコリジョン付きで壊せること」です。
近しい手法も簡単に紹介します。
今回のものはあくまで手段の1つであり、扱いたいピースの個数や規模感などにより以下の方法が適切な場合も多くあります。
| VAT | 魅力的なルックを作れるがコリジョンに反応できない |
| Chaos Destruction | 動的に制御できるが処理負荷が高くなりがち |
| Houdini Niagara Plugin の Point Cache で初期位置を参照 | 軽量に説得力のある破壊を作れるが、ピースごとにメッシュが必要なためドローコールを気にする必要あり |
Houdini でメッシュとポイントキャッシュを書き出し
こちらが Houdini の処理の全体像です。以降で解説します。

[全体像]
Voronoi 分割


『voronoifracture1』『testgeometry_rubbertoy1』はデフォルトのままで問題ありません。
『explodedview1』は分割したメッシュを確認するデバック用として使用しています。
voronoifracture1

・Voxel Size = 0.05 : 精度を高めに設定
・Fog VDB = True : Distance VDB よりも内部に均一にポイントを配置しやすい
scatter1

・Force Total Count = 100 : この数値がおおよその分割個数
分割されたピースごとに Attribute を設定

『foreach~』を使用し、ピースごとに処理を実行します。
『foreach_begin1』『foreach_begin2』の Method は それぞれ “Extract Piece or Point”, “Fetch Metadata” です。
attribwrangle1

// Metadata取得
int index = detail(1, "iteration", 0);
int count = detail(1, "numiterations", 0);
// グリッドサイズ
int cols = max(int(ceil(sqrt(float(count)))), 1);
int rows = max(int(ceil(float(count) / cols)), 1);
// UV座標
int ix = index % cols;
int iy = index / cols;
vector sampleIndex = set(ix, iy, 0.0);
vector uvPosition = set((float(ix) + 0.5) / float(cols), (float(iy) + 0.5) / float(rows), 0.0);
// PrimitiveとVertexに属性を設定
for (int prim = 0; prim < nprimitives(0); prim++)
{
setprimattrib(0, "UV_Sample_Index", prim, sampleIndex);
int vertexCount = primvertexcount(0, prim);
for (int vtx = 0; vtx < vertexCount; vtx++)
{
setvertexattrib(0, "uv1", prim, vtx, uvPosition);
}
}
・Run Over = Detail (only once)
・ピースごとに以下の Attribute を持たせている
・uvPosition:Niagara で読み取る番号
・uv1:メッシュの新しい UV
ここで設定した UV をもとに Niagara で VAT を作成します。
また、Niagara テクスチャを作る際は座標ではなく番号を使うため、”sampleIndex” は正規化していません。
attribcreate1

・ピースごとの Bounding Box を Attribute にもたせる
└これをもとに後の処理で Bounding Sphere を計算し、それを Niagara にわたす
foreach_end1


・Piece Attribute = name : voronoifracture1 で各ピースに設定された “name” でループを回したいため
メッシュに最低限の情報 + Pivot 情報を追加

・『triangulate1』:三角形にし Unreal に読み込んだ際のエラーを予防
・『normal1』:法線を設定
・『autouv1』:UV を作成。今回は特に使わないが形式上の設定
transform1

・Unreal の回転と拡縮に合わせる
extractcentroid2

・Output = Attribute
・Centroid Attribute = PivotPosition
attribwrangle3


// 属性取得
vector PivotPosition = prim(0, "PivotPosition", @primnum);
// UVに格納
v@uv2 = set(PivotPosition.x, PivotPosition.y, 0.0);
v@uv3 = set(PivotPosition.z, 0.0, 0.0);
・Run Over = Vertices
・各ピースの Pivot を UV2, 3 に格納
ポイントキャッシュを書き出す

extractcentroid1


・各ピースのピボットをポイントに変換
・「Transfer Attribute」で Niagara に渡したい Attribute を Point に引き継ぐ
attribwrangle2
f@pscale = length(v@bbox) * 0.5;
・Run Over = Points
・各ピースのバウンディングボックス(vector3)をもとに pscale(float)を作成
niagara1

・Frame Range : Render Current Frame
・Keep Attributes : 標準の設定に “UV_Sample_Index” を追加
UE で動かす
マテリアル


・回転/拡縮を考慮しない最小構成。
・Niagara から Position と Rotation(Quaternion) を受け取り、頂点位置を移動/回転、法線を回転させている。
・Tangent Space Normal = False。
Niagara で動かす

[全体像]
Emitter Spawn



| Houdini Point Cache Info | Houdini から書き出したキャッシュを割り当てる。 |
| RT Pos, RT Rot | メッシュの uv1 に割り当てた縦横(cols、rows)と同じサイズにする。 Override Format = True にし、Format は精度が高い RTF RGBA 16f。 |
Emitter Update


・Houdini Point Cache Info を参照
Particle Spawn



| Sample Spawned Houdini Point Cache | Houdini から書き出したキャッシュを割り当てる。 SetLifeTime, SetVelocity は False。今回は Houdini で設定していないため。 |
| Position | キャッシュに設定した位置を取得(各ピースのピボット) |
| HasTriggered, Impluse | False。Particle Update で使用する前の準備。 |
Get UV Sample Index



・キャッシュに設定した Sample_Index(メッシュの uv1 に対応する番号)を取得。
・Get Float Value の番号はキャッシュファイルの Array Index に合わせる。
Particle Update




| Impluse | 3秒後に1回だけ True。 |
| HasTriggered | 3秒後から True。 |
| Collision | 今回は GPU Distance Field を使用。 Particle Radius は Houdini から持ってきた値を使用し、Particle Radius Scale で調整。 |
Force 系


Impluse, HasTriggered を使い分けて設定してください。
一度起動したら継続的に作用してほしい Gravity などは HasTriggered、Point は一回だけでいいので Impluse といった形です。
Bake RT


・RT に位置と回転を焼き付けている。
Render

上の Mesh Render はあくまでデバッグ用です。特別な設定は不要です。
矢印などデバックとしてわかりやすいメッシュを割り当ててください。
Bake RT

・Houdini で用意したメッシュと専用のマテリアルを割り当てる
・Source Mode = Emitter : パーティクルではなく Emitter に対して生成されるようにする
完成
まとめ
今回の手法を用いることで、多様な形状に分割されたメッシュを簡易的なコリジョン付きで壊すことができます。
他の手法と比較し メリット/デメリット ありますので、適切に使い分けることが重要かと思います。
この記事が破壊エフェクトを作るうえでお役に立ちましたら幸いです。

