The other day I was watching Just One of the Guys and suddenly I thought how would you go about creating spare parameters in a Python Sop in Houdini. I mean, we know that in our trusty VEX Wrangles, we write a line of code, click on that little thingamajig and suddenly we have our custom parameter. However, I don’t remember seeing one of those in a Python SOP. Hmmm… Anyways, today I’ll go exactly over that! We will be creating spare parameters in a Python SOP and connect the Python code to the parameter. A little different than in a Wrangle but not painful.
Parameters The VEX Way
So I will admit it is much easier achieving this in a VEX Wrangle. All you do in order to create spare parameters in a Wrangle is to make a call to the
ch() function and assign that to a variable and your are golden. It’s really that easy. However, if you have some Python chops, why not leverage them?
Parameters The Python Way
If you are using a Python SOP and want to create spare parameters, you need to take a different approach than you would in a VEX Wrangle. The first thing you need to do is create the spare parameter via the Parameter Interface window.
Once in the Parameter Interface window, drag over your data types you intend to use and set up your parameter name and label. Remember what you are naming the name parameter because that will be important later. This is the internal name Houdini uses to access the data. The Label is just for the UI.
Before you can use your new parameters you need to hook them up with a bit of Python code. You are doing the opposite of how you would do this in a Wrangle. Except for the icon thingamajig.
The evalParm() Function
In order to use the spare parameters we need to use a bit of Python code. The line of code that does the magic is
node.evalParm(path). Let me explain this a bit more.
In a VEX Wrangle you would use the function
ch('path') to hook up your custom parameters. In Python you use
evalParm(path) function as you might have guessed evaluates a parameter. This function takes an absolute or relative path. This just means the path to the parameter value you are hooking up. It will return an
string depending on what type of parameter you feed it. Remember the name you gave your parameter back in the Parameter Interface window? That’s what this node is after. However, this could be any other parameter that is already available. So you can use this function to drive the value of a parameter from another node. Just make sure you set the Expression Language to Python at the top-right of the Parameters Pane.
When you use the function in a regular parameter field, Python knows you are referring to the node itself so you don’t have to prefix it with a node object. It returns the node containing the expression. However, when you are using it in a Python SOP, you need to be more specific.
When you first drop down a Python SOP, you get some initial code. Have a look at the following code:
# 1 node = hou.pwd() # 2 geo = node.geometry() # Add code to modify contents of geo. # Use drop down menu to select examples.
Here is what is going on with these two lines of code.
- The first line is getting a reference to the current node. In other words, grab all the data associated with this node and stuff it into a variable called
node. The other way of doing this is
node = hou.node('.')Using
pwd()is a shortcut.
- The second line of code looks into this newly created variable and grabs the geometry data that is being fed into this node by calling its
geometry()method. So if you have a Grid SOP being fed into the Python SOP, it is reading in all the points from the Grid SOP.
Now that we have a reference to this Python SOP via the
node variable, we can use
evalParm(path)to access each parameter and stuff that value in a variable which we can use throughout our code. So for instance, if we had to custom parameters named seed and threshold, this is how you would use the
seed = node.evalParm('seed') threshold = node.evalParm('threshold') # use seed and threshold to set values
A Simple Example
Let’s do a quick example to drive home the point. Nothing fancy here. We are just going to delete primitives based on a threshold value. The threshold will be our custom parameter. So drop down a grid and attach a Python SOP. Then open up the Parameter Interface window and add a Float parameter named threshold. I also set the range of the parameter to go from 0 to 1. Time for some Python code!
# 1 import random # 2 node = hou.pwd() # 3 geo = node.geometry() # 4 threshold = node.evalParm('threshold') # 5 for i in geo.prims(): #6 if threshold > random.random(): #7 geo.deletePrims([i])
Let’s go through this.
- First we import the Python Random module. This is just to quickly generate a random value between 0 and 1. This is the benefit of using Python. You have access to Python’s vast and powerful libraries.
- We grab a reference to the object using
- Grab the geometry data that is being fed into the Python SOP from the Grid using
- Here we connect our slider parameter using the
- We loop through all the primitives with a simple
- Check if the threshold value is greater than our random value generated. You can do this various ways. I wasn’t trying to get fancy here.
- If the threshold is greater than the random number (or I guess it could have been the other way around), delete the primitive. Note
deletePrims(prims)expects a sequence thus the square brackets.
That’s it! Yes, using Python is a bit more verbose than using VEX and some folks may find using VEX easier. Also, many folks will tell you that using VEX is better suited for all geometry manipulation and I do agree with that. Python excels at management and file I/O among many things. However, it doesn’t mean you can’t use it. Especially with simple tasks. Knowing Python is a big plus in my book. Time to ride!