本記事は、
Houdini Advent Calendar 2018 21日目の記事です。
はじめに
ノード生成時に独自のパラメーターを追加する方法を説明します。
(かれこれ5、6年前、h11とかh12の頃にやってた事なので、
既知の内容ばかりかもですが。。。)
例として、
ropのgeometryノードにパラメーターを追加します。
ここでは、geometry ropが元々持っているパラメーターを、
「Default」と言うタブ(フォルダ)を作ってそちらに全部移動し、
追加で新たに「Backburner」と言う名前のタブを追加します。
(Backburner・・・?死語?と言う名前のDispatcherにSubmitするパラメーターを作ってます)
#どうやるか?
Houdiniには、
ノードが作成された直後、
用意したスクリプト(python or hscript)ファイルを実行してくれる仕組みがあります。
Event Scriptと呼ばれます。
Event Scriptは決まったファイル名にする必要があり、
以下が命名規則となってます。
・OnCreated.py(どんなノード生成時も実行される)
・ノードタイプ名.py
(ノードタイプ名のタイプのノードが作成された時実行される。
これはノード生成時に実行されるもので、
デフォルトで、$HFS/houdini/scripts/カテゴリ/ノードタイプ名.cmd が用意されているノードもあり、
独自にノードタイプ名.pyを用意してパスに先に通すと、上記ノードタイプ名.cmdが実行されなくなるので注意。
また、HDAの場合実行されない)
・ノードタイプ名_oncreated.py
(上記ノードタイプ.py実行後、実行される、こちらがノード生成後に実行されるものと捉えられます。
HDAの場合、この命名規則のファイルを用意しておけば実行してくれます)
OnCreated.py
HOUDINI_PATHに通したパスの中の、/scripts/pythonに
ファイルを置いておけば実行してくれます。
パスの中で最初に見つかったものだけ実行されます。
ノードタイプ名.py
ノードはカテゴリ分けされており、HOUDINI_PATHに通したパスの中の、
/scripts/カテゴリ名フォルダ/ノードタイプ名.py
にファイルを置いておけばノードタイプに一致するノード生成時に実行されます。
パスの中で最初に見つかったものだけ実行されます。
ノードタイプ名_oncreated.py
HOUDINI_PATHに通したパスの中の以下に置いておけば実行されます。
/scripts/カテゴリ名フォルダ/ノードタイプ名_oncreated.py
HDAの場合、
/scripts/pythonに置いておいても実行してくれますが、
上記scripts/カテゴリ名フォルダの両方おくと後者は無視されます。
と言うことで、
上記ファイルにパラメーターを追加するコードを書いておけば、
ノード生成時に独自のパラメーターを追加しておく事が可能です。
が、
パラメーターを追加するコードをすべてpythonで自分で書いて、
とか、めんどくさすぎる!!!
ので、HoudiniのUIでパラメーターを作成し、
それを生成するpythonのコードを取り出せる機能を使って、
ファイルに書き出し、それを使ってパラメーターの追加を行いたいと思います。
パラメーター作成とコード書き出し
まずは、Edit Parameter Interfaceでパラメーターを追加(追加方法は割愛)
次に、作った上記のパラメーターをpythonのコードとして書き出します。
# ノードのオブジェクトを取得
node = hou.node("/out/geometry1")
# Backburnerタブを取得
ptg = node.parmTemplateGroup()
folder = ptg.findFolder("Backburner")
# ファイルに書き出し
with open('f:/bbTab.py','w') as f:
f.write( folder.asCode(function_name='createTab') )
上記の最後、folder.asCode()と言うのが、
Backburner(タブ)とそれに含まれるパラメーターを生成するpythonコードを、
文字列として返してくれる関数で、それをファイルに書き出しています。
function_name='createTab'は、
書き出されるコードを関数として書き出すようにする引数で、
以下書き出されたコード、
createTab()と言う関数が作られています。
function_name=に何も指定しないと、関数が作られず、
パラメーターを作るコードが羅列されたものが書き出されます。
def createTab():
# Code for parameter template
hou_parm_template = hou.FolderParmTemplate("default_1", "Backburner", folder_type=hou.folderType.Tabs, default_value=0, ends_tab_group=False)
# Code for parameter template
hou_parm_template2 = hou.ButtonParmTemplate("submit", "Submit")
・
・
return hou_parm_template
Houdiniのパラメーターの持ち方
実際のパラメーターを追加するコードの説明に行く前に、
Houdiniのパラメーターの持ち方を説明します。
houdiniは、
個々のノードがparmTemplateGroupと言う入れ物を持っており、
この中にパラメーターとなるオブジェクトを持ってます。
各パラメーターは、
parmTemplateと言うクラスから派生したオブジェクトとなっており、
parmTemplateGroupが、それを持っています。
parmTemplate class
parmTemplateGroup class
Pythonでノードにパラメーターを追加する方法
以下でサンプルがありますが、順を追って説明すると、
parmTemplateGroup
# ノードを作成(/obj以下にgeometryノードを作成)
node = hou.node("/obj").createNode("geo")
# ノードが持つparmTemplateGroup()(箱)を取得
group = node.parmTemplateGroup()
# My Parmsと言うラベルの付いたフォルダを作成
#(フォルダはパラメーターのタブに当たります)
folder = hou.FolderParmTemplate("folder", "My Parms")
# フォルダにfloat型の myparm という名前のパラメーターを追加
folder.addParmTemplate(hou.FloatParmTemplate("myparm", "My Parm", 1))
# 最初に取得したparmTemplateGroup(箱)にフォルダごと追加
group.append(folder)
で、最後にポイントなのですが、
上記group.append(folder) でparmTemplateGroup()で取得した箱にフォルダを追加してるのですが、
この時点ではノードにパラメーターは追加されず、
何の変化もありません。
と言うのも、
このparmTemplateGroup()で取得した箱と言うのは、
あくまでコピーを取得しており、もはや実際のノードがもつ箱とは別物で、
これに何を追加してもノードに反映されることはありません。
ではどうするか、
最後に以下を行うことで、
追加したパラメーターを持つ箱、parmTemplateGroupをノードにセットでき、
めでたくパラメーターを追加することが可能になります。
node.setParmTemplateGroup(group)
実際にパラメーターを追加するコード
# 上記で書き出したモジュールをimport
import bbTab
# 作成されたノードのオブジェクトを取得
node = kwargs['node']
# template group取得
ptg = node.parmTemplateGroup()
# Tab(Defaultと言うラベルの)を作りその中に元々存在するパラメーターを全部入れる
folder = hou.FolderParmTemplate('default', 'Default', parm_templates=ptg.entriesWithoutFolders())
for p in ptg.entriesWithoutFolders():
ptg.remove(p)
# template groupに上記Default Tabを追加
ptg.append(folder)
# Backburner Tabを作成してtemplate groupに追加
ht = bbTab.createTab()
ptg.append(ht)
# ノードに反映
node.setParmTemplateGroup(ptg)
最後に
上記で「Backburner」と言う名前のTabを追加できるわけですが、
この方法ですと、
geometryノードだけではなく、様々なノードに同じようなコードで、
同じパラメーターの追加が可能になります。
この方法を使った事例としては、
BackburnerのようなDispatcherに対し、
ropのgeometryやその他キャッシュをとったり、publishと言った処理を投げる用に、
同じパラメーターを追加して投げるようにしてました。
メニューやシェルフにSubmitボタンを登録するという方法も取れますが、
ノードにパラメーターがついていることで、
投げた時の設定も保存されるので、再現性も確保できる利点があるかなと。