| On this page |
概要 ¶
レシピの一部としてスクリプトを実行することができます。 たいていの場合、レシピでキャプチャされたパラメータ値を適用したり、キャプチャされたノードを生成したりするだけで十分です。 しかし、その生成された値やノードを現在の状態に合うように変更したい場合もあります。例えば:
-
シミュレーションされる炎のレシピを配置する時に、現在のビューポートに合わせてボリューム光源をオン/オフする必要がある場合。
-
レシピでカメラを作成する時、現行ビューポートに合わせる必要がある場合
プリスクリプトとポストスクリプトを使用することで、レシピの適用前または適用後にPythonを実行することができます。
レシピは、内部ではdata.recipe.jsonに格納されている宣言的なデータモデルに基づいてキャプチャデータを格納します。
このセクションには、そのレシピに関連する他のプロパティも格納されます。
Note
レシピを使用して何もデータをキャプチャしないのであれば、プリスクリプトを使用することで、タスクを実行したり、他のレシピを呼び出すことができます。
作成 ¶
既存のノードからレシピを作成するスクリプトを書くには、以下のHOM関数を使用します:
適用 ¶
ネットワーク内にレシピを適用するスクリプトを書くには、以下のHOM関数を使用します:
Note
DecorationレシピおよびToolレシピには、itemsキー辞書が含まれています。
この辞書のキーは、データに記録されているノード名です。
レシピのノード名を知る必要がある場合は、この出力を確認してください。
レシピはデータ内に格納されている名前でノードの作成を試みますが、その名前のノードが既に存在する場合は別の名前を使用するので、この情報が役に立ちます。
プリスクリプトとポストスクリプト ¶
Parameter Presetレシピを作成する場合、または、Recipe Builderを使用する場合、レシピ適用前に実行されるプリスクリプト用パラメータとレシピ適用後に実行されるポストスクリプト用パラメータを使用することができます。
レシピは、内部では、プリスクリプトをpre-script.recipe.pyセクションに、ポストスクリプトをpost-script.recipe.pyセクションに格納します。
プリスクリプトでは、以下のキーを持つkwargs辞書にアクセスすることができます
name: str
レシピの内部名。これはデバッグで役に立ちます。
data: dict
Houdiniセッションに適用されるレシピに格納されているデータ。 このデータを変更することで、そのレシピによって設定されるノードやパラメータを制御することができます。
node: hou.Node
Parameter PresetまたはNode Presetを実行した時に、ここには、そのプリセットが適用されるノードが格納されます。
network_editor
TabメニューからToolを実行した時に、ここには、そのタブの呼び出し元のhou.NetworkEditorが格納されます。
parent
Toolを実行した時に、ここには、そのツールが中で作成されるノードが格納されます。
central_node: hou.Node
Decorationを実行した時に、ここには、レシピが適用されて他のデコレータノードを生成するノードが格納されます。
anchor_node: hou.Node
Toolを実行した時に、ここには、そのツールが配置されるネットワークエディタ内のカーソル下に表示されるノードが格納されます。
click_to_place: bool
DecorationまたはToolを実行した時に、これは、ツールを配置するのにネットワークエディタ内をクリックする必要があるのかどうかを設定します。 配置選択中は、カーソルの下にアンカーノードが表示され、他のすべてのアイテムはそのアンカーノードを基準に配置されます。
drop_on_wire: bool
DecorationまたはToolを実行した時に、これは、ワイヤで接続された2つのノード間にツールをドロップすると既存のワイヤを再接続するかどうかを設定します。
avoid_overlap: bool
DecorationまたはToolを実行した時に、これは、作成されるノードが他のノードと重ならないように再配置するかどうかを設定します。
prompt: bool
Toolを実行した時に、これは、レシピ作成時に設定されたプロンプトを呼び出すかどうかを設定します。
ポストスクリプトでは、以下のキーを持つkwargs辞書にアクセスすることができます
name: str
レシピの内部名。これはデバッグで役に立ちます。
node: hou.Node
Parameter PresetまたはNode Presetを実行した時に、ここには、そのプリセットが適用されたノードが格納されます。
network_editor
TabメニューからToolを実行した時に、ここには、そのタブを呼び出したhou.NetworkEditorが格納されます。
central_node: hou.Node
Decorationを実行した時に、ここには、レシピが適用されて他のデコレータノードを生成したノードが格納されます。
anchor_node: hou.Node
Toolを実行した時に、ここには、そのツールが配置されたネットワークエディタ内のカーソル下に表示されたノードが格納されます。
items: dict[str, hou.Node]
DecorationまたはToolを実行した時に、ここには、そのレシピが生成または編集した他のすべてのノードが格納されます。
プリスクリプトの例: Pyro Sourceにマスクを追加 ¶
この使用例は、Pyro Source SOPにmaskソース(まだ存在しない場合)を追加するレシピの作成例です。
-
SOPネットワーク内に
Recipe Builderノードを作成します。
-
そのサブネットワークの中に入って、
Pyro Source SOPを追加して、その名前を
pyrosource1にします。 -
そのPyro Source SOP上の Attributes を
1に設定して、その新しいインスタンスの Name をmaskに設定します。 -
Recipe Builderに戻って、以下の操作を行ないます:
-
Recipe Category を Parameter Preset に設定します。
-
Internal Name を
pryosourcemaskに設定します。 -
Label を
Maskに設定します。
-
-
Data タブで、 Preset Node を
pyrosource1に、 Preset Parameter をattributesに設定します。 -
Invocation タブで、 Multiparm Operation を
Appendに設定します。 -
Scripts タブで、 Before Data Applied トグルをオンにして、以下のコードを入力して、レシピがまず最初に既存の
maskソースをチェックするようにします。# インスタンスが2回追加されないようにします。 node = kwargs['parm'].node() # マルチパラメータの親。 multiparm_parent = kwargs['parm'] # 既存のインスタンスと比較するパラメータの名前。 name = 'name' # データに格納されているのと同じパラメータの名前。 data_name = f'{name}#' # 既存のソース名すべてを収集。 existing_names = [node.parm(name + str(i)).evalAsString() for i in range(1, multiparm_parent.evalAsInt() + 1)] # 既存のソース名に基づいて、格納されているデータをフィルタリング。 updated_data = [] for entry_data in kwargs['data']: # 'data_name'キーには、あなたが探している値が直接保持されていない場合がありますが、 # 代わりに、'value'キーが見つかる他の辞書を保持しています。 value = entry_data[data_name]['value'] if isinstance(entry_data[data_name], dict) else entry_data[data_name] # このマルチパラメータインスタンスデータがまだ存在しない場合にのみこのマルチパラメータインスタンスデータを保持します。 if entry_data[data_name]['value'] not in existing_names: updated_data.append(entry_data) # インスタンスが2回追加されないように、新しい更新リストを渡します。 kwargs['data'] = updated_data
ポストスクリプトの例: 現在のタイムラインに基づいて開始フレームを設定 ¶
この使用例は、レシピが作成された時に、そのレシピ内のアンカーノードの Start Frame パラメータを現在のタイムラインのフレーム範囲の開始フレームに設定したい場合の例です。
-
Recipe Builderノードの Scripts タブをクリックします。
-
After Data Applied トグルをオンにして、以下のコードを入力します:
anchor_node = kwargs['anchor_node'] anchor_node.parm('startframe').set(hou.playbar.frameRange()[0])
サンプル: 階層的なレシピ ¶
この使用例は、ツールレシピでノードセットを作成したいものの、それらのノードのうち1つのノードにプリセットレシピを適用したい場合の例です。
ノードに正しい値を適用した状態でツールレシピを保存することもできますが、プリセットレシピに依存するツールレシピをリセットすることなくそのプリセットレシピを変更できる柔軟性が欲しい場合があります。 これを行なうには、ツールレシピを適用してから、作成されたノードの1つを検索して、そのノードにプリセットを適用するようなツールまたはRecipe Builderのスクリプトを作成することで可能です。
hou.data.applyToolRecipe("first_recipe") node = kwargs["items"]["foobar"] hou.data.applyNodePresetRecipe("second_recipe", node)
サンプル: プリセットメニューの作成 ¶
サンプル: デコレータのマージ ¶
この使用例は、作成されたデコレータノードを特定の方法で接続する複雑な挙動の例です。 このレシピは、アンカーノードの入力にマージノードが接続されるようにして、新しく作成されるすべてのデコレーションがそのマージノードに接続されるようにします。
-
LOPネットワーク内に
Recipe Builderノードを作成します。
-
そのサブネットワークの中に入って、2個のNullノードを追加します。
-
それらの新しいNullノードを接続して、それぞれ名前を
start1、end1に変更します。Note
end1を既存のnull1ノードに接続しないでください。 -
Recipe Builderノードに戻って、以下の設定を行ないます:
-
Recipe Category を Decoration に設定します。
-
Internal Name を
decoration_mergerに設定します。 -
Label を
Decoration Mergerに設定します。
-
-
Scripts タブで、 Before Data Applied を有効にして、以下のコードを入力します:
# 作成後のノードの再配置を強制的に無効にします。 kwargs['avoid_overlap'] = False)
-
Scripts タブで、 After Data Applied を有効にして、以下のコードを入力します:
from recipeutils import pprint # まず最初にターゲットノードを取得します。 target_node = kwargs['central_node'] merge_node = None # ターゲットノードに入力がなかった場合、マージノードを作成します。 if len(target_node.inputs()) == 0: # 命令的なPython関数ではなく、データを使用してマージノードを作成します。 merge_node_name = 'wire_nodes_into_here' result = hou.data.createItemsFromData(target_node.parent(), { merge_node_name : { "type": "merge", "position": [target_node.position().x(), target_node.position().y() + 1.0], # offset merge node upwards "outputs": [ { "to": target_node.name(), "to_index": 0, "from_index": 0, } ] } }) # 作成されたノードから実際のhou.Nodeオブジェクトを取得します。 # このキーは、データ内のノード名です。 merge_node = result[merge_node_name] else: # ターゲットノードに入力があった場合、1番目の入力からノードを取得します。 # 場合によっては、ここでそのノードがマージノードかどうかをチェックしたいかもしれませんが、この例ではその手順をスキップします。 merge_node = target_node.inputs()[0] # pprint(kwargs['items']) # 同様に、チェーン内の末端ノードを取得します。その末端ノードはデータ内では'end1'として記録されているので、それをキーとして使用します。 end_node = kwargs['items']['end1'] if merge_node: # この時点で、有効なマージノードが取得できているはずです。 # データ関数を使用して入力コネクションを作成します。 # 既存のコネクションを取得して、それをデータに追加します。 input_data = merge_node.inputsAsData() input_data.append({ "from": end_node.name(), # これによって、確実に正しい名前が取得されます。 "from_index": 0, "to_index": len(input_data), }) # コネクションを作成します。 merge_node.setInputsFromData(input_data)
-
Recipe タブで、 Save Recipe をクリックします。
-
LOPネットワーク内にNullノードを追加して、 Decoration Merger レシピを複数回呼び出します。すると、以下の結果が得られます:
Tips ¶
-
生成されたレシピデータ構造を読みやすい形式で出力するには、以下のスクリプトを使用します。
import recipeutils as ru
-
recipeutilsモジュールを使用すると、利用可能なNode Presetなどのレシピ情報をプリントすることができます。例:import recipeutils as ru names = ru.recipeNames(ru.RecipeCategory.nodePreset, nodetype_categories=hou.sopNodeTypeCategory(), include_label=True, pad=True) ru.pprint(names)
また、
name_patternオプションを指定することで、レシピの内部名に基づいてレシピをフィルタリングすることができます。