今回は簡単なPythonコードを用いて、Houdiniでよくやる作業を自動化する方法についての記事です。
要件としては下記のとおりです。
- シーンにGeometryノードを作成し、名前をWORKにする
- 内部のFileSOPを削除する
- シーンにすでにWORKがある場合は処理を行わず抜ける
- シェルフを作成し、ツールを作成・スクリプトを登録、クリック一発で実行できるようにする
本記事を作成するにあたり、Houdini実践ハンドブックWrangle×Pythonに大きなインスパイアをいただきました。
こちらの書籍については後日レビューを書く予定です。
Pythonを実行する下準備
Pythonの実行はPythonScriptノードやPythonSOPにPythonコードを書くことで実行できますが、今回は最終的にシェルフにツールを登録するので先にシェルフの用意をしておきましょう。
シェルフからツールを実行する際はアイコンをクリックするだけなので、わかりやすく試行錯誤にも向いているかと思います。
シェルフの新規作成
シェルフの+ボタンを押して「New Shelf…」を実行します。
シェルフの設定
Name、Labelをお好みで設定します。ここでは下記のとおりとしました。
- Name: kickbase
- Label: Kickbase
ツールの作成
作成したシェルフ上で右クリックメニューを表示、「New Tool…」を実行します。
ツールの設定
Name、Labelをお好みで設定します。ここでは下記のとおりとしました。
- Name: work
- Label: Work
スクリプトの記述
Scriptタブに移動し、任意のスクリプトを記述していきます。
スクリプトの実行
スクリプトを実行するにはアイコンをクリックするだけです。
コード解説
最終的なコード
たったの6行!普段コードを書かない方でも十分追える分量かと思います。
目標としては、できるだけシンプルで汎用性が高いツールを目指します。今回のツールは新しいシーンを作るとき必ず最初にやる作業なので、最初に作るツールとしてはお手頃で良いんじゃないでしょうか。
ちなみにぼくは素材は主にWORKノード内ですべて作成し、個別に見栄えを調整したいオブジェクトはObjectMergeSOPでシーンに出すというスタイルで作成しています。
以下に実際に書いた順に見ていきましょう。
Geometryノードの作成
geo = hou.node('/obj/').createNode('geo', 'WORK')
最終コードでは2行目に当たりますが、この行から書き始めました。じっくり見ていきます。
まず、Geometryノードをつくるだけならhou.node('/obj/').createNode('geo')
これだけでOKです。これはobj
レベルにGeometryノードを作成します。名前はgeo1
となりました。
ノード生成時に名前をつけたい場合はcreateNodeメソッド
の第二引数に名前を渡します。コードは下記のようになります。
hou.node('/obj/').createNode('geo', 'WORK')
生成したGeometryノードにあとでアクセスするため、戻り値を変数geo
に保持しておきます。これでgeo = hou.node('/obj/').createNode('geo', 'WORK')
となりました。
生成したノードの配置位置を自動調整
geo = hou.node('/obj/').createNode('geo', 'WORK') geo.moveToGoodPosition()
追加したgeo.moveToGoodPosition()
は非常にシンプルです。メソッド名の通り、ネットワークビューでノードをいい感じに自動配置してくれます。
(注)このメソッドを実行しないと遠いところにノードが生成されてしまったり、すでにあるノードに重なってしまったりということが起こります
Geometryノード内のFileSOPを削除
geo = hou.node('/obj/').createNode('geo', 'WORK') geo.moveToGoodPosition() for n in geo.children(): n.destroy()
追加したのは下記部分です。
for n in geo.children(): n.destroy()
これも特に難しくはありません。geo
は生成したGeometryノードなので、geo.children()
で取得できるのはGeometryノード内にあるすべてのノードとなります。これをforループ
で処理し、個々のノードをdestroyメソッド
で削除していきます。
Geometryノードが生成時に持っているのはFileSOPのみですが、子要素をすべて削除することを明示するためにforループ
を用いています。
複数回実行を防ぐ
運用方法としてWORKノードはひとつだけにしたいですが、このままではクリックするたびに実行され、Geometryノードがつど生成されてしまいます。
それを防ぐため「すでにWORKという名前のノードがあったら処理を実行しない」というコードを追加しましょう。*1
if not hou.node('/obj/WORK'): geo = hou.node('/obj/').createNode('geo', 'WORK') geo.moveToGoodPosition() for n in geo.children(): n.destroy()
一行目にif文
を追加しました。元々書いていたコードのインデントをひとつ下げるのをお忘れなく。
これで複数回クリックしても一度だけ実行されるようになりました。
まとめ
今回紹介したコードは6行と短く、機能も非常にシンプルです。しかし、ツールは複雑なコードを書けばいいというものではなく、よく行う作業を効率化できればそれでOKだと思います。
追加したい機能
実は実装できなかった機能として「WORKノードを作成したあと、ネットワークビューでその中に入った状態にする」というのがあります。(つまり/obj/WORK/
にいる状態にしたい)
この方法がわからなかったので、どなたかご存じの方はご教授いただけると幸いです。
*1:コードとしては「WORKというノードがないときのみ実行する」という書き方になります