Houdini PythonでSubnetの出力コネクタ数を増やす(備忘録4)
Subnetに出力コネクタを追加したい
今回のスクリプトは、Subnetを利用してノードを整理する際に、繰り返し使うノードの組み合わせを自動的にSubnet内に作成することを目的としています。ここではOutputノード追加して、Subnetの出力コネクタを増やしたいと思います。
出力コネクタを増やしたい
Subnetを作成すると、デフォルトではOutputノードが1つですが、私の作業ではOutputを3つにする必要がありました。RBDの仕込みにおいて、パーツによってVDB to Spheresを使用したり、軸を拘束したり、元の形状をコリジョンで使用したりと、異なる仕込みが必要になるため、Output先を複数用意することにしました。ここでは、"Geo"、"Spheres"、"Constraint"という3つのOutputを作成します。Subnet内でOutputノードを増やすと、subnetの出力コネクタも増えます。
既存のsubnet内でOutputノードを追加して、Output Indexを切り替える作業は手間がかかるため、ワンボタンで自動化したいと考えました。
そこで、以下の機能を持つスクリプトを作成しました。
- Subnet内にOutputノードを追加(出力コネクタを増やす)
この機能を実装するにあたり、事前に以下のスクリプトを作成し、上記スクリプトに組み込みました。
- 選択されたノードがSubnetであるかどうか確認する
- Subnet内の既存のOutputノードを削除する
環境
Windows10 Pro
Houdini Indie 20.5.332 py3.11
選択したノードがSubnetであるかどうか確認
import hou
def is_subnet(node):
return node.type().name() == "subnet"
selected_nodes = hou.selectedNodes()
if selected_nodes:
for node in selected_nodes:
if is_subnet(node):
print ("Selected node is a subnet.")
else:
print ("Selected node is not a subnet.")
else:
print ("Please select a subnetwork!")
選択したノードが"subnet"かどうかを確認するスクリプトです。流用しやすいようにチェックする部分を関数にしました。
スクリプトを実行するとメッセージが表示されます
上記4行目は、次のように書き換えることもできます。
return node.isSubNetwork():
他の種類のノードでも流用することを考慮すると、type().name()で確認する方が使いやすいかもしれません。
選択したSubnet内で、既存のOutputノードを削除
import hou
def delete_child_nodes_by_type(node, type_name = "output"):
for child in node.children():
if child.type().name() == type_name:
child_name = child.name()
child.destroy()
print (f"Successfully deleted output node: {child_name}")
selected_nodes = hou.selectedNodes()
if selected_nodes:
node = selected_nodes[0]
delete_child_nodes_by_type(node)
pane = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor)
pane.setPwd(node.parent())
else:
print ("Please select a subnetwork!")
このスクリプトは、選択したSubnetノード内のOutputノードを削除します。
既存のOutputノード
スクリプトを実行するとOutputノードが削除されます
または、関数を呼び出す際に、
delete_child_nodes_by_type(node, "merge")
上記のようにノードに続いて削除したいノードのタイプ名を指定することで、Outputノード以外のノードも削除できます。
選択したSubnet内にOutputノードを追加(出力コネクタを増やす)
import hou
def is_subnet(node):
return node.type().name() == "subnet"
def add_output_in_subnet(node, list):
count = len(list)
for i in range(count):
new_name = "OUT_" + list[i]
output = node.createNode("output", new_name)
output.parm("outputidx").set(i)
output.moveToGoodPosition()
return print(f"Successfully added output nodes: {', '.join(['OUT_' + name for name in list])}")
def delete_child_nodes_by_type(node, type_name = "output"):
for child in node.children():
if child.type().name() == type_name:
child_name = child.name()
child.destroy()
print (f"Successfully deleted output node: {child_name}")
def show_selection_error():
print ("Please select a subnetwork!")
selected_nodes = hou.selectedNodes()
name_list = ["geo", "spheres", "cons"]
if selected_nodes:
for node in selected_nodes:
if is_subnet(node):
delete_child_nodes_by_type(node)
add_output_in_subnet(node, name_list)
else:
show_selection_error()
else:
show_selection_error()
このスクリプトは、選択したSubnetノードから既存のOutputを削除し、指定された名前のOutputノードを追加します。記事上段で作成したis_subnet()とdelete_child_nodes_by_type()を流用しています。
出力コネクタが増えました
name_list = ["geo", "spheres", "cons"]
name_listで追加する名前のリストを指定しています。ここではgeo、 spheres、consの3つ記載していて、その数だけノードが追加されます。9行目でPrefixとして ”OUT_” を名前に加えています。
Subnet内でOutputノードが追加された
まとめ
お読みいただきありがとうございました。今回は関数にまとめるのを意識してスクリプトを作成しました。シンプルなスクリプトでも関数の形にしておくと、コードを流用しやすいというのを実感できました。また、「フォーマット済み文字列リテラル」というものも少し理解ができました。コードが読みやすくなって良いですね。
この記事が少しでもお役に立てれば幸いです。
参考
Discussion