Python in Houdini

Python and Houdini Start Up Scripts – Part 1

Upon starting a new Houdini session, the first thing I do is put down a camera node along with a ROP node in my scene. After a while, this can get a bit tedious. Not a big deal but why not automate it with Python and Houdini start up scripts. Let’s create a Houdini start up script that creates these nodes for us when starting up and sets some parameter values. I’ll break this up into two #QuickTips. In the first one all we want to do is get the script working. In the second #QuickTip, we will clean up the code and make it nice and pretty and deal with some issues that you will encounter when setting up the scripts.

Initialization Scripts

When Houdini starts up, it looks for a few initialization scripts. These scripts are in the directories specified on the $HOUDINI_PATH environment variable. Two initialization scripts that are handy are the 123 and 456 scripts. Yes, I know… Anyways, these scripts can either be Hscript or Python scripts. Houdini will only run either an Hscript or Python version of the script. So if you have both Hscript and Python versions of the 123 script, Houdini will only run the Python version.

The 123 script executes when Houdini is started without a scene file while the 456 script runs whenever a scene file is loaded or when you start directly from a .hip file. Read that again because it becomes important later on with your scripts as we shall see. The 123 script runs when you open a fresh session of Houdini. The 456 script runs when you open a .hip file or double click a .hip file which opens Houdini.

As you can imagine, you can have Houdini do a lot of work for you upon starting. You can have Houdini start with a certain state ready for you to work or if you work with large teams, you can have a script that sets up everyone’s scene the same or automatically loads certain assets. The script can be as easy or complex as you want it to be.

Scripts Location

Since we are going to be creating some initialization scripts, we first need to know where to place them. We want to locate our Houdini user preferences directory ($HOUDINI_USER_PREF_DIR). Dive inside the Houdini version you are targeting if you have multiple versions of Houdini installed and look for a folder called scripts. If you don’t have one, no big deal, just create it.

Creating a Camera Node

Now that we are ready to start, create a file called 123.py inside the scripts directory. We are going to be using the Houdini HOM API to create our script. Keep in mind you can also create a 123.cmd version if you’re more comfortable with Hscript. We are not going to write our script directly in the file just yet. We are going to use the Houdini Python shell to do a first draft of sorts. This way we can make sure our code works as expected since we can see things happen in realtime as we code. This is a good way of working and the beauty of Python interactive shells. Get things working then optimize. Open a Python shell or switch to the Technical Desktop.

So, first thing we need is a reference to an object level network. You can think of this node as a container or empty network where you will create nodes inside. We create this node by using the hou.node() function. You supply a path string and it returns a Node object.

obj = hou.node("/obj")

Now that we have this node object, we can create our camera node. We can create a new Houdini node instance by using hou.Node.createNode() on our obj reference. This method take various arguments but the only required argument is the Node type. Have a look at all the arguments you can pass in.

createNode(node_type_name, node_name=None, run_init_scripts=True, load_contents=True, exact_type_name=False)

Notice we can assign a node name, so we are going to do just that.

cam = obj.createNode("cam", "cam_1080")

# Side note
# The above works because the arguments are passed
# in the order that the function lays out its parameters
# The following will not work if you wanted to skip the name
# and set the run_init_scripts parameter to False
#
# cam = obj.createNode("cam", False)
#
# In this case you would need to include the parameter name
#
# cam = obj.createNode("cam", run_init_scripts=False)

You should see a camera node pop up in your Network View. Nifty! One thing you may be asking yourself is how do you get the name for the first argument? Or how do you know the internal name of the node you are creating? I mean, most people would have imagined to create a camera you would use “camera” and not “cam”.

Internal Operator and Parameter Names

If you want the internal name of an operator’s parameters, you will find it in the tool tip. If you hover over the operator’s parameter name you will get a nice pop up with the desired information. These are the names you will use to get and set an operator’s parameters. Now, to find the internal name of the operator object itself it’s a bit different. There are several ways to get the name but the easiest is just to use the operator’s info panel. Middle click your operator and you will find it right at the top of the panel within parentheses. This name needs to be passed in as a String value to hou.Node.createNode() For example, if you wanted to create an empty old geometry object, you would do the following:

obj = hou.node("/obj")
geo = obj.createNode("geo", node_name="myGeo")
Operator Name
Operator Name

 

Setting Parameters on a Node

Setting parameters on node objects is rather easy as well. We can use the hou.Node.setParms() method for this task. This method takes a Python dictionary. For those who are not familiar with dictionaries, these are data structures with unordered key:value pairs. The key is a string that is associated with a particular value so you can alway look up the value through its key. For example, “cat”: 3 maps the key “cat” to a numerical value of 3. Dictionaries are created using the syntax {key:value}. Here is an exmple:

