頂点座標値と頂点インデックスの画像データ出力について


こちらの記事では、頂点座標値と頂点インデックスを分けて画像出力を行う際の設定や、ネットワーク構築の一例についてご紹介致します。


Labs Vertex Animation Textures ROPノードを使用したデータの出力では基本的に、
メッシュデータ(fbxファイル)
頂点情報が記録された画像データ(Position Mapなど)が出力され、
必要に応じてゲームエンジン側で設定を行う際に、必要となる数値を記録したデータ(jsonファイル)を出力可能にするオプションが用意されています。


Position Mapは、メッシュの頂点が共有するポイントの位置座標情報がフレーム番号と関連付けられて記録されています。
そのため、メッシュの構築も含めて画像データから行いたい場合は、別途ポイント番号に対応した頂点情報を記録した画像データが必要となり、それに適したアプローチをとる必要が出てきます。

今回は、下図のような画像データの出力を行う場合の一例を紹介します。

SideFXLabsツールのインストール手順

SideFX Labsツールセットのインストール手順については、以下の記事をご参照ください。

●Houdiniの内部システムからの直接インストール
●Githubからの手動インストール

Labs Vertex Animation Textures ROPノードについて

記事で使用している「Labs Vertex Animation Textures ROPノード」については、こちらの記事をご参照ください。

こちらの記事では、Houdini18.0.597を使用しています。

サンプルファイルについて

記事で使用しているサンプルファイル等は、以下からダウンロードすることができます。

記事の流れは、以下の1~4になります。

  1. はじめに、出力するVATのピクセル数を決める際に必要となる頂点とポイントの総数の最大値を取得します。
  2. 次に、フレーム毎に変化する頂点とポイントの総数を記録するため、ボリュームデータを使用してボクセルに値を格納します。
  3. その後、画像データへ変換する前に一度キャッシュデータを作成します。
  4. 最後に、ここまでのネットワークをLabs Vertex Animation Textures ROPノードの一部として組み込みます。

以上が、本記事の概要です。


1.頂点とポイントの最大数の取得方法について

Houdini内では、頂点とポイントは異なるアトリビュートタイプとして、扱えるようになっており、保持することができる情報も異なります。

  • 頂点アトリビュートは、頂点の共有するポイント番号を保持することができます。
  • ポイントアトリビュートは、位置座標を保持することができます。

初めに、アニメーションから頂点とポイントの総数を取得する段階まで順を追って説明します。
総数を取得することによって、画像を生成した際のピクセル数の制御に使用することができます。

1-1.アニメーションを設定します。画像出力を行った際に、ベイクされている様子の確認を行いやすくするため、ここではポリゴンの枚数を増減させる非常に簡易的なアニメーションをつけています。詳細は、サンプルファイルをご覧ください。

1-2.新しくGeometry Objectノード(Linear_VAT_Sample)を作成して、この中で詳細なネットワークを作成します。先ほど作成したアニメーションは、Object Merge SOPノードを使用して読み込みます。

1-3.Attribute Wrangle SOPノードを使用して、 ポリゴン一枚あたりの頂点数を取得します。Run Overは[Primitives]に切り替えます。

※補足 : Attribute Wrangle SOPノードのRun OverパラメーターをDetail (only once)モードに切り替えた場合は総頂点数を取得することができますが、こちらのモードは一度きりの処理を行うため、総頂点数の更新が行われません。
そのため一度、ポリゴン一枚あたりの総頂点数を取得したのちに、ポリゴンの枚数分の総頂点数を計算し直す必要があります。

1-4.Attribute Promote SOPノードを追加し、total_vtxのアトリビュートタイプを[Primitives]から[Detail]に切り替え、全ての頂点の合計数で上書きします。

1-5.Attribute Promote SOPノードを追加し、アトリビュートタイプを[Detail]から[Point]に変換します。これで、ポイントアトリビュートに総頂点数を取得することができます。

1-6.Blast SOPノードを追加し、アトリビュートを持つポイントを1つに絞ります。

