The Complete Houdini: For-Each Loops (11/x) (Patreon)
Videos
-
clip01.mp4 -
clip02.mp4
Downloads
Content
Houdini users of all levels agree that one part of Houdini, perhaps above all others, just doesn’t make much sense and is hard to get a grasp on. That part? For-Each Loops. Iterating over geometry using loops is a great way to save time and create robust procedural setups, so it’s worth overcoming the obstacles and learning how it works.
And that’s what this installment of The Complete Houdini is for! By the end you’ll have a comprehensive understanding of Houdini’s For-Each workflow, including many of its lesser-known and frequently-misunderstood aspects.
Background
Before we start working in Houdini let’s get a refresher on what a for-each loop is. These types of loops are a central feature of all popular programming languages.
A for-each loop iterates over a list or set of items and performs operations on each item. Contrast this with a basic for loop which simply repeats as many times as you ask it to.
Have a look at this pseudocode:
list = “fish, bird, zebra”
for-each animal in list { print animal}
Running this would result in the following output:
fishbirdzebra
We take a list of three animals and iterate over each element in the list, printing out the name of the animal from the current iteration. The nice thing about this is that the loop adapts to the size of the input. If we add more animals we can keep the same code:
list = “fish, bird, zebra, bear, cat”
for-each animal in list { print animal}
Output:
fishbirdzebrabearcat
For-Each Loops in Houdini
So how does this work in Houdini? Instead of looping over animal types, in Houdini we’ll loop over a particular subset of an input geometry: points, faces or pieces. We can then perform operations on each iteration. Just as in our example code above, these loops will automatically adapt to the size of the input geometry. We could use the same loop to process the 4 points in a simple plane or the 8 points in a cube. This gives us a lot of flexibility and allows for reusable procedural setups.
Let’s get started by looking at the For-Each options in the Tab menu. (Reminder: you can now click on images to view the full size version!)
There are several choices listed here, but note that they’re all the same nodes, just with different starting parameters. (This is much like the various Wrangle options. Detail, Point, Primitive and Vertex wrangles are all the same Attribute Wrangle node with a different Run Over type selected.)
Let’s add a For-Each Point setup and see what it gives us.
This creates two nodes, a Block Begin and a Block End. These demarcate something like the opening and closing braces in our pseudocode, { and }. Every node placed between these are the operations we want to perform during the course of the loop. Houdini visualizes this by creating a colored background that surrounds all the nodes contained in the loop.
Fun bonus tip: the color of the background comes from the color of the Block nodes. Press C to bring up the Color Palette, select the Block Begin or End, then choose a color.
Note that we could construct this same loop by adding a Block Begin and Block End individually and telling Houdini where to look for each so that it knows the two are connected:
This isn’t ever really necessary since picking one of the premade configurations does the same thing in a more efficient way, but it shows how the basic building blocks fit together.
Let’s start modifying some geometry to familiarize ourselves with what the main For-Each parameters do. Say we wanted to set the color of each face in a grid. Attach a Grid to our Block Begin:
This gives our loop some geometry to work on. Now we need to tell it what part of the geometry to loop over. Set the Piece Elements to Primitives.
This will loop four times, isolating each of the four primitives (faces) in the grid one by one. Note that the Block End node updates to show how many iterations it’s processing. (If it doesn’t, click the Reset Cached Pass button.)
Add an Attribute Randomize inside the loop and set the Attribute Class to Primitives and the Attribute Name to Cd (color).
Oops! All the faces are the same color. Why is that? This is one of the primary stumbling blocks when learning Houdini For-Each loops. Even though we’re iterating four times, the seed of the random color generator is not changing, thus it produces the same color each time. We need to give it a new seed for each iteration. In programming we could do this by using an iterator, a number that increments with each pass of the loop. In pseudocode:
list = “fish, bird, zebra”iterator = 0
for-each animal in list { color = random(iterator) animal.color = color iterator = iterator + 1}
How do we set this up in Houdini? Click the Create Meta Import Node button in the Block Begin node:
This adds another, disconnected, Block Begin node within our loop. Click on it and note what it says here:
This node creates a few detail attributes that let us track the state of our loop. Of particular interest to us is the iteration attribute.
But let’s back up a second: what exactly is a detail attribute? Details apply to the entire input geometry and exist independently of the geometry’s individual parts. In this case our grid has 4 primitives/pieces and 9 points and each of those elements can have many attributes attached to each one. But these new detail attributes apply to the grid object as a whole. Open the Geometry Spreadsheet and click the Detail button:
Here we’re on iteration 3 (the fourth one since 0 is the first) and there are 4 total numiterations, one for each face of the grid.
Great, now we have an iterator that will increment by 1 each time the loops runs, just like in our pseudocode. This is all well and good, but we need to access that iterator to provide the seed for our random color.
And this is the single most… well, let’s be nice and call it “unintuitive” part of this whole workflow. We can access detail attributes using a detail function typed into any parameter. Paste the following into the Attribute Randomize Global Seed:
detail("../repeat_begin1_metadata1", "iteration", 0)
This is a VEX function that accesses a detail attribute at a specific location in the node graph. Here we’re looking for the “iteration” attribute contained at the address “../repeat_begin1_metadata1.” The last 0 is redundant and will never need to be changed to any other value. Note that you might have a different address in your node graph, so you’ll need to update it as required.
We now have a different color on each face! The random color generator gets a seed of 0, 1, 2 or 3 depending on which face we’re working on and thus outputs a different color each time.
To recap: we’re bringing in a grid with 4 faces and we’re asking our loop to isolate each face independently and run a random color operation on it. We use an iterator detail attribute to provide a seed for our random generator and this allows us to create a new color each time the loop runs again. The loop finishes after each of the 4 faces has been processed. We could increase the number of faces to say, 16, and the loop would still run perfectly fine:
We can manually step through the loop by enabling Single Pass in the Block End node. This lets us view the output of each iteration individually. Move the slider and we see each face isolated and given a unique color.
Before we move on let’s look at exactly how we’re able to access this detail attribute and why it works the way it does. Here are two other ways to achieve the same outcome using VEX and wiring the metadata node into the rest of the node tree. Use:
@Cd = rand(@opinput1_iteration + @seed);
Or:
@Cd = rand(detail(1, "iteration") + @seed);
Each of these accesses the iterator by checking the Wrangle’s input connector 1 using either the @opinput1_ or detail(1, …) syntax. I added an integer slider for a seed value to allow changing the overall colors.
I think the most perplexing thing for people in the original setup is that the metadata node managing the iterator isn’t attached to anything. Sure, it’s contained in the colored outline of the loop, but it doesn’t look like it should be doing anything since it’s not wired to any other node. This is circumvented because the detail function can access a node by its “address” in the graph, even if it’s not connected.
If you find this strange and hard to wrap your head around, I don’t blame you! In these other two examples we can access the iterator by actually wiring it into our node tree and accessing the value using VEX syntax. There’s no right or wrong way to do this, they all work the same. But you might find one approach a better fit for your thought process. If so, by all means use that going forward.
Before moving on to more advanced use cases, let’s get one thing out of the way: this example, randomizing the colors of the faces in some geometry, is way overcomplicated. The Attribute Randomize node will do this automatically, no need to make our own loop. We did it this way to illustrate Houdini’s For-Each mechanics as clearly as possible.
Let’s do something a little more complex and set the color of each face based on the number of the face. Houdini automatically numbers each point and face in any geometry. Click the Display point numbers and Display primitive numbers icons to see the numbers displayed in the viewport.
Each face is numbered 0 through 3. What if we wanted to set the color of each face from black to white depending on its number? For example, face 0 would be black, face 1 would be 66% gray, face 2 would be 33% gray and face 3 would be white.
We can do this by running some VEX code in our loop. We access our iterator and numiterations detail attributes and perform some math to set the color.
@Cd = (1 / @opinput1_numiterations) * @opinput1_iteration;
Just like our first example, this works fine with more faces in the input geometry. Add more faces and the we automatically create more shades of gray.
This is all still fairly basic, but you’re probably starting to see how loops work and might have some ideas for other tasks to apply them to. Let’s look at three loop-based techniques that advanced Houdini users often take advantage of.
Advanced For-Each Loops
Let’s say we were modeling an Aztec pyramid, which is boxes of smaller and smaller size stacked on top of each other. We could do this by just merging a bunch of boxes together, or by hand modeling insets and extrusions. But even with a simple model this is time consuming, annoying, and not very flexible. Any changes we make later will involve redoing some major aspects of the job. What if we could automate the construction of the model and retain control over the size and number of each new step on the pyramid?
We can create this entire model using just a single loop and a few nodes:
We set the PolyExtrude nodes to create a new Front Group called extrudeFront. We want to run each new extrude in the loop on only that group:
This means we can create this entire pyramid just from one grid. Well, we do need to give it a kick start by creating the group manually before the first iteration:
That gives the PolyExtrudes something to work with the first time, then, after that, each extrude overwrites the group to contain only the relevant face. Working this way we can create a completely procedural pyramid. We can go back and change the height of each step, the inset amount, the twist, and the numbers of total steps. Note that, unlike our first example, we’re setting the loop count manually. Change the Iteration Method to By Count and set the desired max iterations. This controls how many levels our pyramid has (5 here).
This is huge timesaver compared to creating the model manually. In this simple example, sure, you could get away with doing it by hand and it would be manageable. But increase the complexity even slightly and For-Each loops are the only practical solution. We could make heavy use of these type of loops to build an entire city with each building remaining modifiable without breaking anything in the overall scene.
Another important use of loops in Houdini is working with destruction simulations that include many procedurally generated fragments. Instead of creating a full fracture simulation here, we’ll fake the output of one by splitting up a cube. Fill a cube with points and create a Voronoi Fracture connecting the points and generating new geometry. Add an Exploded View node to push the fragments apart in 3D space:
This is a common setup that we’d find ourselves with after breaking something apart in a simulation, giving us a number of named pieces. Check the Geometry Spreadsheet and see that the Voronoi Fracture tagged each fragment with a piece attribute.
This will be used by our loop to treat each fragment as one unit even though it contains many points and faces.
Let’s say we wanted to apply detailed textures to each piece. That would usually require UVs, but do you want to hand craft UVs on every single piece of rubble here? Not likely! We could just run an Auto UV over the entire mess, but then we’d have a single UV tile with a ton of unfolded pieces on it. Doesn’t give us much flexibility.
Loops to the rescue. We can simply embed our Auto UV process into a loop and apply it individually to each piece.
Switch to the UV viewport and at first we just see a giant pile of UVs. Step through each part of the loop manually and we can see that each piece now has its own unique full UV tile. This is a perfect setup ready to accept procedurally generated or hand-painted textures.
Let’s quickly look at one more use case for loops. In the last article here we talked about the wonderful MOPs addon that makes setting up instanced geometry a breeze. Let’s explore a Houdini-native, significantly less breezy way to do this.
Add some test geometry, pack it so that it’s a single unit, then copy it to points.
Great, we’ve got some “instances” now, but how do we control them? If we try to modify the size or orientation of the geometry that just changes all the copies in unison.
We can fix this by creating a loop and inserting a Transform From Centroid node. This great tool lets us transform each instance relative to its own unique position. I stuck some randomization functions into each parameter I wanted to control and seeded them with an iterator.
And there we go, truly randomized instances created the old-fashioned way. MOPs is still the easiest way to go, but it’s great to know how to build things from scratch too.
Final Thoughts
For-Each Loops in Houdini enable setups that would be extremely time-consuming or downright impossible to achieve any other way, letting us iterate over massive amounts of geometry and apply any procedural modifications we might desire. Give them a try and think creatively about how you might put them to use in scenes you’re working on!