Vex Attributes vs Variables

VEX Attributes vs. Variables

I’ve been getting quite a few emails regarding VEX and what certain things mean in the language. The questions have to do more about programming fundamentals than VEX. I know VEX is all the rage right now and for many, VEX is probably the first time trying out any kind of scripting. As a result, I’m going to do some tips on programming basics and the things you might run across while working with VEX. First, it seems there is some confusion about the difference between attributes which use the @ symbol and regular old variables that don’t . I assume you have passing knowledge of entering a few commands in a Wrangle node. Not necessarily that you know how to program. So, in this #QuickTip we will talk about VEX attributes vs. variables. Specifically, in the context of Wrangle nodes.

Houdini Attributes

I started putting wheat grass in my smoothies. Really has a chocolate like taste to it. Nothing like what I imagined a piece of grass would taste like. Well, while drinking my smoothie, I was watching a Houdini tutorial and the instructor was typing in some VEX code in a Wrangle node. The problem was that he kept using the @ symbol for every token he was creating. Some of these were just used calculate or extract a simple value. Why is this an issue? First, let’s talk about attributes.

If you were to look up attributes in the Houdini docs, you will read the following:

Attributes are named values stored on vertices, points, primitives, and objects. Point color, position, UV coordinates, spline weight (W), and normal, for example, are stored as point attributes.

So what does this actually mean? Basically, it is data that is attached and travels with the geometry. You can have Primitive attributes that deal with the geometry primitives. Point attributes which work on the geometry’s points. Vertex attributes that work with vertices as opposed to points and Detail attributes that work on the object’s geometry as a whole.

Houdini provides plenty of attributes for you right out of the box. Some of these are @P, @ptnum @Cd, @numpt, to name a few. These are the attributes that Houdini already set up for you. You don’t create them. You use them or modify them. If you want to sound cool at your high school reunion, you say that you read or write to them.

You can see the attributes on a node by opening a Spreadsheet or accessing the node’s info window. The attribute is in green and the light blue is the type of data the attribute contains. More on this later.

Particle Attributes
Particle Attributes

 

Custom Houdini Attributes

You can also create your own custom attributes such as @myCat. This custom named attribute can be used to drive other attributes or parameters in expressions, scripts, etc. A classic example that involves the use of attributes is to transfer the color attribute (@Cd) from one object to another. In the following example, I have a sphere that is transferring its @Cd attribute to a grid via an Attribute Transfer SOP. In addition, I created a custom attribute called @myCat that is assigned a random value based on the Primitive number of the sphere object. This custom attribute drives the local Z distance parameter of a Poly Extrude node on the grid. Nothing really earth shattering since I couldn’t come up with anything better.

Attribute Transfer
Transferring attributes

 

Attributes are a powerful concept in Houdini. If you are going to learn one fundamental thing in Houdini, make sure you understand attributes. Since we are talking about VEX and Wrangles, creating an attribute in a Wrangle node is quite easy. Just add an @ symbol before the attribute name so you end with a format such as @attribute_nameNotice you don’t need to assign a value right away but I highly suggest against this. Good practice is to always initialize your attributes with a value.

// Attribute with no assignment. DON'T RECOMMEND THIS.
@boring_attrib;

// Vector attribute
[email protected] = @Cd;

// Float value
[email protected]_random_value = (rand(@ptnum)*100)-200;

// Writing to our Position attribute
@P = set(1.0, 0.5, 0);
Attribute Wrangle attributes
Attribute Wrangle attributes

 

Hey, wait! What are those funny letters in front of the @ symbols? I’ll get to those in a minute.

Variables

Now that you know what attributes are, let’s talk about variables. A variable is a named storage space in memory that contains a value we can read or write. These values can vary or change over time. That’s why they are called variables.

Take for example a storage locker. When you pay for a locker, the locker has a number attached to it. This is your locker and no one else can take it. You can store whatever you want in the locker. Comics, gym shorts, wheatgrass smoothies, etc. If you need to store additional items or take out certain things, you can always find your locker by its number. When you declare a variable in a script, you are given a memory address by the operating system where you can store your values. Sounds a lot like attributes right?

Here are some examples of creating variables. You start with the datatype (I’ll get to this), followed by the name you want to give your variable, and finally the value the variable will contain. Again, notice that just like when you declare an attribute, you do not need to initialize the variable with a value. There are different schools of thought on this topic but I won’t get into it. Google it if you are interested in knowing more.

Variables
Variables

 

// Vector variable with no assignment. DON'T RECOMMEND THIS.
vector container;

// String variable
string myCat = "Waffle";

// Float variable
float randValue = fit01(rand(123), .1, .5);

// Integer variable
int number_of_cats = 3;

Datatypes

I’m glossing over many details that will be left up to user research but one thing I want to point out is that some programming languages require you specify what kind of value you are storing in your variables. VEX is one of those languages. So for example, if you were only going to store comics in your locker, you would specify you wanted a locker specifically for comics. Want to store your Yoo-hoo drinks, make sure the locker is big enough for them and preferably refrigerated.

This is what the single character just before the @ symbol or the keyword before the name are doing. You are specifying a data type. Please note that there is no space between the data type and the @ symbol. Custom attributes do not require you specify the data type but it is highly recommended you do. Otherwise, all @attributes with not datatype it will be cast to a float datatype. Houdini already knows the VEX datatype for commonly used attributes such as @P, @Cd, or @ptnum so there is no need to specify the datatype. Some people do it anyways and some don’t. I fall in the “don’t” camp.

When creating regular variables you qualify them with the whole keyword such as float, int, string, vector, etc. Once you declare your variables and attributes, you do not need to specify the datatype again.

