Houdini 20.0 Maya

Mayaプラグインコードの紹介

On this page

理想の世界ではコードは一目瞭然になっていて、ほぼ理想の世界では、コード以外の部分に適切にコメントが付けられていることでしょう。 Mayaのプラグインはほぼこれに当てはまると信じたいところですが、コードに関心のあるユーザが直感的でない部分を乗り越えられるように、このセクションを用意しました。 DGでは通常、Houdiniプラグインは以下の図のようになっています:

(今回)ここで注目したいのは、このプラグインでの命名がHoudini基準であることです。 例えば、houdiniInputGeometry1は、MayaからHoudiniへの入力です。 Output Node Idアトリビュートは、HoudiniからMayaに出力されます。 この命名規則は、コード全体で一貫しています。 Input クラスとメソッドはHoudiniへの入力、 Output クラスとメソッドはHoudiniからの出力に使用します。 Get メソッドはパラメータ値を取得し、アトリビュートを設定します。 Set メソッドはアトリビュートを取得し、パラメータ値を設定します。

もう1つ注目したいのは、ノードアーキテクチャの非対称性(一対一の関係性がない)です。 入力ジオメトリは個別の入力ノードによって変換されてEngineに転送されているのに対して、すべてのMaya出力ジオメトリの出力Mayaデータはアセットノードによって計算されています。これにはメリットとデメリットがあります。まず、以下のことが可能になります:

ただし、ユーザに表示されるメインインターフェースは、アトリビュートエディタ内のアセットノードです。これは、以下を意味します:

また、アセットノード自体にもアトリビュートの非対称性(一対一の関係性がない)があります。 私どもは、パラメータには動的なアトリビュートを追加するようにしました。 というのも、アセットには好きなようにパラメータを追加してそれを好きなようにフォルダに整理することができることを踏まえると、実質上、この方法しか選択肢がありませんでした。 すべてのパラメータアトリビュートは、houdiniAssetParmアトリビュートのCompound(複合)型の子アトリビュートとして追加されます。 アセットの入力には独自の非動的入力マルチアトリビュートがありますが、オブジェクト参照をHDAのパラメータにエクスポートした場合には、そのオブジェクト参照がそのHDAの残りのパラメータアトリビュートと一緒に取り込まれます。

出力は動的ではありませんが、複雑なCompound(複合)型アトリビュートを複数持たせています。 これは、出力ジオメトリを可能な限り網羅するためです。 実際、Houdiniのアトリビュート構造は、Autodeskが内部でテストするものよりも複雑なようで、時々Mayaが正常に動作しなくなることがあります。 2018.4や2019.0で試みたユーザは、お気付きでしょう。 本当の問題は、 outputObjects/outputGeos/outputParts アトリビュートがネスト化され、それぞれのoutputPartにあらゆる出力ジオメトリを記述するのに十分な子アトリビュートがあることです。 ジオメトリ(またはオブジェクト)レベルのネスト化を省くことで、出力階層を平坦化できたでしょうか? または、各パートのジオメトリタイプ毎に出力ノードを分けることで、パートコンパウンドを分割できたでしょうか? そうしていたら、Mayaのバグに遭遇するリスクを減らせたでしょうか? 結果論ですが、実際に試してみないと何とも言えません。今後Mayaの難解な不具合に遭遇した場合に、これらは検討する余地があります。

プラグイン

  • plugin.C

これは、通常のプラグイン操作(プラグインのロード/アンロード、ノードおよびコマンドの登録/登録解除)を処理します。 また、Engine側のプラグインのロードも処理します。

  • Engineセッションの管理(HARSプロセス)

  • optionVarの管理(これらの大部分はセッションや環境を参照するため)

  • Engineとやり取りする、時間単位での処理の管理

プラグインがロードされると、HARSセッションを作成するか(自動起動がオンの場合)、指定したパイプやソケットを介して既存のHARSサーバーに接続します。 プラグインをアンロードする時は、セッションを終了し、必要に応じてサーバーも終了します。 Houdini17.0以降はプロセス内のセッションをサポートしていませんが、プロセス内セッションコードは現在もプラグイン内に存在します。 プラグインをロードするとEngineセッションが開始されますが、アセットがロードされたり、ノードが作成された場合にのみ、ライセンスが取得されることに注意してください。

