Help us understand the problem. What is going on with this article?

ノード作成時に独自パラメーターを追加する方法

More than 1 year has passed since last update.

本記事は、
Houdini Advent Calendar 2018 21日目の記事です。

はじめに

ノード生成時に独自のパラメーターを追加する方法を説明します。
(かれこれ5、6年前、h11とかh12の頃にやってた事なので、
 既知の内容ばかりかもですが。。。)

例として、
ropのgeometryノードにパラメーターを追加します。

ここでは、geometry ropが元々持っているパラメーターを、
「Default」と言うタブ(フォルダ)を作ってそちらに全部移動し、
追加で新たに「Backburner」と言う名前のタブを追加します。
(Backburner・・・?死語?と言う名前のDispatcherにSubmitするパラメーターを作ってます)

geometryノードのデフォルトパラメーター 
addParm0.jpg

こちらが変更、新たに追加したタブとパラメーター
addParm.jpg

どうやるか?

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でパラメーターを追加(追加方法は割愛)
editParm.jpg
editParm2.jpg

次に、作った上記のパラメーターをpythonのコードとして書き出します。

createTab.py
# ノードのオブジェクトを取得
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

add_param.py
# ノードを作成(/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)

実際にパラメーターを追加するコード

/scripts/out/geometry_oncreated.py
# 上記で書き出したモジュールを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ボタンを登録するという方法も取れますが、
ノードにパラメーターがついていることで、
投げた時の設定も保存されるので、再現性も確保できる利点があるかなと。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした