Did you know Aaron Paul from Breaking Bad fame once appeared on the game show The Price is Right? No joke. It just goes to show anything is possible. I wish I could be on The Price is Right. You know what else is possible? Using your own custom Python functions in Houdini parameter fields. How might this be handy? Well, imagine you created a custom random or noise algorithm or maybe you developed a set of custom utility functions. Sounds helpful doesn’t it? Let’s see how we can go about creating them.
You can find the other parts here:
- Part I – Python Parameter Expressions I: Basics
- Part II – Python Parameter Expressions II: Custom Functions
- Part III –Python Parameter Expressions III: Auto Import
So we have a line that we want to jitter the points on. Simple enough. There are various ways to do this in Houdini but we will create a custom function that you can impress your friends with at the Homecoming dance. Who knows, you might even get selected as the Homecoming king!
Again, we’ll do something contrived just to demonstrate the idea. This is by no means award winning or the best way to accomplish the task. The best way to learn how to code is by actually coding. You can’t learn this stuff through osmosis.
Line node with about 100 points in the
X direction. Then, attach a
Point node to it.1
The idea is we want to randomize the points in the
Y direction but do not want to affect the first and last points. These points should remain with a
Y value of
Right-mouse click on the the
Y position parameter field and convert the expression to a Python expression. While your mouse cursor is still on that parameter field, open up the Expression Editor by pressing
Command(CTRL) + e.
We want randomness, so the best place to start is just by importing the Python random module. Python has done the hard work for us already. Why paint a yellow banana yellow again. Let’s play around with the different Python
One of the nice things about using Python in Houdini is that you have access to the Python Standard Library. This is an extensive list of Python modules that offer a wide range of facilities. Want to do object serialization inside Houdini? No problem, import the
pickle module. Hold the mustard. For now, let’s just play with something simple.
Start by first importing the
random module. You should have the Houdini Expression Editor open. Type in the following:
random module is fairly simple to use. All you have to do is call
random.random() and you will get back a random number in the range [0.0, 1.0). This means the random number will be between 0.0 and 1.0. It will include 0.0 but never include 1.0. We can leave it at that and head out to the homecoming dance but we are going to dig a bit deeper. After all, it’s custom ™
We’re going to play around with some of the different methods in the
random class. Namely
gammavariate(). You may be asking where did I find those and what do they do? To answer the first question, open a Python shell by going to
Window then selecting
Type in the same
import statement in the shell as you did in the Expression Editor,
import random, then hit Enter. If you recall in the last post, we used the
dir() method to inspect the module. I’m going to introduce another method that gives you more information. Type the following statement after
You will see a bunch of text scroll by. Scroll through it and you will see the various classes and methods the
random class provides along with documentation. The
help() function just invokes the built-in help system. Just remember this function is intended for interactive use.
Python Random Module
So back to our Random class. Why did I pick these two particular methods? No reason. It’s just to experiment and see if something different came out of these methods. The
gammavariate() methods are used for non-uniform distribution applications that usually model real world situations. For instance,
normalvariate() is used for the analysis of astronomical data. Is this overkill? Of course it is, but again, experimentation can sometimes lead to wonderful discoveries.
Ok, let’s head back to the Expression Editor. One thing you want to remember is any Python code you write in the editor is treated as a function that needs to return a value. Type the following code after your import statement then hit apply.
Hey look! It works! That’s cool but let’s try out those other methods we talked about. Replace the previous return statement with the following:
Now lets try using the
gammavariate() method passing in the previous values.
I’m just entering arbitrary numbers but try entering different values and you’ll get interesting results. The method
gammavariate() sends our points upward in the positive direction and
normalvariate() gives us points going in positive and negative directions. Let’s bring our points back down a bit by dividing by the number of points. We can use our the handy local variable
$NPT which returns the total number of points. Remember how to use local variables in Python? We need to use the method
lvar() and pass in the local variable. You don’t have to use
$NPT, experiment with different values if you like. I like the output of the
gammavariate() method so let’s stick with it. Type in the following:
import random return(random.gammavariate(1,2)/lvar("NPT"))
So we have this working! Notice that every time we hit apply in the Expression Editor you will get back a different result. Now we want to keep the first point and the last point from being affected by the noise. We can code this by checking what point is being processed and skipping it but here us an alternate way. Drop a
Group node before the
Point node. Give the group a name and set the Entity to Points. In the Pattern field enter:
This gives us a Point group containing the first and last point. Why didn’t we just enter 0 and 99? Well, what happens if we add more points to the line? The Group node won’t contain the last point anymore. You would have to remember to go in and change the pattern values. By using the local variable
$N, which gives us the number of points – 1, we keep things procedural.
Now here is the trick! On your Point node, set the Group parameter field to whatever you called your group. Notice how this is totally not what we want. We want the inverse. Add an exclamation mark to the front of the group name and like magic we clamped our first and last points.
Wait, what does this step have to do with Python? Absolutely nothing. I was just adding a little spice to the task. Sort of like when you add curry to your Quinoa. Try changing the number of points on your line and see some procedural goodness. Basic but still very cool. It’s definitely cooler than that 90s remake of The Twilight Zone.
In our next installment we will learn how to save these custom these functions to a library and simply call them from our Parameter Fields while being able to pass a parameter or two. Keep it procedural!