ノードとコマンド

Mayaノード:

  • 入力ノードおよびマージノード: ジオメトリデータをHDAに取り込みます。

  • assetNode: パラメータ値とアニメーションを取り込み、HDAをクックし、出力ジオメトリをMayaデータに変換します。

Mayaプラグインコマンド:

  • Engineセッションステートにアクセスし、アセット定義をロードします。

  • アセットノードを作成し、アセットのパラメータに対応するMayaのアトリビュートを追加します。

  • 出力アトリビュートのデータに基づいて、Mayaの出力ノードを作成します。

Maya MELコード:

  • 入力ノードを作成し、それをアセットノードに接続します。

  • (他のすべてのUIについても当然可能ですが、驚くには当たりません)

入力ノード

MayaにはメインのHoudiniアセットノードが1つあり、そのアセットノードに、MayaジオメトリをHoudiniに取り込むための様々な変換ノードを接続します。 入力MayaノードがEngineに入力ジオメトリオブジェクトを作成し、HoudiniのノードIDを出力します。 AssetNodeはノードIDを使用して、Engine側でアセットの入力に接続します。

入力ノードタイプ毎に1つのクラスが用意されています。

  • houdiniInputGeometry (InputGeometryNode.C)は、メッシュパーティクルと単一のカーブ入力を処理します。

  • houdiniInputCurve (InputCurveNode.C) - 複数の入力カーブ

  • houdiniInputTransform (InputTransformNode.C) - トランスフォームアトリビュートでパーティクルに変換された複数のトランスフォーム(UIが現在サポートしているのはロケータのみですが、トランスフォームは機能します)

  • inputMergeNode (InputMergeNode.C) - Houdiniでマージノードを作成し、Engine側でその入力を接続します。

入力ノードにはそれぞれ入力オブジェクトがあり、これが呼応するHoudiniジオメトリノードを実際に作成する作業を行ないます。 入力オブジェクトにはcompute()メソッドもあるため、派生したMayaクラスまたはHoudiniのユーティリティオブジェクトのどちらが対象かについて把握しておく必要があります。 入力オブジェクトの階層は以下の通りです:

  • Input.C

    • InputCurve.C (単一のカーブ入力 - 廃止)

    • InputMesh.C

    • InputParticle.C

アセットノード

  • houdiniAsset (AssetNode.C) - Mayaノード関連、アトリビュートを定義します。

  • Asset.C - assetNodeはアセットオブジェクトを保持し、MayaとEngine間のインターフェースを管理し、Houdiniオブジェクトから出力データを作成します。compute()メソッドもあり、ノード計算で行なわれることをそれとなく示しています。

これ以降のセクションは、コードを見て、それらがどう組み合わされるかに関心がある方なら楽めるでしょう(それでも退屈に感じる人がいるかもしれません)。

ノードメソッド

AssetNode.Cを見ると、その約3分の2は出力アトリビュートの構築であることが分かります。 出力アトリビュートは、可能な限りの出力ジオメトリを網羅することを目的としているため、多くなっています。 完全なリストは、Houdiniアセットのノードに関する説明を参照してください。

