Creating and editing shelf items
See customizing the shelf for information on rearranging the shelf.
Tip
To make a shelf item that creates a node or group of nodes, you don’t need to script the item yourself. Just drag the node or nodes from the network editor onto the shelf.
In the shelf, right click the tab background and choose New tool, or right-click an existing icon and choose Edit tool.
Set the item’s Name (an identifier that must be unique across all tabs), and Label (the human-readable label that will appear in the tooltip and when the shelf is set to display text).
See the documentation on the Edit tool window for information on editing the tool and its script.
Embedding tools in digital assets
The Tools tab of the type properties window lets you specify the options for item(s) that added to the tab menu for a digital asset. This lets you, for example, write a script, and specify a different submenu name (by default all digital assets show up in a submenu named “Digital Assets”).
Window controls
| Save to | The Any shelf files you save should be in $HOUDINI_PATH in a You can load a |
Options tab
| Name | Internal name of the shelf item. This must be unique across all loaded
shelf tools. Must start with a letter, can contain letters, numbers,
and/or underscores ().
[Id:label] Label:
The human-readable name of the shelf item, appears in the
[tab menu|/basics/tabmenu]. The label should be
relatively short (two to four words) but as descriptive as possible.
[Include:optype#icon]
== Script tab ==
Script language:
The language of the script. This lets you write this script in HScript, but doing so does not offer any of the advantages of Python, and the script cannot be selection/context aware. We strongly encourage you to use Python instead.
External editor:
Click __Launch_ to edit the script in an external editing program (defined by the |
| Script | Enter the script to run when the user clicks the shelf item. See writing the script below. |
Help tab
You can write or paste wiki-formatted help for the the item here, or specify a URL the help should be loaded from.
This help is displayed when the user hovers over the item and presses F1. When you write the help in wiki format, Houdini uses its “summary” text as the item’s tooltip (see the wiki format documentation for information on summaries).
Context tab
The options on this tab control on which tab menus (in which network contexts) the item appears, when the user opens the tab menu in the viewer or network editor.
The Tab submenu path controls which sub-menu of the tab menu the item appears in. You aren’t restricted to the submenus containing the original Houdini tools – you can type a new name here and Houdini will create the corresponding submenu on the tab menu.
Hotkeys tab
This tab lets you specify hotkeys for the item. You can give the item a Global hotkey that works everywhere, and/or a hotkey that only works when the mouse is in the network editor pane, scene view pane, or compositing view pane.
Refer to the Hotkey editor to avoid possible conflicts with existing hotkeys.
Writing the script
You can write a script that acts like a tool (that is, uses the current selection or asks the user for a selection, or lets the user place something in the viewer), or a simple action that’s performed immediately when the user clicks the item and doesn’t require any interaction.
You may not need to write a script at all, if all you want is a shelf item that creates a certain node/asset. When you drag a node onto the shelf, Houdini automatically creates a shelf item with a generic script to create that type of node. See how to customize the shelf for more information.
While running shelf scripts Houdini is still “Live”. This is most noticeable if you acquire DOP Objects and then change the DOP Network. After changing the DOP Network, the current frame will recook and invalidate your DOP Objects.
To avoid recooking the current frame, you can call hou.setSimulationEnabled() to disable the simulation for the duration of your operation. Make sure you record the initial simulation state (hou.simulationEnabled()) and restore it, however.
General tips
See the Python scripting section for general information about scripting Houdini with Python.
While you're debugging a script, you can display alert windows using...
hou.ui.displayMessage("Hello World")
The default shelf items created when you drag nodes onto the shelf are generated by the code in
$HFS/houdini/python2.5libs/defaulttools.pyand generally just callxxxtoolutils.genericTool(). You may want to look at these scripts to learn how to write a simple tool script.The
xxxtoolutilsmodules in$HFS/houdini/python2.5libs/defaulttools.pycontain some useful high-level functions that might make writing tool scripts easier.View the scripts of stock items on the shelf, such as the
Delete action on the Modify shelf tab, for useful techniques and bits of code.
To get the scene viewer pane object...
import toolutils scene_view = toolutils.sceneViewer()
To get the current viewport in the active viewer
active_pane.curViewport()
To get the network location of the scene viewer
import toolutils scene_viewer = toolutils.sceneViewer() path = scene_viewer.pwd()
Detecting what network context the tool is called in
You might want to make a tool that works inside two or more different network types. For example, the
Delete action on the Modify shelf tab works at both the object level, where it deletes the selected object, and at the geometry level, where it creates a Blast surface node.
There are a few ways you could write this part of your script. One is to follow the code used by the Delete action’s script:
import toolutils # Find out current context. # Returns the active pane when the tool/action was called. # If there is not an active pane when the tool/action is called, # this returns None. active_pane = toolutils.activePane(kwargs) # If the pane is a context viewer, treat it like a scene viewer. if active_pane is not None and active_pane.type() == hou.paneTabType.ContextViewer: active_pane = active_pane.sceneViewer() # If there is no active pane, or the active pane is not a # scene viewer, raise an error. if active_pane is None or active_pane.type() != hou.paneTabType.SceneViewer: raise hou.Error("The tool was not invoked in the scene viewer.") # Get the network context of the viewer. child_type = active_pane.pwd().childTypeCategory() if child_type == hou.objNodeTypeCategory(): ... elif child_type == hou.sopNodeTypeCategory(): ... elif child_type == hou.dopNodeTypeCategory(): ... elif child_type == hou.popNodeTypeCategory(): ...
Getting a selection
You can use methods on the scene viewer pane object to get a selection. If the current selection matches the selection type you're asking for, the method will return immediately. Otherwise, it will prompt the user for a new selection.
import toolutils # The toolutils.selectionPrompt() utility function # gets the standard prompt string for a given node type. # For example, this... prompt = toolutils.selectionPrompt(hou.dopNodeTypeCategory()) # will return something like # "Select dynamic objects. Press Enter to accept selection." # The selectXXX methods of the hou.SceneViewer class # prompt the user for a selection in the viewer. # The argument is the text of the prompt that appears in # the status line. # The result is usually a tuple of nodes, but the # selectGeometry() method returns a GeometrySelection object. scene_viewer = toolutils.sceneViewer() selected_objects = scene_viewer.selectObjects(prompt)
Tip
If you try to test the scene_viewer.selectXXX methods in the Python Shell window, it may seem to freeze or not do anything. This is because the prompt only appears when the mouse is over the viewer.
Note
If you're writing your own custom prompt text, remember to tell the user to press Enter to finish the selection.
Limiting which objects the user can select
The hou.SceneViewer.selectObjects method has an optional allowed_types keyword argument that lets you supply a list of object type names. If you supply this argument, the method will only accept selections of these types, and during interactive selection the user won’t be able to select objects that aren’t of the allowed type(s).
The list of allowed types uses the internal names of nodes. To see a node type’s internal name, right-click an instance of the node type in the network editor and choose Type properties. At the top of the window the internal name is listed after Operator type:.
For example, to ask for a camera selection...
# Note: internal name of the Camera object is "cam" selected_objects = scene_viewer.selectObjects("Select a camera and press Enter", allowed_types = ["cam"])
Prompting the user for a position, multiple positions, or a path
To ask the user for a location, as when you place new geometry using the tools on the Create shelf tab:
import toolutils # The selectPositions() method of the hou.SceneViewer object lets # you prompt the user for one or more positions (using the # number_of_positions keyword), optionally connecting multiple # positions (for example when prompting for a path), displaying # a bounding box (when prompting to place geometry), etc. # The result is a tuple of Vector3 objects. scene_viewer = toolutils.sceneViewer() positions = scene_viewer.selectPositions(prompt='Click to specify a position', number_of_positions = 1, connect_positions = True, show_coordinates = True, bbox = BoundingBox(), position_type = positionType.WorldSpace, icon = None, label = None)
See the help for selectPositions(), BoundingBox, and positionType.
Manipulating the current viewport
To get the current viewport...
import toolutils # Get the scene viewer scene_view = toolutils.sceneViewer() # Get the current viewport viewport = scene_view.curViewport()
Calling the settings() method on the GeometryViewport object returns a GeometryViewportSettings object. This object has a ton of methods for getting and setting information about the viewport.
# Get the viewport's settings object settings = viewport.settings()
Among the most useful methods on the settings object are viewTransform() and setViewTransform(), which get and set the viewport’s transformation matrix respectively. You can
To set the viewport to look through a camera, use...
viewport.setCamera(camera_node)
To get the camera node that a viewport is currently looking through...
# Returns None if not looking through a camera viewport.settings().camera()
There’s a special method on viewports to copy their view to a camera or light, so you can copy the ctrl-click behavior of the standard tools on the Lights and Cameras shelf tab...
viewport.saveViewToCamera(cam_or_light_object)
Modifying node parameters
To modify the current selection, first get the selection as shown above. If the user already has an appropriate selection, you’ll get that, or Houdini will prompt her for a selection.
If you want to make an item that always modifies the same node, instead of the currently selected one (for example, a button that toggles the Activate parameter on an important node), just use the standard function to get a node by name...
my_cam = hou.node("/obj/cam1")
To modify a node’s parameters...
# Get a list of all parameters on a node all_parms = my_cam.parms() # Get the current value of a parameter current_lookat = my_cam.parm("lookat").get() # Set the value of a parameter my_cam.parm("lookat").set("/obj/torus1")
Tip
The argument to the Node.parm() method must be the internal name of the parameter. To find out the internal name of a parameter, hover over its label in the parameter editor. The internal name appears in a tooltip.
See the Python API for more information on available functions and methods.
Alternate clicks and other arguments
Houdini’s shelf uses a convention where clicking a tool with the Ctrl key held turns the tool into an immediate action. For example, the Camera tool on the Lights and Cameras shelf tab lets you place a camera in the scene, but ctrl-clicking it immediately creates a camera from the current view, instead of asking you to place the camera. Similarly, ctrl-clicking the Sphere tool on the Create shelf tab immediately places the sphere at the origin instead of asking you to place it.
If you want to use this convention in your own tool, you can use the value of kwargs["ctrlclick"] to see if the user ctrl-clicked your tool.
When Houdini calls your script, it sets a special dictionary variable named kwargs in the script’s context. This dictionary contains useful information. You can see its contents by creating a tool and giving it the following script...
# Convert kwargs to a string and pass it # to the displayMessage function. hou.ui.displayMessage(str(kwargs))
Key name | Value |
|---|---|
| Whether or not Shift was pressed when the tool was invoked |
| Whether or not Alt was pressed when the tool was invoked |
| Whether or not Ctrl was pressed when the tool was invoked |
| If invoked by right-clicking on a node’s input connector in the network editor, this is the index of that node’s input. Otherwise, it is -1. |
| If invoked by right-clicking on a node’s input connector in the network editor, this is the name of that node. (It will presumably be the output of a newly created node.) Otherwise, it is ''. |
| If invoked by right-clicking on a node’s output connector in the network editor, this is the index of that node’s output. Otherwise, it is -1. |
| If invoked by right-clicking on a node’s output connector in the network editor, this is the name of that node. (It will presumably be the input of a newly created node.) Otherwise, it is ''. |
| If invoked by middle-clicking on a node’s output connector in the network editor, this is True. Otherwise, it is False. |
| The name of the tool that was invoked. |
| If the tool was invoked from the shelf, it is None. If it was invoked from a viewer, it will be a hou.SceneViewer or other viewer pane tab instance. If it was invoked from the network editor, it will be a hou.NetworkEditor. |
| If the tool was invoked from the viewer, this is set to the hou.GeometryViewport where the tool was chosen. |