Introduction:
VEX is a scripting language that is native to Houdini. It allows you to develop very fast and very complex functionality for you procedural modeling tasks, as well as many other tasks inside of Houdini. Throughout these posts we will focus mainly on how to use VEX to create procedural models for games. This post assumes you are completely new to VEX and would like to learn the language from the ground up. You do not need any experience with the VEX language but having knowledge of how to use Houdini is a plus as we will not be covering the basics of using the Houdini application.
Ok so let's move on and get into VEX. We are going to start with the Wrangle node. As of this posting, we are using Houdini 17.0.352. When you hit tab inside of a GEO node, you will find that there are a bunch of different types of wrangle nodes available. There is the Attribute Wrangle node, the Point Wrangle Node, the Primitive Wrangle Node, and the Detail Wrangle Node. Don't let these nodes fool ya. They are all the same, except that their context is set to their respective type. meaning the context drop down is set to point, primitive, or detail.
So lets drop down an Attribute wrangle node and begin to learn a little about VEX. I usually drop down the Attribute Wrangle node and then just change the context to the type I want. Most times you will find yourself working with points or prims. Detail is useful but we will discuss that here in a bit. So create an Attribute Wrangle node inside of a geometry node. This will get us set up for the next step.
Variables and Attributes:
When we are working with VEX code we should start by understanding the difference between a "Local Variable" and an "Attribute". These are two very different things so making sure we have a solid understanding is key to being successful with VEX.
A Local Variable, in VEX, is one that we declare inside of the Wrangle code editor. A local variable has a very specific format we should follow. We always write a local variable as such.
float myVariableName = enter some code here;
The first part of that declaration is the variable type. By saying we want this variable to hold a float value we are saying that this variable will hold a decimal value....or something like 1.2, 0.05, 10.3. Any number that has a decimal in it is a float value. There are a lot of types we can declare in VEX and it is pretty much the same in any programming language you might encounter.
We have the integer type which is indicated by the "int" keyword, the string type which is indicated by the "string" keyword, the vector type which is indicated by the "vector" keyword, and a few others. See the following for an explanation of what each of the types hold.
float = a decimal value, e.g. 0.02, 10.5, 20.45345
int = an integer value e.g. 1, 5, 4, -10, -32
string = a text value e.g "some text", "my code", "some more cool text"
vector2 = a value that holds two floats e.g {1,1}, {2,3}, {4.3,8.4}
vector3 = a value that holds three floats e.g {2,3,6}, {4.3, 5.6, 2.9}, {6.5, 4.5, 7.6}
bool = a value that holds true or false...or 1 or 0 e.g True, False, 0, 1
There are a few more value types but we will focus on these for now and get into some of the more complex ones in a later post. We can do quite a lot with just this set of value types.
The next part of a variable declaration is the variable name. This tells the computer how to identify the value that we are declaring. It can be any name you want but without spaces or special characters. I perfer to use what is called camel case for my naming. This is where the first letter in the variable name, is lower case and every following word has an upper case letter. For example:
myCoolVariable
I have found that this makes my variable names much more readable by myself and others. You can use any naming convention you'd like and can find more info at this link.
The last part of the variable declaration is the setting of the value. By putting an "=" symbol after the variable name, we are setting the initial value of the variable. This doesn't have to be done and if there is no initial value set, then the variable will default to a built in value. Usually zero, false or null.
So lets write some code and get into creating local variables. Enter the following code into the wrangles code editor:
float myVarA = 2.3; float myVarB = 1.4; float sum = myVarA + myVarB; printf("The sum is: %g\n", sum);
This code declares two local variables and adds them together, then prints the result out to the Houdini Console, using printf().
The local variables are only available to the current wrangle node. No other node, in your network can use those variables, hence the reason why I call them Local Variables. They are local only to the wrangle node they are declared in. If we want to be able to pass around the data to other nodes, we need to declare VEX attributes. These are created in a slightly different way but are very powerful and absolutely needed when creating procedural modeling networks.
To declare an attribute, we need to include the "@" symbol before the variable name. Plus we need to identify the type in a different way. Instead of writing something like int to declare an integer type, we simply type the following:
i@variableName
This declares a new attribute and this attribute can be seen by other nodes and can even exist throughout your whole network. This is how we pass data around inside of Houdini. Using attributes means we can then see our data in what is called the "Geometry Spreadsheet". Open the Geometry Spreadsheet by clicking on the little plus button next to an already existing tab. Then Select "New Pane Tab Type", then select the Geometry Spreadsheet from the list of Pane Tab Types. This is where we can view the current value of our attribute as it travels from one node to the next.
So lets create a new attribute and see this awesomeness in action! Type the following code into the Wrangles code edtior and then look at the Geometry Spreadsheet. Make sur eyou have an add node hooked up with at least one point added. We need this node since our Attribute Wrangle node is set to "Run Over" points.
i@myAttr = 10;
Notice how we now have a new value in our Geometry Spreadsheet called myAttr. And it is initialized to a value of 10! Pretty cool! This means we can pass this value to other nodes, where as with the local variable we can not.
So to sum up, Local variables are values we create that are only local to their wrangle node, and attributes are values we create to pass data to other nodes. That's the difference between these two types of data declarations. Try out more declarations for yourself to get a handle on it. We use variables and attributes all the time throughout our VEX coding.
One thing to keep in mind though, creating everything as an Attribute is not recommended. Try to only expose the data you know you will need in other nodes and everything else is kept as a local variable. The reason being is that the more attributes you create the more of a performance hit you take, plus it also beings to make your Geometry Spreadsheet unmanageable and disorganized. The more VEX you write the better you will be to decide when to make a local variable and when to make an attribute.
Points and Lines
At this point we should take a look at how to add new geometry. We can do this simply by using the addpoint() function. This function takes two arguments. The first argument is the geometry we want to add a point to, and the second is the position at which we want to place the new point.
addpoint(0, {0,1,0});
Lets add it to a new wrangle node so we can see the result of using this function.
We now have a new point in our scene. Lets add another point to our geometry so we can ultimately draw a line. Enter the following code:
addpoint(0, {0,0,0});
We now have a second point. Now that we have two points let take a look at the addprim() function. This will add a new primitive to the geometry and give us the option of turning it into a line. The addprim() function takes a few arguments. In this case we are going to use the function below.
addprim(0, "polyline", 0, 1);
The first argument is the geometry we want to add to. The second is the type of primitive we want to create, which in this case, is a polyline. The last two arguments are the index values of the two points we want to connect. Point 0, and Point 1. We have these two points because we added them with the addpoint() function.
And there we have it! We just created a line with two points, pointing up in the "Y" direction by 1 unit. Pretty cool! I have a whole series of VEX tutorials on my YouTube Channel. Check out PArt 1 below!
Conclusion and Resources
Ok, so I am going to close out this post about VEX. Here we got to take a look at the first steps of using VEX inside of Houdini. There is so much more to learn and I will do my best to cover as much as I can throughout the coming weeks and months in these blog posts! You can also go to the Indie-Pixel youtube channel and watch the Intro to Vex series, where I cover even more techniques and the foundations of VEX. Thanks so much! :-)