'The Magic of Houdini': What are VEX Operators?

In VFXWorld's latest excerpt from The Magic of Houdini, Will Cunningham discusses the basics of the graphical building interface to the VEX language.

All images from The Magic of Houdini by Will Cunningham. Reprinted with permission.

This is the next in a series of excerpts from the Thomson Course Technology book The Magic of Houdini by Will Cunningham. In the next few months VFXWorld readers will learn the basics of the dominant tool that has been used in the creation of some of the most awe-inspiring animation and cinematic effects ever made.

VEX operators (or VOPs) are the graphical building interface to the VEX language. Each VOP node contains a snippet of VEX code. You can graphically wire together nodes, which essentially creates blocks of VEX code. If you already know VEX, you'll find VOPs a quicker way to create VEX code. However, if you don't know VEX, that's fine too! VOPs were designed to be useful to all levels of users.

You can use VOPs to create very simple, specific shaders or you can create very complex, general shaders and anywhere in between. VOPs let you create new SOPs, so you can use them as a modeling tool. VOPs let you create new CHOPs, so you can use them as an animation tool. VOPs let you create new POPs, so you can use them to create effects. VOPs let you create new COPs, so you can use them to create cool compositing operations. For example, the Sprinkler POP was created using VEX, which means it can be created using VOPs. The VEX Mountain SOP was created using VEX, so you can create your own version in VOPs if you wanted to. VOPs can be used to make parts of a lighting system, designed so a new user just wires up the pieces and doesn't worry about the details. In a sea shell, VOPs are an extremely powerful context where your options and are both far and wide.

VEX, Expressions and Hscript

There are at least three "scripting" languages in Houdini: Hscript, Expressions, and VEX. In fact, Hscript and Expressions are very closely related and can work together. Hscript gives you commands to directly control Houdini and its user interface. You can add new operators, wire them together, change their parameters and many other things with Hscript. Expressions are often used directly in an operator's parameters to create channel references, animate a channel like using a sin() expression, and more. You can also use expressions with Hscript, to create more complex scripts.

VEX is a whole different world. VEX is a very specialized programming language that does one thing, and does it extremely quickly: It modifies attributes. When you create a surface shader in VEX (or VOPs, because VOPs are really just a GUI for VEX), you are modifying attributes on the surface of the object being rendered. When you create a new SOP or POP with VEX, you are modifying attributes of the geometry's points, like color or position. When you create a new CHOP in VEX, you are modifying channel data. When you create a new COP in VEX you are modifying pixels. As you continue through your journey in Houdini, you come to have more and more contact with each of these languages.

[Figure 1] The stucco VOP node.

Salutations to the VOP Node

One example of a VOP, being a Stucco VOP, is shown in Figure 1. Most VOPs have inputs on the left and outputs on the right. So, the Stucco VOP has eight inputs and one output. There are some VOPs, like the Global Variables VOP, that only have inputs even though they are located on the right of the node. This is because you are bringing information from geometry into VOPs for use. The Output VOP only has inputs, because this node is the last node in a VOP network and all information computed in a VOPnet must pass its results out through the Output node. Just as in other contexts, you can LMB the icon in the upper-left to drag the node around the network editor pane or MMB to get an popup info window. You can collapse the display of the node to varying degrees by selecting the 1, 2 or 3 dots to the right of the icon. Connecting inputs and outputs works just like in other contexts.

To wire the color output to some other input, LMB on color and then on the desired input. Say you had a P from the Global Variable VOP wired into P on the stucco node and you wanted to disconnect it. Just LMB on stucco's P input and then LMB again in a blank area anywhere in the network editor.

Some VOPs are actually a collapsed network of many VOPs with particular parameters promoted to the top level. To see what is going on inside a VOP of this type (like the Stucco VOP shown in Figure 1), just select it and press Enter to jump inside. Jumping into existing VOPs to see how the logic works is a great way to learn about the VOP context.

Creating a Soccer Ball Surface Shader

The most common use of VOPs is to roll your own surface shaders. So, we'll walk through how to do this using the soccer ball you created in the Chapter 5. This is a great example of the power of VOPs as the default shaders aren't capable of some of the behavior that you can easily create in VOPs. The completed exercise is available for reference in the Chapter 10>hips directory in the soccerballCompleteVOPs.hip.

Analyze the Look

