Houdini Python

· Houdini MOC · Python ·

TOC

Tips

To get available packages dir()

Hscript $F becomes in Python hou.frame(), $T becomes hou.time()
Local parameters: Hscript $CY becomes in Python lvar("CY")

To store some form of variable in a way that it persists over multiple scripts or executes of a script, you can use hou.session. Open the python shell and write hou.session.foo = "Hello!" Now you can call hou.session.foo anywhere and your variable will persist!

Snippets

Basic node operations

SOPs

import hou

# Define geometry node name
geometryName = 'MY_GEO'

# Get selected node
node = hou.selectedNodes()[0] # can also drag and drop into shell

# Get node upstream connections
listParents = node.inputAncestors()

# To get the parent node n:
n.node("..")

# Get scene root node
sceneRoot = hou.node('/obj/')

# Check if "MY_GEO" exists
if hou.node('/obj/{}'.format(geometryName)) == None:
    # Create empty geometry node in scene root
    geometry = sceneRoot.createNode('geo', run_init_scripts=False)
    
    # Set geometry node name
    geometry.setName(geometryName)
    
    # Display creation message
    hou.ui.displayMessage('{} node created!'.format(geometryName))

else:
    # Display fail message
    hou.ui.displayMessage('{} already exists in the scene'.format(geometryName))

LOPs

# get the selection of a lopnetwork inside a geo sop network
hou.node('/obj/geo1/lopnet1').selection()

# get the selection of the "root" stage context
hou.node('/stage').selection()

# set selection
paths = ['/scene/geo/sub/sphere', '/scene/geo/sub/box']
hou.node('/stage').setSelection(paths)
lop_node = hou.node('/stage').node('null_1')
# <hou.LopNode of type null at /stage/null_1>

stage = lop_node.stage()
# Usd.Stage.Open(rootLayer=... ...LOP:rootlayer-session.usda'))

stage.GetPrimAtPath('/materials/green')
# Usd.Prim(</materials/green>)

A python expression can use hou.lvar('primpath') to get the path and from there get the USD prim from which further information can be retrieved, for instance pwd().input(0).stage().GetPrimAtPath(hou.lvar('primpath')).GetPrimStack()[-1].layer.identifier

Toggle update mode hotkey bind

# David Torno "Toggle Update mode Auto/Manual"  
# Make a Shelf Tool and assign it a Hotkey, and place this code in the "Script" Tab...
  
import hou  
mode = hou.updateModeSetting().name()  
if(mode == "AutoUpdate"):  
    hou.setUpdateMode(hou.updateMode.Manual)  
if(mode == "Manual"):  
    hou.setUpdateMode(hou.updateMode.AutoUpdate)

Camera lock hotkey bind

# David Torno "Toggle camera lock/unlock"  
# Make a Shelf Tool and assign it a Hotkey, and place this code in the "Script" Tab...  
  
pane = hou.ui.paneTabOfType(hou.paneTabType.SceneViewer)  
view = pane.curViewport()  
view.lockCameraToView(not view.isCameraLockedToView())

Get current camera

Python expression to get the path to the current viewport's camera

cd = hou.ui.curDesktop()
tab = cd.paneTabOfType(hou.paneTabType.SceneViewer)
vc = tab.curViewport()
return vc.cameraPath()

External Commands

Using subprocess

import subprocess
subprocess.call(["cmd"])
import os.path as op
test = op.join(hou.expandString("$HFS"),"bin","hcmd")
subprocess. call([test])

Create Karma Material subnet and USD Preview Material subnet with Python

import hou
import voptoolutils

materialLibrary = hou.node('/obj/lopnet1/materiallibrary1')

#create Karma MtlX builder inside specified LOP materiallibrary
mask = voptoolutils.KARMAMTLX_TAB_MASK
mtlxbuilder = materiallibrary.createNode("subnet", "karmamaterial")
voptoolutils._setupMtlXBuilderSubnet(mtlxbuilder, "karmamaterial", "karmamaterial", mask, "Karma Material Builder", "kma")

#create UsdPreviewMaterialBuilder inside specified LOP materiallibrary
mask = voptoolutils.USDPREVIEW_TAB_MASK
usdpreviewbuilder = materiallibrary.createNode("subnet", "usdpreviewmaterial")
voptoolutils._setupUsdPreviewBuilderSubnet(usdpreviewbuilder, "usdpreviewsubnet", mask, "USD Preview Material",)

Simple UI

hou.ui.displayMessage('Hello')
hou.ui.displayMessage('hello', ['ok','cancel'])
hou.ui.readInput('Type your input')

Buttons

Button callback python expression

Wired to a button, that rewrites values of the dictionary interface named groups

hou.pwd().parm('groups').setFromData({'dictionary': {'Eyebrows':'brows|eyebrow','Eyelashes':'eyelashes'}})

Button python code

Create a multistring field
Set language to Python
Use python callback:

exec(kwargs['node'].parm('pythoncode').eval()) # where python code is the name of the filed

Installing python packages using pip

Houdini comes with its own python environment that is independent of the system python. Out of the box it will at times lack some packages.
To install a new python package using pip inside of houdini's python environment, in the python shell use:

import pip
pip.main(['install', 'package_name'])

Using an IDE to write into python nodes

Create a folder in your $HIP directory where you will place your .py files. For example, you can create a file working directory"/python/example_file.py
Create a Python node and insert the following code:

file = "example_file"
folder = "python"
exec(open(hou.getenv('HIP') + '/' + folder + '/' + file + '.py', 'r').read())

Enjoy all the benefits of your favorit IDE!

Solaris inspector custom data

This can run a custom python code to evaluate something useful.
The code is located in Program Files/SideFx.../Houdini v.v.v/houdini/scene/inspect_usd_prim.py

Wrote this little function to fetch the first Mesh subprim and a specific attribute from it. It detects if the attribute is a list/array and then it outputs min:max values, otherwise it outputs the actual value or indicates if the attribute is not present.

Not sure how Python can handle all the diversity of the USD datatypes yet, so you'll have to take care of it from here for vectors/matrices/etc. Code updates require a Viewport reset (at least I haven't found another way yet).

import hou
from pxr import Sdf, Usd, UsdGeom # can be useful but not here

def inspect(viewer, viewport, stage, primpath):
    attr_name = "primvars:hl" # set the attribute name
    try:
        parent_prim = stage.GetPrimAtPath(primpath)
        child_prim = parent_prim.GetChildren()[0]
        attr = child_prim.GetAttribute(attr_name)
        if attr.IsValid():
            attr_val = attr.Get(hou.time())
            if hasattr(type(attr_val), '__len__'):
                res = f'{child_prim.GetName()}\n {attr_name}({len(attr_val)}) = {min(attr_val)}:{max(attr_val)}' # min:max values for data that has length
            else:
                res = f'{child_prim.GetName()}\n {attr_name} = {attr_val}'
        else:
            res = f'{child_prim.GetName()}\n {attr_name} not found'
        return res
    except:
        import traceback
        return traceback.format_exc()