次に、通常のノードメソッドを必要に応じてオーバーライドします。以下に、面白いHoudini関連のこと、少し奇妙なMaya関連のことが起こる例を示します。

  • アセットノードがサーバー側で作成/削除されるようにします。

    • nodeAdded()nodeRemoved()postConstructor()createAsset()destroyAsset()

  • シーンのロード時にアセットをセットアップします。

  • パラメータの更新と同期のタイミングを計算します。

    • setSependentsDirty() - サーバー側でパラメータ値を設定し、特別な場合(およびDirtyな伝播の場合)は強制的に同期します。

    • setInternalValue() パラメータアトリビュートおよびアセット名/パスは、internalSetです。名前とパスが実際に保存されるのはノード内部で、パラメータはデータをHoudiniに渡すためだけに存在します。setDependents Dirtyと一部重複しています。EM/DGモードの違いにより、片方が呼び出されるのか、または両方が呼び出されるのかは分かりません。場合によっては、追加でパラメータが更新される可能性もありますが、少なくともパラメータが欠落することはありません。

    • preEvaluation() 評価マネージャ(EM)向けのDirty化 - 残念なことに、EMは親コンパウンドのみを見るため、Dirty化できるのはトップレベルのパラメータのみです。それらはすべて、houdiniAssetParmsの下に作成されているからです。

  • パラメータ値とアトリビュート値の間で変換します。

    • setParmValues() - アトリビュートを取得し、パラメータを設定します(Asset.cでのパラメータイテレータ向けラッパー)。

    • getParmValues() - パラメータ値からアトリビュートを設定します(Asset.cでのパラメータイテレータ向けラッパー)。

    • マネージャ関連を評価します。

  • compute() パラメータを更新し、Asset::compute()を実行します - 興味深いさまざまなことが、ここで起こります。

  • shouldSave() 一部の値がデフォルトである、複数の数値を保存するために、Mayaの最適化のバグを回避するために必要です。入力でノードIDが強制保存されます。

  • connectionBroken() 接続解除の挙動が複数コンパウンドの要素に対して機能していないように見える、Mayaのバグを回避するのに必要です。

アセット/Houdiniインターフェース

Asset.Cで最も面白い部分は計算です。実際に、Mayaデータ/Houdiniデータのインターフェースをすべて処理します。

アトリビュート/パラメータインターフェースは、パラメータイテレータUtil::WalkParmOperationに基づいています。 数多くのパラメータイテレータを作成し、データを双方向にコピーします。 アトリビュート作成は、syncAttributesコマンドで処理されます(後で詳しく説明します)。

  • AttrOperation

    • GetMultiparmLengthOperation

    • GetAttrOperation

    • SetMultiparmLengthOperatio

    • SetAttrOperation

    文字列のコピーは、クライアント-サーバーのインターフェースで最も時間がかかる処理のため、アセットへの初回アクセス時にすべてのパラメータ名をキャッシュ化します。

アセットノードは、入力ジオメトリノードとアセット入力サーバー側の接続も処理します。

出力を計算する

Maya出力データを実際に構築するOutputObjectsには、階層があります。Houdini出力オブジェクトノードをウォークし、これらのOutputObjectsを構築してから、OutputObjectsをウォークして、それらに実際の作業を行なわせます:

  • OutputObject.C

    • OutputGeometryObject.C

      • OutputGeometry.C

      • OutputGeometryPart.C

      • FluidGridConvert.C

    • OutputInstancerObject.C

  • OutputMaterial.C

Asset::compute:

  • クックします。

  • 出力/表示ノードとしたいノードで、ノードリストを更新します。

    • SOPアセット - ノードIDのみ

    • オブジェクトアセット - 場合によってはgetComposedChildListが必要

  • ノード向けにOutputObject(s)を作成します(例えば、OutputObjectクラスがその子クラスの1つのオブジェクトをインスタンス化します - OutputGeometryObjectまたはOutputInstancerObject)。

    • これらのOutputObjectsは、実際の出力データを構築するのに使用されます。

  • アセットのトランスフォームを計算します。

    • (関係があるのはサブネット付きのオブジェクトアセットのみ)

  • computeInstancerObjects()

    • すべてのoutputObjectsをウォークし、それぞれのOutputInstancerObjectsについて出力データを計算します。

  • computeGeometryObjects()

    • すべてのoutputObjectsをウォークし、OutputGeometryObjectsを取得して出力データを計算します。

  • computeMaterial()

    • これは一種の逆行です(詳細を思い出すには、コードをもう少し見る必要があります)。

    • 出力ジオメトリに実際に割り当てられているマテリアルについて、出力マテリアルパスが同期入力されていることが前提です(これは確実ではない部分です。後日コードを再度確認します)

    • 既存の出力数分のOutputMaterialオブジェクトを作成し、それらをイテレートします。

      • マテリアルが変更されたり、クックの回数が遅れた場合には…

      • アセットのVOP/SHOPノードで、マテリアルパスと一致するマテリアルを検索します。

      • 一致するマテリアルが見つかったら、すべてのマテリアル情報を抽出し、データを更新して、出力テクスチャをベイクします(非常に時間がかかる可能性があるので、must bakeオプションがオフの場合は、可能な限り既存のテクスチャファイルを再利用します)

