Code Snippets: Houdini Py

create a node

root = hou.node('/obj/')
node = root.createNode('node_type')

get node properties

name = node.name()
type = node.type().name()
position = node.position()
color = node.color()
comment = node.comment()

set node properties

node.setName('node_name')
node.setColor(hou.Color((1, 1, 1)))
note.setPosition([x, y])

note.setComment('comment')
node.setGenericFlag(hou.nodeFlag.DisplayComment, True)

delete a node

node = hou.node('/path/to/node')
node.destroy()

unlock a node

node = hou.node('/path/to/node')
node.allowEditingOfContents()

change node shape

node.setUserData('nodeshape', 'light') # light shape

check if a node exists

if hou.node('/path/to/node') == None:
    # the node does not exist
else:
    # the node does exist

get selected node(s)

selection = hou.selectedNodes()

set current selected node

node.setCurrent(True, clear_all_selected=True)

get a list of nodes

# get all top level nodes in a context
nodes = hou.node('/obj').children()

# get all children of a node
all_children = current_node.allSubChildren()

get primitive groups

node = hou.node('/path/to/node')
group_list = node.geometry().primGroups()

# get names
for group in group_list:
    name = group.name()

connect nodes

input_node = hou.node('/path/to/node')
output_node = hou.node('/path/to/node')

# option 1
output_node.setInput(0, input_node)
    # output_index, input_node

# option 2
output_node.setNamedInput('parm_name', input_node, 0)
    # parm_name, input_node, input_node_index

the input_node is the top node, while the output_node is below the input_node

ie. [input_node] ---> [output_node]


insert a new node between two existing connected nodes

start_node = hou.node('/path/to/node')
output_connections = start_node.outputConnections()

new_node = start_node.createOutputNode('node_type')

if output_connections:
    target = output_connections[0]
    
    output_node = target.outputNode()
    #output_index = target.outputIndex()
    # input_node = target.inputNode()
    input_index = target.inputIndex()
    
    output_node.setInput(input_index, new_node)

set display flag on a node

node.setGenericFlag(hou.nodeFlag.Render, 1)
node.setGenericFlag(hou.nodeFlag.Visible, 1)

layout nodes

# equal to hitting "L" in network view
root = hou.node('/obj/')
root.layoutChildren()

# layout specific nodes
# note: laid out in reference to first node in list
root.layoutChildren(items=[list, of, nodes], horizontal_spacing=1.7, vertical_spacing=1.4)

# layout a single node
node.moveToGoodPosition()

get node position

x, y = node.position()

get a parameter

node = hou.node('/path/to/node')
value = node.parm('parm_name').eval() # method 1
value = node.evalParm('parm_name') # method 2
value = node.parm('parm_name').rawValue() # method 3

set a parameter

node.parm('parm_name').set(value)
node.parm('parm_name').setExpression(expression)

create a parameter reference

master_node = hou.node('/path/to/node')
target_node = hou.node('/path/to/other/node')

master_parm = master_node.parm('parm_name')
target_node.parm('parm_name').set(master_parm)

create a parameter

node = hou.node('path/to/node')
parm_group = node.parmTemplateGroup()
new_parm = hou.FloatParmTemplate('name', 'label', 1)
parm_group.insertAfter('existing_parm_name', new_parm)
node.setParmTemplateGroup(parm_group)

get all parm templates in a parm group

parm_group = node.parmTemplateGroup()
templates = parm_group.parmTemplates()

remove a parm template from a parm group

parm_group.remove(template)

get node comment

comment = node.comment()

set node comment

node.setComment('comment')
node.setGenericFlag(hou.nodeFlag.DisplayComment, True)

create a sticky note

root = hou.node('/obj/')
note = root.createStickyNote()

customize a sticky note

note.setName('note_name')
note.setSize([w, h])
note.setPosition([x, y])
note.setText('sticky note text')
note.setTextSize(0.5)
note.setColor(hou.Color(1, 1, 1))
note.setTextColor(hou.Color(0, 0, 0))

create a network box

root = hou.node('/obj/')
box = root.createNetworkBox()

customize a network box

box.setName('box_name')
box.setSize([w, h])
box.setPosition([x, y])
box.setComment('title')
box.setColor(hou.Color(1, 1, 1))

get all network boxes (and some parameters)

root = hou.node('/obj/')
boxes = root.networkBoxes()

for box in boxes:
    name = box.name()
    size = box.size()
    position = box.position()
    comment = box.comment()
    color = box.color()

get a specific network box

root = hou.node('/obj/')
netbox = root.findNetworkBox('netbox_name')

get all nodes in a network box

nodes = netbox.nodes()

get current context

network_editor = None
for pane in hou.ui.paneTabs():
    if isinstance(pane, hou.NetworkEditor) and pane.isCurrentTab():
        network_editor = pane
        
if network_editor:
    network_node = network_editor.pwd()
    network_path = network_node.path()

display message

hou.ui.displayMessage('message to user')