As discussed in the previous chapter, the first thing to do when shading an object is to think about what makes that object look like it does. You have to decide what you want the surface of the soccer ball to look like. At its simplest, a soccer ball is a collection of alternating black-and-white hexagons. However, most of us stopped playing with those balls back in the 1980s. Now, much more complex patterns exist. So, let's create an interesting pattern, with a few labels on the ball and some scuff marks to give it a bit of realism. For a more complex soccer ball, you'll use custom attributes based on groups for the black-and-white patches and build in some dents. Then you'll add another couple of layers to apply some labels.

Consider Approaches for Achieving the Look

In Houdini, there are usually multiple ways to accomplish the same task. Often, there is no single best way to achieve a goal...ahem. It is a matter of experience and creativity to conjure an elegant solution. To create the more complex surface for the soccer ball, you could use simple shaders to apply color to the black-and-white areas. But how would you then apply the label which will cover more than a single patch, and the scuff marks, which will cover the entire ball?

One solution might be to have two pieces of geometry, two spheres, one inside the other. On the inner geometry, you could apply the black-and-white shaders to groups, which would be simple. Then, on the outer geometry, you could make it transparent except where the label and scuff marks are. This is perfectly valid, except it gets complicated when you start to do things like displacement, which actually pushes out the geometry. You could start to have problems with the inner sphere pushing out through the outer sphere.

Another solution is to use VOPs to create a single, more complex shader that is uniquely tied to the soccer ball and allows any level of complexity. As this is the better way and this chapter covers VOPs, you'll now pursue this method.

Visualize Groups on Existing Geometry

It is often useful to be able to visualize what geometry is a member of a particular group. The Visibility SOP allows you to easily do this.

  • 1. Load the soccerballComplete.hip from the chapter05 folder from the Website. You need to do a few things to it in preparation for using it in VOPs.

2. Jump into the soccerBall object. MMB on the applyWhite node and note that there are two groups, coloredWhite and coloredBlack. Quite often you will use a model or hip file from another artist and you will not have been involved in the creation of the model. Although for the soccer ball it's easy to tell which group is which, it is often not so easy.

3. To quickly visualize which group is which, branch append a Visibility SOP to the chain to the applyWhite node and rename it visGroups. In the Apply To menu, select Non-Selected Primitives and put the display flag on the Visibility SOP. Nothing interesting has happened yet. If you set the Apply To menu to Selected Primitives, the whole soccer ball disappears. That's because the empty Group field actually means "everything."

4. Set the Apply To menu back to Non-Selected Primitives and use the arrow next to the Group Field to select the coloredWhite group. This now shows you only the white patches in the viewport. Use the arrow to select coloredWhite again and the selection will clear. Select coloredBlack group to see only the black patches.

5. MMB on the Visibility SOP and then the node above it. Notice that the point numbers and primitive numbers are the same. The Visibility operation is not deleting or modifying the geometry in any way. It is simply hiding part of it in the viewport.

Apply UV Coordinates

It is now the time in your life for applying some UV coordinates.

  • 1. You're going to need UV coordinates on the soccer ball sooner or later, so you might as well apply them now. Drag the dispRender node down a ways and always keep it as the last node in the chain. Every time you need to insert or append the next operation, always ensure that the dispRender is still way down at yon bottom and is the last node in the chain.

2. Append a UV Project SOP to the chain (remember, above the dispRender node), and set the display and render flags to it. Move your mouse into the viewport and press Enter to go into the operational state. This should make the guide geometry visible, which by default is a blue grid indicating this is an orthographic (flat) projection. Set the Projection to Polar and the Group Type to Vertices. In the Initialize tab, click the Initialize button. You should see the blue guide geometry of the texture projection snap to the size of the soccer ball, as shown in Figure 10.2. The UV Project SOP will apply various UV projections to geometry with interactive viewport handles so you can rotate, scale, and translate the UV projection if you want to. Because this is a simple sphere, you can leave it as it is. Setting the Group Type to Vertices will make sure that the seams of the texture (where it wraps around) match up nicely.

[Figure 2] The initialized guide geometry using polar projection.

  • 3. To see the UV coordinates in the viewport mapped into a 0-1 square, over the viewport, hold down the spacebar and Ctrl and then RMB and select UV viewport. Alternatively, use the hotkey spacebar+5 and the viewport will change to show you the UV coordinates you just applied in a flattened out view. Use spacebar+1 to get back to the perspective view.

