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


# 初めに

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

![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/805f2c34-69f9-46c0-4f9c-c3981a56dd8d.png)

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

![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/6f27cd17-2d6e-4aa0-5f98-722c0f14245a.png)

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


![suzanne.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/d0a9582d-62a5-9297-505c-6961b50c2183.png)


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

![material_sop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/16677de2-7f67-89e1-e6b4-d1124b667141.png)


# HDAの解説


## パラメータ

![parameter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/b68aa792-8cff-73f9-8f9a-871a41451681.png)

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

#### Update Material List(update_material_list)

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

![button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/78d710fd-a56e-a2fc-386d-2643c4e1611b.png)

#### Material Name Attribute(mat_name_attrib)

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

#### Reload Toggle(reload_toggle)

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


## ノード構成 

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

![node_network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/f5cbe02b-b4a1-5eb9-0de7-99ed33e2764b.png)

## 処理の流れ

### detailwrangle

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

```vex: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!!" }`はマテリアルのノードに限定するための記述です。

```python: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223831/066d25d3-764b-61f0-09f6-d3fc84327f67.png)

### primitivewrangleでのshop_materialpathの設定

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

```vex: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の魅力の一つだと思います。自分にとって作業しやすい構成を探ってみるのも良いのではないでしょうか。