1-7.CHOP Networkを作成し、中にGeometry CHOPノードを作成します。CHOP を使用して、フレーム範囲における頂点の総個数の最大値を取得するための設定を行います。

Geometry CHOPノードのGeometryタブ内のパラメータは、下の画像のように設定することで、SOPコンテキスト内のポイントからtotal_vtxアトリビュートを取得し、アトリビュートのチャンネルが作成されます。

Node Infoを確認すると、Attribute Scopeパラメータでチャンネル作成の対象となったアトリビュートの最小値と最大値が得られることが確認できます。

1-8.Expression CHOPノードを追加し、HScriptエクスプレッションのicmax関数を使用して、total_vtx0の最大値を評価します。

最後に、SOPコンテキスト内で再読み込みを行うため、Output CHOPノードを接続しておきます。

1-9. SOPコンテキスト内でChannel SOPノードを作成し、CHOPコンテキスト内で評価したtotal_vtx0の最大値をtotal_vtxにリネームして取得します。
ここでは、頂点数60個が最大値であることが分かります。

ここまでの処理により、頂点の最大個数を取得できます。

1-10. 同様にポイントの最大個数を取得していきます。Attribute Wrangle SOPノードを使用して、ポイントの総個数をtotal_ptアトリビュートとして作成します。

1-11. 頂点の最大個数を取得する際と同様に、アトリビュートを持たせるポイントをBlast SOPノードを使用して絞ります。その後、CHOP Networkを使用してフレーム範囲以内におけるポイントの最大個数を取得します。
アトリビュートの名前が異なるのみで、ネットワークの構成は全く同じです。

240フレーム範囲内におけるポイントの最大個数は17であることが確認できます。

以上の流れで、頂点数やポイント数がフレームによって変動するアニメーションにおける、頂点の最大個数とポイントの最大個数を得ることができます。
この値を、縦もしくは横のピクセル数として使用し、画像データのサイズを調節していきます。


2.ボリュームデータへの変換

次のステップとして、SOPコンテキストとCOPコンテキストの組み合わせで、画像データのベースとなるボリュームデータを作成します。

ボリュームデータはボクセルという正規格子単位で構成されています。奥行がなければピクセルと同様に扱うことができるので、SOPコンテキストでも画像データのベースは作成可能です。

今回は一例として、SOPとCOPコンテキストを交えて扱う方法で進めていきます。

2-1.COP2 Networkを作成します。

2-2.COPコンテキストに入り、Color COPノードを作成します。

2-3. 次にパラメータの設定です。ここでは、最終的に出力する画像はデフォルトで縦にフレーム数、横に頂点インデックスを記録するようにします。
また、アルファ値に対して保存するように指定します。

そのため、xの値はpoint関数を使用し、先に用意したtotal_vtxアトリビュートの値が入力されるように指定します。
yの値は「$FEND – ($FSTART -1)」を入力することで、開始フレームが0番である場合でも、正確なフレーム数が取得できます。

2-4. SOPコンテキストに戻り、COP2 Networkのパラメータを変更します。
Methodパラメータを[Mesh]から[Volume Slice]に切り替えておきます。これによって、COPコンテキスト内の平面やコンポーネント毎に2Dボリュームが生成されます。

2-5.Volume Wrangle SOPノードを追加し、COP2 NetworkのアウトプットからVolume Wrangle SOPノードのインプット1に接続します。

VEXpressionに「@A = -1;」と入力し、ボクセルのデフォルト値を-1に設定しておきます。

2-6.Time Shift SOPノードを追加します。後ほどボクセルに頂点インデックスを記録させる際に、ループ処理を行う必要があるのですが、その際に使用します。ここではノードだけ先に作成し、_IN(Null SOPノード)と接続しておきます。

2-7.もう一つVolume Wrangle SOPノードを追加し、インプット1をvolumewrangle1のアウトプットと接続し、インプット2をtimeshift1のアウトプットから接続します。

