On this page |
Overview ¶
You can run scripts as part of a recipe. In most scenarios, you only want to apply the captured parameter values in a recipe or generate the captured nodes. However, sometimes you want to vary these generated values and nodes so they match the current state. For example:
-
When you put down a simulated fire recipe and need to turn the volume light sources on or off to match the current viewport.
-
When you create a camera in a recipe and need it to match the current viewport.
You can use pre and postscripts to run Python either before or after a recipe’s application.
The recipe internally stores captured data that’s based on the declarative Data Model stored under the data.recipe.json
section. This section also stores other properties related to the recipe.
Note
If you don’t capture any data with the recipe, you can use the prescript to run tasks or invoke other recipes.
Creating ¶
You can use the following HOM functions to script the creation of recipes from existing nodes:
Applying ¶
You can use the following HOM functions to script applying recipes in the network:
Note
The decoration and tool recipes include the items
key dictionary, where the dictionary keys are the node names as recorded in the data. View this output if you need to find the recipe’s node names. This is useful because recipes try to create nodes with the name they're stored under in the data, but use another name if a node with that name already exists.
Pre and postscripts ¶
If you create a parameter preset recipe or use a Recipe Builder, they have parameters for a prescript that runs before the recipe is applied and a postscript that runs after the recipe is applied.
The recipe internally stores the prescript under the pre-script.recipe.py
section and the postscript under the post-script.recipe.py
section.
The prescript can access a kwargs
dictionary with the following keys
name
: str
The internal name of the recipe, which can help with debugging.
data
: dict
The data stored in the recipe that applies to the Houdini session. Change this data to control which nodes and parameters are set by the recipe.
node
: hou.Node
When running a Parameter preset or Node preset, this stores the node to which the preset applies.
network_editor
When running a Tool from the Tab menu, this stores a hou.NetworkEditor from which the tab was invoked.
parent
When running a Tool, this is the node inside which the tool is created.
central_node
: hou.Node
When running a Decoration, this is the node the recipe applies to and spawns other decorator nodes.
anchor_node
: hou.Node
When running a Tool, this is the node displayed under the cursor in the network editor when the tool is placed.
click_to_place
: bool
When running a Decoration or Tool, this sets when you must click in the network editor to place the tool. During placement selection, the anchor node is displayed under the cursor and all other items are relative to that.
drop_on_wire
: bool
When running a Decoration or Tool, this sets when to rewire any existing wires when the tool is dropped between two nodes connected by a wire.
prompt
: bool
When running a Tool, this sets whenever to invoke any prompt set during the recipe creation.
The postscript can access a kwargs
dictionary with the following keys
name
: str
The internal name of the recipe, which can help with debugging.
node
: hou.Node
When running a Parameter preset or Node preset, this stores the node to which the preset applies.
network_editor
When running a Tool from the Tab menu, this stores a hou.NetworkEditor from which the tab was invoked.
central_node
: hou.Node
When running a Decoration, this is the node the recipe applies to and spawns other decorator nodes.
anchor_node
: hou.Node
When running a Tool, this is the node displayed under the cursor in the network editor when the tool is placed.
items
: dict[str, hou.Node]
When running a Decoration or Tool, this stores all other nodes that the recipe creates or edits.
Prescript example: add mask to Pyro Source ¶
This use case is an example of how to create a recipe that adds a mask
source (if one doesn’t already exist) to a Pyro Source SOP.
-
In a SOP network, create a
Recipe Builder node.
-
Dive into the subnetwork and add a
Pyro Source SOP named
pyrosource1
. -
On the Pyro Source node, set Attributes to
1
and set the Name of the new instance tomask
. -
Go back up to the Recipe Builder and do the following:
-
Set Recipe Category to Parameter Preset.
-
Set Internal Name to
pryosourcemask
. -
Set Label to
Mask
.
-
-
In the Invocation tab, set Multiparm Operation to
Append
. -
In the Scripts tab, turn on Before Data Applied and enter the following code to make the recipe check for an existing
mask
source first.# Make sure that an instance is not added twice node = kwargs['parm'].node() # The multi-parameter parent multiparm_parent = kwargs['parm'] # The name of the parameter to compare existing instances name = 'name' # The name of the same parameter as it's stored in the data data_name = f'{name}#' # Gather all existing source names existing_names = [node.parm(name + str(i)).evalAsString() for i in range(1, multiparm_parent.evalAsInt() + 1)] # Filter the stored data based on the existing source names updated_data = [] for entry_data in kwargs['data']: # The 'data_name' key may not directly hold the value you're looking for # but holds another dictionary where you must look for a 'value' key value = entry_data[data_name]['value'] if isinstance(entry_data[data_name], dict) else entry_data[data_name] # Only keep this multi-parameter instance data if it doesn't exist yet if entry_data[data_name]['value'] not in existing_names: updated_data.append(entry_data) # Pass on the new updated list to ensure an instance is not added twice kwargs['data'] = updated_data
Postscript example: set Start Frame based on the current timeline ¶
This use case is an example of when you have a recipe and, when it’s created, you want the Start Frame parameter on the anchor node in the recipe set to the start of the current timeline’s frame range.
-
Click the Scripts tab in the
Recipe Builder node.
-
Turn on After Data Applied and enter the following code:
anchor_node = kwargs['anchor_node'] anchor_node.parm('startframe').set(hou.playbar.frameRange()[0])
Example: hierarchical recipes ¶
This use case is an example of when you want a tool recipe to create a set of nodes, but want one of those nodes to have a preset recipe applied to it.
Though you can save the tool recipe with the correct values applied to the node, you may want the flexibility of being able to change the preset recipe without having to reset any tool recipes that depend on it. You can do this by making a tool or recipe builder script that applies the tool recipe, then looks up one of the created nodes and applies a preset to it.
hou.data.applyToolRecipe("first_recipe") node = kwargs["items"]["foobar"] hou.data.applyNodePresetRecipe("second_recipe", node)
Example: create preset menu ¶
Tips ¶
-
Use the following script to output the generated recipe data structure in a readable format.
import recipeutils as ru
-
Use the
recipeutils
module to print out recipe information, such as the available node presets. For example:import recipeutils as ru names = ru.recipeNames(ru.RecipeCategory.nodePreset, nodetype_categories=hou.sopNodeTypeCategory(), include_label=True, pad=True) ru.pprint(names)
You can also provide a
name_pattern
option to filter recipes based on their internal names.