create an arnold shader

shop_name = 'shaders'
shader_name = 'example_shader'
shader_type = 'standard_surface'

# create shopnet
root = hou.node('/obj/')
shopnet = root.createNode('shopnet')
shopnet.setName(shop_name)
shopnet.moveToGoodPosition()

# create vopnet
shop_path = '/obj/' + shop_name + '/'
root = hou.node(shop_path)
vopnet = root.createNode('arnold_vopnet')
vopnet.setName(shader_name)
vopnet.moveToGoodPosition()

# create shader
vop_path = shop_path + shader_name + '/'
root = hou.node(vop_path)
shader = root.createNode(shader_type)

out = hou.node(vop_path + 'OUT_material')
out.setInput(0, shader)

root.layoutChildren()

get current node (when run within a node, ie. a callback_script or hda)

current_node = hou.pwd()

# can also pass node args, such as:
def function(args):
    pass

create a new shelf

new_shelf = hou.shelves.newShelf(file_path='/full/path/to/shelf/file', name='shelf_name', label='shelf_label')

get an existing shelf

target_shelf = 'shelf_name'
shelf = None

shelves = hou.shelves.shelves()
for shelf_name, shelf_object in shelves.iteritems():
    if shelf_name == target_shelf:
        shelf = shelf_object

add a tool to a shelf

tool_list = list(shelf.tools())

file_path = '/full/path/to/shelf/file'
tool_name = 'toolname'
tool_label = 'Tool Label'
tool_script = 'print "Hello World"'
tool_icon = 'MISC_present'

new_tool = hou.shelves.newTool(file_path=file_path, name=tool_name, label=tool_label, script=tool_script, language=hou.scriptLanguage.Python, icon=tool_icon)

tool_list.append(new_tool)
shelf.setTools(tool_list)

somewhat basic ui start

import hou
from PySide2 import QtCore, QtWidgets, QtUiTools, QtGui

MODULE_NAME = 'uistart'
MODULE_LABEL = 'UI Start'
VERSION = '1.00'

class Dialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        # define the dialog
        super (Dialog, self).__init__(parent)
        
        self.setFixedSize(self.sizeHint()) # always keep widgets packed together
        widget = QtWidgets.QWidget()
        
            # open the dialog at mouse location
        mouse_position = QtGui.QCursor().pos()
        x = mouse_position.x()
        y = mouse_position.y()
        self.setGeometry(x, y, 250, 50) # (x,y,w,h)
        
        # add widgets to the dialog
            # horizontal divider line
        divider_layout = QtWidgets.QHBoxLayout()
        self.divider = QtWidgets.QLabel('')
        self.divider.setStyleSheet("QLabel {background-color: #3e3e3e; padding: 0; margin: 0; border-bottom: 1 solid #666; border-top: 1 solid #2a2a2a;}")
        self.divider.setMaximumHeight(2)
        divider_layout.addWidget(self.divider)
        
            # apply/accept/close buttons
        run_layout = QtWidgets.QHBoxLayout()
        self.apply_btn = QtWidgets.QPushButton('Apply')
        self.accept_btn = QtWidgets.QPushButton('Accept')
        self.close_btn = QtWidgets.QPushButton('Close')
        run_layout.addWidget(self.apply_btn)
        run_layout.addWidget(self.accept_btn)
        run_layout.addWidget(self.close_btn)
        
        # add layouts to the dialog
        main_layout = QtWidgets.QVBoxLayout()
        main_layout.addLayout(divider_layout)
        main_layout.addLayout(run_layout)
        
        widget.setLayout(main_layout)
        self.setLayout(main_layout)
        
        # prevent keyboard focus
        self.apply_btn.setAutoDefault(0)
        self.accept_btn.setAutoDefault(0)
        self.close_btn.setAutoDefault(0)
        
        # connect widget signals
        self.apply_btn.clicked.connect(self.onApply)
        self.accept_btn.clicked.connect(self.onAccept)
        self.close_btn.clicked.connect(self.onClose)
        
        # set widget values
        self.changeUI()
        
    def changeUI(self):
        pass
        
    def executeFunction(self):
        hou.ui.displayMessage('hello world')
        
    def onApply(self):
        self.executeFunction()
        
    def onAccept(self):
        self.onApply()
        self.close()
        
    def onClose(self):
        self.close()

#### Run ####
MODULE = Dialog()

if MODULE_NAME not in hou.sessionModuleSource.func_globals.keys():
    hou.sessionModuleSource.func_globals[MODULE_NAME] = MODULE # assign to hou.session globals
    
else:
    hou.sessionModuleSource.func_globals[MODULE_NAME].close()
    hou.sessionModuleSource.func_globals[MODULE_NAME] = MODULE # assign to hou.session globals
    
MODULE.setParent(hou.qt.mainWindow(), QtCore.Qt.Window) # stylesheet
MODULE.setWindowTitle(MODULE_LABEL + '::' + VERSION) # name of the dialog
MODULE.show()

more information