So we covered basic Python expressions and how to work with custom functions. Alright, that’s nice and dandy but how do we get Houdini to load our custom functions so they are always available? Custom functions can auto load in a couple of ways. You need to setup a few of things but it’s quite straightforward. Today, we will look at how to auto import our functions so they are always available.
If you need to catch up, here are the previous posts:
- Part I – Python Parameter Expressions I: Basics
- Part II – Python Parameter Expressions II: Custom Functions
- Part III – Python Parameter Expressions III: Auto Import
Setup Python Files
First, navigate to your Houdini preferences folder. Create a folder called
python2.7libs and dive inside. Create a file called pythonrc.py. This file will contain your code. The file name is important. Don’t name the file waffle.py or scrambles.py.
Houdini runs the code in the file when it starts up. This will give us the ability to just type in our function name in any parameter field. Open the file with your text editor. We are ready to drop in some code.
What we need to do now is wrap our code inside function syntax. Recall single lines of Python code run as standard expressions, but many lines of code run as part of a function body. Transfer the jitter code over to your
import random def lineJitter(alpha, beta): return(random.gammavariate(alpha, beta) / hou.lvar("NPT"))
First, this is a start but Houdini still won’t know what to do with the code. We need to tell Houdini, “Here, take my code and place it alongside your other expression code”. For this, we will make use of the
hou.expressionGlobals() function. This function returns the globals dictionary used by the parameter expression evaluation namespace. Python expressions run in a different namespace than the global namespace. This helps avoid polluting the global namespace and getting in all sorts of trouble. We are adding our custom function to the
expressionGlobals() dictionary so it’s available when we invoke it in a parameter field.
Have a look at the output of the
hou.expressionGlobals() function in a Houdini Python shell. You will see a bunch of
key/value pairs scroll by. We want to inject our code into that sea of madness.
Second, notice I’m appending
hou to the
lvar() function. The reason is because of namespaces as well. When you are running Houdini, it automatically does
from hou import * which brings in the Python expression namespace and allows us to drop the
hou in the parameter fields. The
pythonrc.py file is not running in the Python expression namespace.
Third, I’ve refactored the function to accept arguments. You can hard code the numbers but this gives you the ability to experiment without having to restart Houdini every time you want to change the numbers.
import random def lineJitter(alpha, beta): return(random.gammavariate(alpha, beta) / hou.lvar("NPT")) hou.expressionGlobals()["lineJitter"] = lineJitter
The last line of code is just saying create a
key called “lineJitter” and assign it the
lineJitter. In this case, we are assigning the function we just defined. The
key portion of this can be called anything you want. This name is what we type in our parameter fields when we write our expression. The
value is the code we want to run.
At this point you want to start a new Houdini session if it was running. Once Houdini is back up, you can type your function name in the appropriate parameter field, passing any arguments and do a happy dance. You should see that Houdini pops up our function signature. You can even create custom parameters to interactively change the arguments in your function.
Well, that does it for now. Next time, we will improve upon this idea by placing our functions in a separate module to keep
pythonrc.py nice and light.