HOME

Maneki Pipeline

ゲーム開発のためのプロシージャル

非連続なジオメトリに連続的なマスクを設定する

SandBox:シェーダーなどで木を揺らすためのマスクを作成したい場合どうすればよいかを考えたもの

だいぶニッチな用途です。

やりたいこと

既存の木アセットに対して風などの影響を与えるためのマスクを作成したい。

ゲーム用の木を利用しようとした場合、頂点カラーでシェーダーの風の影響を受けるような設定がされていることがほとんど。

Megascan/EuropeanBeechアセットの例。風シェーダーの影響を受け取るための頂点カラーがRGBAそれぞれに異なる用途目的で割り振られている

だがこの数値はアセットごとに想定シェーダーも異なるため、特定のシェーダー前提で動かす必要が多い。
シェーダー最適化工程などを考えると

  • シェーダー統合がしづらい
  • 不要なデータを持つ可能性

といった障害となりうるため、生成済みの木に対してもコントロール可能な係数を振れる仕組みを考えたい。
やろうとしているのは「生成済みの木」に対して実行するのが肝で、ゲーム用の木は枝~小枝~葉が非連続なメッシュで構成されていることが多いのでこの状態に対して連続的なマスクを振っていく。

枝や葉っぱはメッシュとして結合していないので連続的なマスクを振ろうと考えた場合に工夫が必要になりそう

生成結果

特定の頂点カラーが割り振り済みの木の頂点カラーをいったん白で塗りつぶしてから形状に合わせたマスクを作成する

いったん頂点カラーを白にした既存の木(Megascan/EuropeanBeech)

  • 木の根本から葉先までのマスク
  • 葉の付け根の枝か、それぞれの葉先までマスク

の二通りを作成した。

木の根元から葉先までのマスク
枝の付け根から葉先までのマスク

試しにノイズで移動させると以下のように動いてくれた。(ノイズが適当で四方八方に動いていますが)

葉、木それぞれ影響度を設定する想定。

根本から木全体のマスクにノイズ
葉の付け根から葉先までのマスクにノイズ
両方のマスクを併用したノイズ適用

ノイズは以下のように2種類のマスクに対してVATでオフセットを設定するもので上記のテスト画像を生成している。

DistanceAlongGeometryノード

Houdiniドキュメント | Distance from Geometry geometry node
https://www.sidefx.com/ja/docs/houdini/nodes/sop/distancefromgeometry.html

今回利用したノードで、始点グループを定義し判定対象のコンポーネントが始点グループからどの程度離れているかのサーフェス表面上の距離を取得することができる。

始点に属するポイントからサーフェス上の距離を数値で取得できるノード

入力データ

入力に使用したのは上述のとおり頂点カラーを一度削除した既存の木メッシュ。本来はUnrealEngine向けSpeedTreeシェーダー用の頂点カラーが設定されている。

Megascan/EuropeanBeechから頂点カラーを削除

また、葉と木はMaterialが分かれているのでこれを基準にする。

葉と木はマテリアルが分かれているのでこれに準拠して分離

木の影響度のセットアップ

木全体の、根元から葉先に掛けてのマスクを作成する。

mask始点の作成
木全体のmaskの始点としてpointを作成する。
clipで木の根元のみを取得してバウンディングボックスのbottom centerを基準にした(が、木の形状によっては根があったりすると不具合が起きそうなやり方なのでここは検討の余地ありだと思う)。これに「start」というグループ名を設定。

根元の中心位置に始点用のpointを追加

影響度計算用のジオメトリを作成
葉と木全体を含むメッシュからscatterでpointを作成し、startポイントとmerge。

全体のメッシュからscatterでpointを作成

Connect Adjacent Piecesノードを点群に接続し、離散した点をつなぐカーブを作成

点群から近しい距離でカーブを作成

DistanceAlongGeometryを接続して、各点のstartからのサーフェース上の距離を取得する。

Distance Along geometryでカーブをつないだ点群それぞれの startからの距離を数値化

不具合回避としてdeleteでdistanceが-1になっている途切れたpointは削除(実装段階ではもう少し丁寧な不具合回避したほうが良いかと思います)。
attrib remapで正規化し、attribTransferで元のメッシュアトリビュートを転送。 分離したメッシュを含む、始点からサーフェース上の距離ベースのmaskができた。

構成要素をscatterし、カーブで接続した距離準拠のマスクが作成できた

葉の影響度のセットアップ

葉だけを動かすための、枝から葉先までのマスクを作成する。

元メッシュのpointから隣接カーブを作成
葉はquad polygonの集合体になっているのでscatterで計算すると葉ごとの影響度が乱数によるばらつきが大きそうなので元メッシュからConnect Adjacent Piecesでカーブを作成。こちらは始点はmergeせずにカーブを作成する。
(木のポリゴンだとポリゴン数が密度に対して差が大きそうなのでscatterしていました。似たような用途があった場合は物によって適切な隣接接続をすることになると思います)

もとメッシュの隣接頂点をつないだメッシュを作成

Distance Along Geometryで頂点それぞれに対してbranchグループからの距離を計算する。
Distance Along Geometryは特定の1点だけではなくグループ化した複数のジオメトリからの距離を計算できる。

カーブ接続した各ポイントへのbranchグループからの距離を取得

splitで枝グループのpointを削除(deleteは枝同様不具合pointの削除)

葉用のマスクなので枝グループを削除

AttribTransferで葉グループに転送すると枝から各葉pointへの距離マスクが作成できた。

カーブで計算したマスクを葉グループに転送


ニッチ用途ですが…。
精度周りはまだ調整したいものの、非連続なメッシュに連続した影響度を割り振る機会はたまにあるので、個人的にはこの「Connect Adjacent Piecesで接続したジオメトリで距離を計算し、元ジオメトリにマスクの転送」は結構色々使えそうなテクニックかなと思っています。

fish_ball

プロシージャル魚類