出力データが既に出力シェイプに接続されている場合は、次の描画または他の評価で選択されます。どの出力にも接続されていない場合は、次の同期で、出力されたすべてのデータの出力シェイプが作成されます。

コマンド

主に2つのプラグインコマンドがあります。

  • EngineCommand.C: Engineセッションとやり取りするためのコマンド(セッションの照会、hipファイルの保存)

  • AssetCommand.C: 特定のアセットとやり取りするためのコマンド(HDAのロード、アセットからのMayaノードとアトリビュートの更新)

どちらのコマンドにも複数のフラグがあり、対応するサブコマンドオブジェクトを作成し、それを使用してdoIt()undoIt()などを実行することで実装されます。分かりやすくなるよう、メソッドの命名をまたMayaメソッドに合わせています。 すべてのコマンドオプションについては、プラグインのコマンドを参照してください。

サブコマンド

  • SubCommand.C - すべてのサブコマンドオブジェクトの親クラス

Engineサブコマンドはシンプルで、すべてEngineCommand.Cにあります。アセットサブコマンドは複雑で、追加のクラス階層と独自のファイルを持っています。

  • AssetSubCommandLoadAsset.C - アセット定義を削除してリロードします。

  • AssetSubCommandSync.C - パラメータステートに基づいてアトリビュート再構築したり、出力に基づいて出力ジオメトリノードをクックおよび再構築します。

    • SyncOutputInstance.C

    • SyncOutputMaterial.C

    • SyncOutputObject.C

      • SyncOutputGeometryPart.C

    • SyncAttribute.C

同期

同期はまた、別の同期操作を行なうためのヘルパーオブジェクトも作成します。

  • preSyncCallBack(ユーザ定義、パラメータや出力に対するすべてのカスタム変更をキャッシュ化)

  • アトリビュートを同期する場合、syncAttibutesオブジェクトを作成して実行します。

  • 出力の同期

    • アセットノード下のすべてのノードを検出し、削除します。

    • すべての出力マテリアル接続を削除します。

    • すべての自己接続を削除します(例えば、同期によってAssetObjectTransformがオフになった場合など)

    • outputObjectsプラグイン要素をウォークし、SyncOutputObjectを作成して実行します。

      • syncOutputMaterialはマテリアルが割り当てられた最初のオブジェクトのみに使用します。

    • outputInstancersプラグイン要素をウォークし、SyncOutputInstanceを作成して実行します

ユーティリティ

その他のユーティリティメソッドは以下になります:

  • util.C

    • パラメータ名およびノード名を有効なMaya名に変換

    • 進捗バーのハンドリング/ステータスのチェック

    • パラメータイテレータ

    • DG操作向けの便利なメソッド

    • エラー処理

  • AssetNodeOptions.C - ノード固有のオプションにはNodeOptionsクラスが1つありますが、現在これを利用しているのはアセットノードのみです。

MELコマンドとUI

これらについては説明不要でしょうが、注意点をいくつか記しておきます。

  • グローバルプロシージャ名はスクリプトファイル名と一致しないため、大量のソーシングが行なわれています。

  • 新しいバージョンのHoudiniをインストールする際には、シェルフを再構築する必要があります(シェルフコマンドの更新があるのはそのためです)。ツールシェルフはシェルフアイテム内にツールの場所を埋め込んでいるため、ツールの新しい場所を参照するように更新する必要があります。シェルフを削除して置き換えるため、デフォルトのMayaの確認ボックスが表示されます。また、削除したシェルフは明示的に置き換える必要があります。そうしないと、Mayaが以前削除したシェルフを記憶していて、それを更新します。確かに、きれいなコードとは言えません。ご不便についてはお詫びしますが、こうするしかありませんでした。

  • 私たちはMayaの主な新機能を賢く利用しながら、Houdiniのリリースで一新されたHoudiniプラグインの主な機能を利用できるようにしているわけです。

Maya

はじめよう

入力および出力のジオメトリ

Houdini Engine for Mayaを使用する

リファレンス