4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Houdini ApprenticeAdvent Calendar 2024

Day 21

アトリビュートに合わせてパラメータを用意してくれるHDA

Last updated at Posted at 2024-12-20

初めに

タイトルからどんな内容か分かりにくいと思いますがどういうことかというと、初期状態が以下のようなパラメータしかない自作のHDA(Houdini Digital Asset)ですが

before.png

Update Material Listのボタンを押すと入力に接続されたジオメトリのmaterial_nameに合わせて以下のようにパラメータを生成してくれます。

after.png

この項目を埋めることでマテリアル(shop_materialpath)の設定を行うことが出来ます。

suzanne.png

これは通常のMaterial SOPでも同じように設定できますが機能を限定して(パラメータを少なくして)一覧性を高めたものです。
Material SOPだとグループ指定なのでmaterial_name以外の設定が出来たり複数設定で別タブになったりで正しく意図通りに設定したかを見直すのにちょっと苦労したりします。

material_sop.png

HDAの解説

パラメータ

parameter.png

Separatorは見た目調整のためだけなので実質3つです。

Update Material List(update_material_list)

更新ボタンです。Callback ScriptでPythonModuleのスクリプトを呼び出すだけの簡単なものです。

button.png

Material Name Attribute(mat_name_attrib)

どのPrimitiveアトリビュートを元に設定するかを指定するものです。String型を想定しています。

Reload Toggle(reload_toggle)

パラメータを追加した後にノードを繋ぎなおさないとパラメータが反映されないのでSwitchノードを切り替えて正しく反映されるようにしています。内部処理だけに使われるのでInvisibleにチェックを入れて非表示にしています。

ノード構成

やっていること自体はshop_mateialpathを設定しているだけなのでシンプルです。

node_network.png

処理の流れ

detailwrangle

まずdetailwrangleで名前のリストを取得しています。
uniquevalsで取得できるリストをそのままmaterial_namesとしています。

detailwrangle
string mat_name_attrib = ch("../mat_name_attrib");
s[]@material_names = uniquevals(1, "primitive", mat_name_attrib);

Update Material Listが押された時の処理

そんなに長くはないのでコメントの部分を見てもらえれば処理の流れは分かるかと思います。
パラメータ名は'material_' + material_name.replace('/', '__')として/が入るのを避けています。
tags={ "opfilter" : "!!CUSTOM/MATERIAL!!" }はマテリアルのノードに限定するための記述です。

PythonModule
def update_material_list(node):

    # detailwrangleのノードから名前のリストを取得 
    list_node = node.node('detailwrangle')
    list_node.cook(force=True)
    geo = list_node.geometry()
    material_list = geo.stringListAttribValue('material_names')
    
    # 現在のパラメータを保存 
    value_dict = dict()    
    for parm in node.spareParms():
        value_dict[parm.name()] = parm.evalAsString()
        
    # パラメータを一旦全削除
    node.removeSpareParms()
    
    # パラメータを追加
    for material_name in material_list:
        if material_name is None:
            continue
        name = 'material_' + material_name.replace('/', '__')
        label = material_name if len(material_name)>0 else '(empty)'
    
        template = hou.StringParmTemplate(
            name, label, 1, 
            string_type=hou.stringParmType.NodeReference,
            tags={ "opfilter" : "!!CUSTOM/MATERIAL!!" }
            )
        node.addSpareParmTuple(template)
        
    # 保存したパラメータを復元 
    for key, value in value_dict.items():
        p = node.parm(key)
        if p is not None:
            p.set(value)
            
    # switchを切り替えて更新処理が走るように
    toggle_value = node.parm("reload_toggle").evalAsInt()
    node.parm("reload_toggle").set(1-toggle_value)

Switchの切り替え

reload_toggleのパラメータを参照して切り替えています。上記のPythonModuleを実行するたびに0,1,0,1...と値が切り替わり、ノードを繋ぎなおすのと同じような効果になります。

switch.png

primitivewrangleでのshop_materialpathの設定

mateiral_nameのアトリビュートを見て自身が参照すべきパラメータ名を判断、参照してshop_materialpathに設定しています。
PythonModuleで設定するパラメータ名の決定ルールとずれないように注意が必要です。

primitivewrangle
string mat_name_attrib = ch("../mat_name_attrib");
string material_name = prim(0, mat_name_attrib, @primnum);
string path = ch("../material_" + replace(material_name, "/", "__"));
s@shop_materialpath = path;

まとめ

標準で用意されているノードは色々な需要に合わせて多くのパラメータと機能を持っています。それとは逆に機能や用途を絞って迷わない・ミスをしにくいノードもまた良いものです。

ノードネットワーク構築の自由度の高さはHoudiniの魅力の一つだと思います。自分にとって作業しやすい構成を探ってみるのも良いのではないでしょうか。

4
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?