HOME

Maneki Pipeline

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

EnumerateとPackのススメ

enumerateノードとpackノードを使ったいくつかの用途

enumerateノードについて

enumerateノードは指定の要素ごとに0から始まるindexを割り振ることができる。

Houdini Document| Enumerate geometry node
https://www.sidefx.com/docs/houdini/nodes/sop/enumerate.html

index割り振りとしての機能

indexを取得する用途
基本的な使い方としてコンポーネントごとの番号をアトリビュートとして作成できる。

VEXを書いた際に記述する機会の多い「以下のようなポイント番号、プリミティブ番号を保持する処理」と同等になる。
i@index = @pointnum;
i@index = @primnum;

プリミティブに順番でindexを振って、それに応じてcolorを割り当て
事前にindexを割り振っておき、変形後に保持していたindex準拠で処理を実行

アトリビュート基準のindex割り振り機能

enumerateノードの優れた機能として、「アトリビュートの値を参照してindexの割り振り」機能がある

アトリビュート値を基準とした疑似的なgroupのような用途
同一のアトリビュートを持つコンポーネントごとにindexを割り振った、groupのような使い方もできる

  1. fabなどからfbxをダウンロード(画像はEuropeanBeech/SM_EuropeanBeech_Field_01)
  2. (option)deleteでLOD0以外を削除、AttribDeleteで頂点カラーを削除
  3. enumerateノードで piece attributeをshop_materialpath
  4. (option)ColorノードでColorType/ Random from Attributeでindexごとにランダムカラーを割り振り
Enumerateによるアサインマテリアル名に応じた色の塗分け

この「indexによるグループ分けはgroupを作成する場合に対していくつかのメリットもある

不特定多数を対象に処理の分割

boolであるgroupと異なりintで管理できるidは不特定多数の分割対象に対して処理を実行しやすい。
例えば、以下のように入力メッシュにアサインされているマテリアルごとにforeachで処理の単位を分けることができる

for eachでpiece attributeにパーツ分けしたindexを指定すると各パーツごとに処理ができる

COPとの親和性が高い
Copernicusにはidの値からmaskを作成する機能があるのでmaskでわけたいメッシュごとにindexを割り振っておくとマスクわけが楽にできる

IDはCOPに入力するとすぐにmaskにできる

などの利点がある

mesureと組み合わせて要素に合わせたソート

アトリビュートで割り振った場合、値が小さい方からindex付けをしてくれるのでmeasureと組み合わせることでmeasureで測定した値、たとえば面積に準ずるソートなどもできる。

  1. measure:primごとの面積(Area)を取得
  2. primwrangle:index化するためにareaを100倍(int型にする必要があるので)
  3. attribcast:areaをint化
  4. enumrate:areaをPieceAttributeに指定 これでareaが小さい方からindexが作成される
  5. sort:PrimをPrimitiveSort/ ByAttribute、Attribute/ indexで指定してPrim番号をindex順に並び替え
  6. Color:RampFromAttributeでindex順に色付け
面積順にソートして大きいほど濃い色を設定

Packノードについて

ジオメトリをインスタンスとして扱うためのノードで軽量化などのメリットがある

Houdini Document| Pack geometry node
https://www.sidefx.com/docs/houdini/nodes/sop/pack.html

packの特徴

Packは複数のコンポーネントを一つのコンポーネントとして扱うための方法。
CopyToPointsで作成できるインスタンスやAssebleの設定で作成できるpackもこの状態。

複数のPointやPrimitiveを単一のコンポーネントして扱う状態

packには特に効率化に関してのメリットが有り、

描画の高速化

背景配置時のオブジェクトなどをpackしておくと簡易表示にすることで描画を高速化するできる

配置時にPackしておいて簡易表示にする

処理の最小化

Pack中に設定したアトリビュートはunpack時に含まれるコンポーネントすべて反映することができるので、例えば「HoudiniEngine用にunreal_materialアトリビュートを対象のプリミティブに設定する」みたいな処理を最小限の実行回数で行える

Packしておくと複数のPointやPrimitiveに設定したい値をまとまりごと一回ずつの処理に圧縮できる

配置がしやすい

pack状態は含まれるコンポート全体で位置情報を持つので配置などが行いやすい

描画の高速化ももちろんだが、単純にPack単位で扱えるので配置などで扱いがしやすい

といったメリットがある。

アトリビュートによるPack分け

このpackだがPackノードの設定項目で指定の要素でpackされたコンポーネントを作成することができるので前述のenumerateと同じようにgroupのような扱いができる。

NameAttributeに分離の基準となるアトリビュートを指定すればそのアトリビュートが共通のコンポーネントをパックしてくれる

packされたコンポーネントではpack単位で行われるのでたとえばアサインマテリアルの情報を参照するなどの、まとまりごとに一度しか行わない処理と非常に相性がいい。

アサインされたマテリアルごとに処理を行う
packされたコンポーネントではwrangleなどの処理が一度しか実行されないので、共通のアトリビュートをもつコンポーネントの中でループの回数が最小限で済む
例えば以下の例ではこれでマテリアルごとに実行したい処理をすべてのPrimitiveではなく、マテリアルごと4回のループで実行できる

  1. FBXを読み込み
  2. PackノードのName Attributeにアサインされているマテリアル名である「shop_materialpath」を指定
  3. primWrangleでマテリアルごとに実行したい処理を作成 (ここでは「material名 + bc」をbc_textというアトリビュートで保存
  4. unpaclk時に bc_tex アトリビュートをTransfer Attributeに設定。
Packして処理を行うと処理を少ないループ回数で属するすべてのコンポーネントに適用できるのでマテリアルごとに行いたい処理などに適している

PackとEnumerateの組み合わせ

ここまで述べた通り、packもindexも毛色の違うgroup分けとして利用できるのだが、組合わせての利用もしやすい

indexによるPack
indexでpackの参照条件がアトリビュートとして指定できるのでenumerateで分けておくとpack、unpackがしやすい。
以下の例では先にenumerateでindexをつけておき、高速に処理したいときにindex準拠のPackを行っている。

PackのNameAttributeはIntも指定できるのでenumerateでindexを作成しておくと高速にしたい処理の時だけPack、UnPackができる

Packグループの保存用途

また逆にpackした状態でenumerateするとpackごとにindexを割り振ってくれるのでpackの状態を保存できる。
以下の例ではPackでの処理中にenumerateでindexを保存しておいて、あとから再度Indexを基準にして再度Packに利用する。

Pack中にenumerateでindexを振っておいてunpackすればいつでも再度Packできる

Packオブジェクトをindexでコピー

CopyToPointsでPackしたオブジェクトをindex付けし、indexによってコピーすると楽

  1. CopyしたいPack済みオブジェクト単位でenumerateでindexを振っておく
  2. コピー対象のpointに同様のindexを割り振る
  3. copy to pointでPieceAttributeにindexを指定
PackとIndexを利用してCopyToPointで分散コピー

Packを使うとループ処理がかなり高速になります。
Enumerateを使うとPack、Unpackがかなりしやすくなります。

indexで処理単位を分けるのは一気にプログラミング的な扱い方になってしまうものの、いろいろな用途に使え、慣れると処理を分けるのが迅速になり、Packとの組み合わせで処理自体も高速化できるので便利です。

fish_ball

プロシージャル魚類