The following table lists the available datatypes and the corresponding attribute syntax.

VEX type Syntax
float [email protected]name
vector2 (2 floats) [email protected]name
vector (3 floats) [email protected]name
vector4 (4 floats) [email protected]name
int [email protected]name
matrix2 (2×2 floats) [email protected]name
matrix3 (3×3 floats) [email protected]name
matrix (4×4 floats) [email protected]name
string [email protected]name

source: http://www.sidefx.com/docs/houdini/vex/snippets

The following table lists the available datatypes for variables with examples.

Type Definition Example
int Integer values 21, -3, 0x31, 0b1001, 0212, 1_000_000
float Floating point scalar values 21.3, -3.2, 1.0, 0.000_000_1
vector2 Two floating point values. You might use this to represent texture coordinates (though usually Houdini uses vectors) or complex numbers {0,0}, {0.3,0.5}
vector Three floating point values. You can use this to represent positions, directions, normals or colors (RGB or HSV) {0,0,0}, {0.3,0.5,-0.5}
vector4 Four floating point values. You can use this to represent positions in homogeneous coordinates, or color with alpha (RGBA) {0,0,0,1}, {0.3,0.5,-0.5,0.2}
array A list of values. See arrays for more information. { 1, 2, 3, 4, 5, 6, 7, 8 }
struct A fixed set of named values. See structs for more information.
matrix2 Four floating point values representing a 2D rotation matrix { {1,0}, {0,1} }
matrix3 Nine floating point values representing a 3D rotation matrix or a 2D transformation matrix { {1,0,0}, {0,1,0}, {0,0,1} }
matrix Sixteen floating point values representing a 3D transformation matrix { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} }
string A string of characters. See strings for more information. "hello world"
bsdf A bidirectional scattering distribution function. See writing PBR shaders for information on BSDFs.

source: http://www.sidefx.com/docs/houdini/vex/lang

 

VEX Attributes vs. Variables

Alright, with all that out of the way, let’s have a look at the following code that someone new to VEX might write in an Attribute Wrangle.

// Plain old integer value
[email protected] = 1234;

// Float value
[email protected] = @primnum * @multiplier;

// Float value based on random value
[email protected] = rand(@seed);

At first glance you may say that it looks fine. It works! Nothing to see here, move along. Open up a Spreadsheet and have a look at the attributes you currently have. Here we have our @P attribute along with the attributes the code above created.

Attribute Spreadsheet
Attribute Spreadsheet with attributes created

 

As you can imagine, the more attributes you have on a piece of geometry, the more expensive it becomes. This is why it is recommended that you delete any attributes that are not being used. The only attribute we want is @extrude. The other two attributes are just holding temporary values that we are really never going to use again. The issue here is that @multiplier and @seed are going to travel along with our geometry anyways.

What we really want is for multiplier and seed to be variables. We don’t need them to stick around. The only value we care about is extrude so we make this an attribute. The takeaway here is for values you need to access and travel with your geometry, you create attributes via the @attribute_name syntax. There are other ways of creating attributes in a Wrangle but we will keep things simple here. If you don’t need values to stick around, or are just calculating some temporary values, use variables.

Attribute and Variable Gotchas

We are going to refactor the previous code and use some variables to optimize our code. We will make multiplier and seed variables of datatype integer and float respectively. Have a look at this code:

// Plain old integer value
int multiplier = 1234;

// Float value
float seed = @primnum * multiplier;

// Float value based on random value
[email protected] = rand(@seed);

There are no errors so everything seems to be fine now. Not so fast! Have a look at the code again and look at your Spreadsheet. Remember, the Spreadsheet is your friend. It’s a debugger of sorts. Trust me, it will tell you a great deal about what is happening with your data.

Attributes and variables
Automatic binding

 

What is going on here? Why is seed still an attribute when we made it a variable and why does it have a value of 0.0? Have a look at what you are passing in to the rand() function as an argument. Notice the @ symbol attached to seed? Oops! Simple mistake but what is happening here is you are not using the variable you created. There was no error thrown because what you are seeing is automatic binding at work. All you did was create a new attribute on the fly. This is why seed appears as an attribute in the Spreadsheet.

Remember when I said attributes that have no datatype specified are cast to float values? Here it is initialized to 0.0. Automatic binding is convenient, however, silently binding non-existing attributes can be a source of bugs and headaches. Go ahead and remove the @ sign in front of seed so we are using it as a variable and not creating an attribute.

Another less obvious issue is the datatype used on seed. We used a float datatype but what we really need is an integer. We never get a fractional value from our expression for seed so why use a float. In this case, it’s not a big deal but it’s important to be aware of the type of data you are storing. This also can lead to bugs when the code starts to get more complex. Make seed an interger and you should see the following in your Spreadsheet:

Attributes and Variables
Final @extrude attribute

 

We can now use the @extrude attribute elsewhere as needed since it will be attached to the geometry. We also don’t have data hanging around bloating our geometry. Everything nice and clean!

Conclusion

I know that was a lot of information to take in so hopefully it helped demystify VEX attributes vs. variables in Houdini. It’s not a hard concept to grasp but if you’re just starting out it can be a bit confusing especially, if you don’t have any programming experience. Here are a few more resources that probably provide a better explanation an go over things in some more depth. If you have any questions or see some errors please Tweet me.

Introduction to Vex

CGWiki

ILLUME Webinar | Houdini VEX

Using VEX Expressions

Share:
990adjustments

990adjustments

I am a motion designer & developer based out of South Florida. When not designing or animating pixels, I wrangle some code. If all else fails, I watch Twilight Zone, I Love Lucy, or Three's Company reruns.

Leave a Reply