2-8. 続けて、volumewrangle2に記述を行っていきます。
1行目はnvertices関数を使用して、インプット2から入力したジオメトリの頂点数を取得します。

2行目、3行目はボリュームのx軸y軸方向のボクセルインデックスを取得します。ixやiyのような変数は、バインド変数に@をつけることでアクセスできます。
row_numberという変数を作り、その中にx軸方向の取得した数値を入れます。
column_numberには、y軸方向の取得した数値を入れます。

4行目にchi関数でパラメータを作成します。このパラメータは、クックするフレームの番号を取得するために用意しています。
また、先ほど作成したTime Shift SOPノードのFrameパラメータと関連付けをしておきます。

最後に、vertexpoint関数を使用して、頂点が共有するポイント番号を取得します。
処理は、x軸方向のボクセルの数がtotal_vtxアトリビュートの値以下であることと、フレーム番号とy軸方向のボクセルの番号が同じであることを満たした場合に実行されます。
取得したポイント番号をアルファに格納します。

タイムスライダーを動かすと、フレーム番号に対応した行のボクセルに値が保持される様子が確認できます。
下の画像は、0フレーム目、12フレーム目、24フレーム目、36フレーム目、48フレーム目の結果を並べたものです。

2-9. 全フレーム分保存できるようにするため、Foreachによってフレーム数と同じ回数分、処理を繰り返します。
For-Each Numberを追加し、下の画像のように接続します。

foreach_end1(Block End SOPノード)のGather Methodパラメータを[Feedback Each Iteration]に切り替え、Iterationパラメータに「$FEND-($FSTART-1)」を入力し、フレーム数を反復回数に指定します。

加えて、foreach_begin1(Block Begin SOPノード)をコピーし、volumewrangle1とvolumewrangle2の間に配置します。また、Methodパラメータは[Fetch Feedback]に切り替えます。

最後に、Time Shift SOPノードのFrameパラメータにiterationアトリビュートを入力します。
このアトリビュートは、foreach_count1(Block Begin SOPノード)によって生成されたDetailタイプのアトリビュートです。detail関数を使用して、取得することができます。

ここまでの設定で、頂点インデックスを記録した画像のもとデータの生成ができました。

2-10.ポイントの位置座標用のデータも同様にして作成していきます。初めに、下の画像のように、ネットワークを複製します。

2-11.複製したCOP2 Networkに入り、Color COPノードのパラメータを変更します。

アトリビュートを読み込むノードまでのパスを変更し、読み込むアトリビュート名もtotal_ptに変更します。また、こちらはRGBとして保持するように指定します。

2-12.attribwrangle4のVEXpressionを「v@C = 0;」に変更します。

2-13.attribwrangle3の記述を変更します。

npoints関数でインプット2から取得したジオメトリのポイント数を取得します。point関数でx軸方向のボクセルインデックスに応じたポイントの座標値を取得して、カラー情報として保持するように設定します。

以上で、先ほどの頂点インデックスを保存したデータに対応した、Position Mapのベースが生成できました。x軸方向のボクセル数は、頂点が共有しているポイントの最大数に依存します。

3.キャッシュの作成と書き出し

ジオメトリのキャッシュファイルの作成と、画像データ(exr形式)への書き出しを行います。

3-1.SOPコンテキスト内にTOP Networkを作成します。

3-2.TOPコンテキストに移動します。ここで、ROP Geometry Output TOPノードを作成します。

ROP Geometryタブ内のSOP Pathパラメータに先ほどのボリュームデータをパスで読み込み、Output Fileパラメータに出力先の指定します。ここでは、ファイルフォーマットはbgeo.scに設定しておきます。

3-3.ROP Geometry Output TOPノードを複製し、位置座標値を記録しているボリュームのキャッシュ作成用に設定を変更します。

3-4.Partition by Index TOPノードを使用して、ネットワークをまとめます。

3-5.SOPコンテキストに移動し、File SOPノードを作成します。こちらも、頂点インデックス用と位置座標用で2つ用意しておきます。