# Creates a dictionary
d = {'one': 1, 'two': 2, 'three': 3}

If we take this concept to Houdini, you can see how a node’s parameters fit nicely into this data structure scheme. I want to set the resolution of the camera that we just created. First thing is to look up the internal names for the camera’s resolution and notice names is plural because resolution is two dimensions, x and x. The width is called resx and height is resy. I can now either store the dictionary in a variable and pass in the variable to hou.node.setParms()or just create the dictionary within the method. Remember we already have a reference to the camera object in our variable cam.

# Set the camera's resolution to 1920 x 1080

# First way
# Create a variable to story our resolution values
res = {'resx': 1920, 'resy': 1080}

# Pass in the variable to our method
cam.setParms(res)

# Second way
# create the dictionary within the method
# Watch those brackets!
cam.setParms({"resx": 1920, "resy": 1080})

Check the camera node’s parameter values and you should see the changes take place after running your code in the Python shell. One last thing I want to do is set the display flag off for the camera node. This is done through the hou.setDisplayFlag() function. This function simply turns the object’s display flag on or off. Notice that Python booleans True and False are capitalized. Alternatively, you can pass in 1 or 0. You cannot use the actual words “on” or “off”.

cam.setDisplayFlag(False)

Now let’s move on to creating a Mantra ROP.

Creating a Mantra ROP

So hopefully you probably tackled this one yourself since it’s basically the same process with one slight difference. If you followed the exact same steps, you probably got an error right off the bat saying something about an invalid name.

Rop error
Rop error

 

After the first error, you may realize that “mantra” is not the correct internal name. Remember the node’s internal name doesn’t necessarily coincide with the user-facing name. When I was first learning, this took me a while to figure out. So if you manually create a Mantra ROP, middle click the node to get its info, sure enough, the object name is “ifd”.

Mantra ROP
Mantra ROP

 

If you try again, you get the same error again. What gives? Have a look at where you are trying to create the ROP operator. The culprit is this line of code:

obj = hou.node("/obj")

Remember that you create ROP operators in the Out network context. When we created the camera, this line of code worked because we create cameras at the Object network level. We need a reference to an Out network. Let’s try it again by switching “/obj” with “/out”.

obj = hou.node("/out")
Creating a ROP node
Creating a ROP node

 

Set some parameters such as the camera we will be rendering out of, the render engine type and to speed things up, override the camera resolution. Give it a go and see if you can set the parameters. I’ll wait.

Right now you are probably thinking how do you get the names on the dropdown list for the rendering engine parameter? The hover trick is not working. The easiest way is to use the Parameter Interface window. Find the parameter and under the Menu tab, you should see the internal names under the Token column.

Drop down parameter names
Drop down parameter names

 

Another way is to use the opscript command which I recently did a #QuickTip on. You can manually set the value you want and then run opscript on the node. However, you will have to dig through the output to find the parameter which is a PITA. I’m sure there are other ways and if you know of any please Tweet me.

# Create Mantra - PBR driver
out = hou.node("/out")
rop = out.createNode("ifd")

# Set some parameters
rop.setParms({"vm_renderengine": "pbrraytrace", "override_camerares": True, "camera": "/obj/cam_1080"})

What’s Next?

Hopefully, you haven’t had trouble following along. As of right now we have just been testing things out in a Python shell to make sure everything works. If you were to transfer this code over to the 123.py script file and started up Houdini, everything should work as expected.

We can do better though. For one, we can clean up our code a bit. Second, open up a fresh new session of Houdini and then immediately create a new scene. What you’re going to find is the new scene doesn’t contain our nodes. What happens if you add this same code in the 456.py file? We’ll tackle this and more in the next episode of the Fall Guy. Sorry, #QuickTip.

Play around with the code by changing various parameters or creating other nodes that may be handy to your workflow. You can do many things with Houdini start up scripts. As with anything code, you have to get your hands dirty.

# Create Camera object
obj = hou.node("/obj")
cam = obj.createNode("cam", "cam_1080")
cam.setParms({"resx": 1920, "resy": 1080})
cam.setDisplayFlag(False)

# Create Mantra - PBR driver
out = hou.node("/out")
rop = out.createNode("ifd")
rop.setParms({"vm_renderengine": "pbrraytrace", "override_camerares": True, "camera": "/obj/cam_1080"})
Share:
990adjustments

990adjustments

I am a motion designer & developer based out of South Florida. When not designing or animating pixels, I wrangle some code. If all else fails, I watch Twilight Zone, I Love Lucy, or Three's Company reruns.