Houdini 21.0 Networks and parameters

Scripting recipes

How to use scripts to create, apply, and run in recipes.

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.

  1. In a SOP network, create a Recipe Builder node.

  2. Dive into the subnetwork and add a Pyro Source SOP named pyrosource1.

  3. On the Pyro Source node, set Attributes to 1 and set the Name of the new instance to mask.

  4. 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.

  5. In the Invocation tab, set Multiparm Operation to Append.

  6. 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.

  1. Click the Scripts tab in the Recipe Builder node.

  2. 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

This use case is an example of how to display available recipes for a node in an Ordered Menu (the preset menu), invoking the recipe every time you choose an item from the menu.

  1. Create multiple node presets or parameter presets for a node. If you use a Recipe Builder, you can use the Submenu parameter to categorize the recipes.

  2. Open the Edit Parameter Interface window and click the ordered menu parameter that you want as the preset menu.

  3. In the Menu tab, turn on Use Menu and enter the following code in the Menu Script tab. This code builds the items of the preset menu based on the recipes that're created with their submenu set to Materials. When submenu is an empty string, the menu displays all available presets for the node.

    import recipeutils as ru
    return ru.buildPresetMenu(kwargs,
                                submenu='Materials')
    
  4. In the Parameter tab, set Callback Script to the following code. This invokes the recipe each time you pick an item from this preset menu.

    import recipeutils as ru; ru.setPresetMenu(kwargs)
    

To set up a preset menu that jumps back to the default state when a preset is selected, use the above steps but change the code to the following:

  • Enter the following code as a postscript for each preset recipe, where presetmenu is the name of the preset menu parameter. This makes the preset parameter also change when the preset is invoked from the Recipe menu.

    kwargs['node'].parm('presetmenu').set(0)
    
  • For the preset parameter in the Edit Parameter Interface window, enter the following code in the Menu Script tab:

    import recipeutils as ru
    return ru.buildPresetMenu(kwargs,
                            submenu='Materials',
                            revert=True,
                            revert_token='materials',
                            revert_label='Materials')
    
  • Enter the following code in the Callback Script parameter:

    import recipeutils as ru; ru.setPresetMenu(kwargs, revert=True)
    

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.

Networks and parameters

Networks

  • Network editor

    How to create, move, copy, and edit nodes.

  • Network navigation

    How to move around the networks and move between networks.

  • Connecting (wiring) nodes

    How to connect nodes to each other to make them work together.

  • Network types and node flags

    Flags represent some state information on the node, such as which node represents the output of the network. Different network types have different flags.

  • Badges

    Badges indicate some status information about a node. They usually appear as a row of icons below the name of the node.

  • Node Info

    The node info window shows a quick overview of statistics and information about a particular node.

  • Find nodes in a network

    How to use the Find dialog to find nodes based on various criteria.

Editing parameters

Next steps

Expressions

Recipes

Reference

Guru level