ROP Geometry Output TOPノードのOutput Fileパラメータと、File SOPノードのGeometry Fileパラメータは、パスで関連付けておくことで、出力したキャッシュファイルが自動で読み込まれるようになります。
下の画像は、頂点インデックス用のノードですが、頂点座標用のノードにも同じように設定を行います。

処理を実行する際は、TOP NetworkのParameter View上の「Cook Output Node」ボタンを押します。

3-6.画像変換用のCOP2 Networkを追加します。

COPコンテキストに移動し、先ほどキャッシュを取得したベースデータを読み込んできます。SOP Import COPノードを2つ用意します。

SOP Import COPノードのSOPパラメータから、読み込むノードのパスを入力します。

SOP Import COPノードのOverride Sizeパラメータの値は、Color COPノードのOverride Sizeパラメータの値と合わせておきます。
また、Image Planeパラメータも合わせておきます。

同様に、もう一方も解像度とImage Planeパラメータを合わせます。

3-7.SOP Import COPノードに続けて、Flip COPノードとレンダリングの際の目印として、Null COPノードを接続します。

3-8.TOPコンテキストに移動し、ROP Composite Output TOPノードを追加します。

COP Pathパラメータからパスを使用して、先ほど作成したNull COPノードを読み込むためには、ROP Composite Output TOPノードの[Use External COP]チェックボックスにチェックを入れ、有効にする必要があります。

ここまでの設定を行い、TOP NetworkのParameter View上に用意されている[Cook Output Node]ボタンを押して、書き出しを開始します。

以上の流れで、下の画像のようなexrファイルの出力ができます。

※補足 : 頂点情報はアルファチャンネルに保存されます。Photoshopを使用して画像データの確認を行う場合、アルファチャネルを有効にすると確認できます。

4.HDAへの組み込み

3章までのネットワークをLabs Vertex Animation Textures ROPノードに組み込む場合の一例を、ここではご紹介します。

4-1.outコンテキストへ移動し、Labs Vertex Animation Textures ROPノードを作成します。

4-2.Labs Vertex Animation Textures ROPノードを[Allow Editing of Contents]で編集可能にします。

4-3.SOP Networkを作成して中に入り、先ほど作成したネットワークをコピーします。

4-4. 一つ上の階層に戻り、Geometry ROPノード2つと、Composite ROPノード2つを接続します。
Geometry ROPノードでキャッシュファイルを作成し、Composite ROPノードで画像ファイルの出力を行います。

作成した2つのGeometry ROPノードのパラメータは、以下の画像のように設定します。読み込むSOPノードは、先ほどコピーしたSOP Network内のノードを読み込みます。

作成した2つのComposite ROPノードのパラメータは、以下の画像のように設定します。
こちらも、SOP Network内にコピーしたCOPノードを読み込んできています。

出力先のファイルパスと、Plane Scapeパラメータの設定は忘れずに行います。

4-5.SOP Network内に入り、Object Merge SOPノードのパスを、Labs Vertex Animation Textures ROPノードのSOP Pathパラメータと関連付けます。

4-6. SOP Network内のFile SOPノードのGeometry Fileパラメータと、Geometry ROPノードのOutput Fileパラメータを関連付けます。
これで、出力されたキャッシュファイルが自動で読み込まれるようになります。

もう一つのFile SOPノードとGeometry ROPノードに対しても同様に行います。

Labs Vertex Animation Textures ROPノードのRenderボタンを一回押すことによって、一連の処理が実行されるようになるかと思います。

紹介する内容は、以上です。
今回は、頂点インデックスと頂点座標値(Houdiniではポイントの座標値)を対応づけた2枚のテクスチャを生成するネットワークの例を紹介しました。こちらでは、試しませんでしたが、ポリゴンの描画に必要な情報がこの2枚で補える可能性があります。

この点につきましては今後調査を行い、可能である場合は、追って記事としてまとめることができればと考えております。