4. MMB on the uvproject node and notice that there is now a vertex attribute uv of size 3. These are your UV coordinates. Houdini applies them as three floats, because in fact they can be UVW, where W is the distance off the surface. This is normally not used; however, in rare situations where it is helpful, it is always available as the third number in the attribute.

Add a Custom Attribute

Speaking of attributes, you need to create a custom attribute as well. When you work in VOPs, you are creating a single shader that is applied to the entire soccer ball. This means that the two groups, coloredBlack and coloredWhite, can't be used directly to apply the black-and-white materials like you did with the Shader SOP in the Tree Trophy exercise. This is because a shader has no direct knowledge of the groups. However, shaders can look at an unlimited number of custom attributes and it is easy like pudding pie to embed the group information into a custom attribute.

  • 1. Append an AttribCreate SOP to the uvproject node and rename makeBallColor so that the network is visually clear. This allows you create any attribute you want and apply it to the geometry. You are going to create a single attribute called ballcolor and set it to 1, where the ball is white and 0 where the ball is black. Your shader will then pick up and use this attribute to color the appropriate areas.

2. In the Name field, enter ballcolor for the attribute name. Note that capitalization matters, so I recommend that all attributes that you create always be lowercase to avoid confusion. In the end scenario, you can do what seems most logical, but you will need to match this attribute's name exactly later when you create the VOP surface shader. Change the Class to Primitive. You don't want the points to have different values. You want each polygon (primitive) to have a value of 0 or 1. Change the Type to Integer because you only want values of 0 or 1, with no decimals.

3. Before you apply the group, look at what values the geometry holds right now. RMB on the attribcreate node and select Spreadsheet. This table shows you the attribute values of every point, primitive, vertex, or detail on the geometry. It is extremely powerful and you will use it a lot when you get into more complex projects in Houdini. In the spreadsheet, change the type of information from Points to Primitives. In the Show|Hide menu, turn off everything else but ballcolor, which should give you a single column under the ballcolor heading. This is the value of the ballcolor attribute for every primitive in the soccer ball. Scroll down through the values and you can see they are all 0 because you haven't changed anything in the attribcreate SOP.

4. Change the first Value field in the parameters to 1. Notice in the spreadsheet that all the primitives now have a ballcolor attribute value of 1. In the Group field, select the coloredWhite group. Now, scroll through and notice what has happened in the spreadsheet. Some of the polygons have a ballcolor value of 1 and now some have a value of 0. When you use a group in an Attribute Create operation, you are actually setting two values. You are setting all primitives not in the group to the Default value and also setting all primitives that are in the group to the Value value.

5. To better understand this, change the first field of the Default parameter to 2. Notice in the spreadsheet that the primitives that previously were 0 have changed to 2. The primitives that previously were 1 have stayed at 1. Because you have used the coloredWhite group in the Group field, you know that the Default value (currently 2) is being applied to all primitives except those in the coloredWhite group, which get the Value (currently 1) applied to them. Set the Default value back to 0. You know that those are the black patches because you only have two groups. Close the spreadsheet and make sure the Display and Render flags are on the dispRender node.

Find out more about how to apply each of Houdini's features to your projects as you take on modeling, character animation, particle effects animation, dynamic simulation animation, shading, digital asset creation and rendering. The Magic of Houdini by Will Cunninham. Boston, MA: Thomson Course Technology, 2006. 355 pages with illustrations. ISBN: 1-59863-082-2 ($49.95). Check back to VFXWorld frequently to read new excerpts.

Will Cunningham began his trek by studying both traditional art subjects and 3D computer software at the Academy of Entertainment and Technology. After his studies, he was hired as a Houdini technical intern by Side Effects, the developers of the Houdini software package. Eager to create effects for the big screen, he then jumped into production with BlackBox Digital on the feature, The Prince and Me. Shortly thereafter, he also began teaching Introduction to Houdini at the Academy and has since taught both the introductory and intermediate Houdini courses. In the fall of 2004, he was awarded a fellowship grant by Santa Monica College to support his efforts in creating this book. Over the years, he has worked for a number of production studios on a variety of projects, including The Chronicles of Narnia: The Lion, the Witch and the Wardrobe, Open Season and Ghost Rider. Currently, he is enjoying effects challenges and learning opportunities at Sony Pictures Imageworks.