Procedural Typography in Houdini: Passing Custom Attributes into a For-Each Loop
25 Sep 26 (1mo ago)
How to Drive Per-Piece Variations in a Houdini For-Each Loop
When generating procedural typography or iterating over individual clones in Houdini, you often need distinct parameters for each piece—such as varying letter sizes, dynamic kerning (X-axis movement), or specific internal distances (Translate Y).
Instead of hard-coding values inside the loop, the most efficient, scalable approach is a data-driven structure. By defining attributes before the loop and referencing them inside the loop, you decouple your logic from your geometry data.
Here is the complete workflow to assign, pass, and utilize custom attributes per piece.
The Pre-Loop Setup: Packing and Structuring
Before entering the loop, your text or geometry must be split into individual, manageable elements.
- Font SOP: Generate your base text.
- Assemble SOP: Enable Create Packed Geometry. This packs each letter into a single point, which vastly improves performance.
- Sort SOP (Optional): Ensure your point order flows logically (e.g., left to right).
Defining the Data (Attribute Wrangle)
When establishing your structural node network, using a standard Attribute Wrangle is far easier to manage procedurally than relying on a multi-parameter randomize node. By writing a few lines of VEX before the loop, you gain absolute control over the sequence of your values.
Drop an Attribute Wrangle after your Assemble/Sort nodes to assign distinct values to each packed point:
// Define specific sequences for attributes
float dist_values[] = {3.0, 1.0, 5.0, 2.0, 8.0};
float size_values[] = {1.2, 0.8, 2.0};
// Use the point number (@ptnum) to index through the arrays.
// The modulo (%) ensures the list repeats if there are more letters than values.
f@midpart_dist = dist_values[@ptnum % len(dist_values)];
f@letter_size = size_values[@ptnum % len(size_values)];
The For-Each Loop & Spare Inputs
Create a For-Each Named Primitive or For-Each Point loop. Because your geometry is packed, each iteration of the loop will process exactly one point (meaning the current point number inside the loop is always 0).
To cleanly pass your wrangled attributes into the nodes inside your subnetwork or loop without messy, easily broken expressions, use the Spare Input method:
- Add a target node inside the loop (e.g., a Transform SOP to drive translation or scale).
- Click the Cogwheel icon (top right of the Transform SOP's parameter pane) and select Add Spare Input.
- A new parameter named Spare Input 0 will appear at the bottom.
- Drag and drop the
foreach_beginnode into this new slot.
Referencing Attributes via Hscript
Now that your Transform node is linked directly to the incoming point data via the Spare Input, you can reference the attributes natively in the parameter fields using the point() expression.
For example, to drive the Translate Y (ty) parameter using your custom distance attribute, enter this into the ty field:
point(-1, 0, "midpart_dist", 0)
Expression Breakdown:
-1: Directs Houdini to look at Spare Input 0 (the cleanest way to reference external nodes).0: Looks at point number0(the current packed letter)."midpart_dist": The explicit name of your wrangled float attribute.0: The attribute index (always0for single floats).
To Unpack or Not to Unpack?
A common misconception is that you must unpack geometry inside the loop to manipulate it.
- Do NOT Unpack if you are strictly altering transforms (scale, rotate, translate). Acting directly on the packed point is highly performant and preserves your transform matrix integrity.
- DO Unpack (using an Unpack SOP) only if you must execute vertex-level deformations (like bending or boolean operations) on the raw polygonal mesh.