メインコンテンツまでスキップ

PDGでカスタムプロセッサを作る(2) - プロパティ追加

前回、 では、PythonProcessor で基本的な Generate と Cook を実装したので
今回はプロパティと WorkItem のアトリビュートを追加して、Cook 側でもう少し具体的な処理を書いていこうと思います。

Processor のプロパティを追加する

まず、PDG のノード自体の処理 正確に言うと WorkItem を Generate する時に使いたいパラメーターは
通常の Houdini と同じく

EditParameterInterface から追加します。

例として Processor でテキストファイルに書かれている数だけ WorkItem を作る...というのをやりたい場合。
パラメーターとして FilePath を追加します。

A B C

そして、中身が ↑ のようなテキストファイルを作り、 file_path にパスを指定します。

path = self["file_path"].evaluateString()

with open(path,'r') as f:
data = f.readlines()

for i in data:
name = i.strip()
options = pdg.WorkItemOptions()
options.inProcess = True
new_item = item_holder.addWorkItem(options)

new_item.addAttrib("name",pdg.attribType.String).setValue(name)

テキスト 1 行ごとに WorkItem を生成する場合がこのようになります。
Int などの数値であっても、JSON やほかのフォーマットになった場合でも基本は同様です。

PythonScript の場合

Houdini の PythonProcessor ノードに対して追加する場合は、上記の手順でしたが
Python スクリプトに保存した場合は以下のようになります。

    @classmethod
def templateBody(cls):
return """{
"name": "pythonprocessor1_template",
"dataType": "genericdata",
"parameters": [
{
"name": "file_path",
"label": "File Path",
"type": "String",
"value": "D:/sample.txt",
"tags": "['script_callback_language']"
}
]
}"""

templateBody の parameters が、プロパティの設定になるので、
parameters 内に name label type value tags の辞書型を追加します。

プロパティと Generate と WorkItem

PythonProcessor ノードを使用して Cook を書いた場合、
プロパティを Cook 側でも参照できます。

例として

print(self["file_path"])

これを Cook に書いたとしても読むことが可能ですが、個人的には Cook 側で使用する値は
Generate 側で WorkIem のアトリビュートとしてセットするほうが良いと思っています。

というのも、LocalProcessor で実行している分にはあまり問題にはならないかもですが
WorkItem を Out-Of-Process で実行したりする場合、外部プロセスとの値のやり取りは JSON 化した WorkItem
の情報を経由して、各実行プロセスに値が渡されます。

TaskGraphTable にも情報が残らないので、極力タスクを実行するのに必要なものは Generate した段階で
完結するほうが、個人的に以降の処理がわかりやすくなると思っています。

もし、Cook で扱いたい値をプロパティとして追加したい場合は
Generate 時に WorkItem に対して値をセットするようにします。

WorkItem アトリビュート追加

というわけで、Cook 側で必要とする情報は Generate 側で実装していきます。
WorkItem には、Int や String といったプログラミングの一般的に使われる「型」以外にも
PyObject という型が用意されています。

new_item.addAttrib("sample",pdg.attribType.PyObject).setValue({"HOGE":"FUGA"})

この PyObject は、辞書型やリスト型といった構造も持つことができて、

value = work_item.attrib("sample").values
print(value["HOGE"])

このように、Cook 側でも辞書型で扱うことができます。

辞書型以外にも、(すごく事故りそうでならないですが)

path = self["file_path"].evaluateString()

from pxr import Usd

stage = Usd.Stage.Open(path)

for prim in stage.Traverse():

options = pdg.WorkItemOptions()
options.inProcess = True
new_item = item_holder.addWorkItem(options)

new_item.addAttrib("sample",pdg.attribType.PyObject).setValue(stage)
new_item.addAttrib("sdf_path",pdg.attribType.PyObject).setValue(prim)

USD の Stage や Prim のオブジェクトといったものも、WorkItem のアトリビュートとして扱えて、

Cook 側でも扱うことができました。
(ただし、Prim だけではエラーになり、Stage もアトリビュートとして持たないとエラーになります)

個人的には、辞書やリストにとどめておくほうがよさそうだなとは思いつつも
指定のファイルの Prim だけ PDG の処理をする...とか、あるファイルを参照して処理を実行する
みたいなことはかなり自由に書けると思うので
押さえておきたいポイントかなとおもいます。

次回、Cook と InternalDependencies などをもう少し詳しく見ていこうと思います。