Using VEX to Art Direct your Copy Stamp (Part 2)
In the last post, I had spoken about how we can use VEX to Art Direct our Copy Stamps and Wedges but it was more of a manual approach to setting up the system. We can now begin to build a system that would allow users to deal less with the VEX code itself and more with the Houdini Interface to not only set up their Art Direction parameters and systems but also create setups quickly! The goal is to slowly build an HDA that encompasses the entire tool and allows users the opportunity to simply add attributes and parameters on demand without having to deal with the pain of setting things up manually.
Before we begin with this post, let's look back at some of the issues with the previous system:
1. Manual Process: If an Artist wants to set up the Parameters he has to make sure the names of the parameters and the attribute name on the VEX Code match each other. This has a huge scope for mistakes and can cause things to break even if one or the other changes.
2. Tedious: The user has hard code the attribute names into the code along with their type, this can be tedious and reduce the scope of working fast or customizing the system according to your shot. What if you suddenly decide you want the attribute to be a global attribute (same value on all points)? What if you suddenly want to switch the type from a vector to float etc? What if you want to suddenly add attributes specific to a shot on demand? These issues mean that users have to pay attention to every step carefully which reduces the scope for a fast workflow or can lead to the system breaking easily.
3. Tough to debug immediately: Although it is not a complex system as it involves several aspects of the basics of Houdini Parameter Interface, debugging things can be complicated as you have to run through all the steps every time to find the issue. As mentioned earlier, even one hiccup can cause the flow to break.
How do we Solve these Issues?
If we break the systems into three simple sections we can categorise them as "The VEX or Expressions Section", "The Parameter Interface Section" and "The Copy Stamp or Wedge Workflow Section". In this post, I concentrated on getting rid of the "The VEX Code Section" by making a generic code that works entirely on the Parameter Interface allowing Artist to quickly set things up without dealing with Hard Coding things. However, at this moment every time a user adds a new attribute, he or she still has to manually add a parameter with the same name to match it, this is a later step to tackle things and automate it using python etc.
In the previous code, we were concentrating on creating the value for the attribute on each point or wedge:
string pt = itoa(@ptnum);
@val = ch("value" + pt);
However in this case we are looking at the other side, giving the user control to decide the name of the attribute itself. This is important as the points can be used for various things also besides copy stamping, the other advantage is that we can give common names to attributes that Houdini Copy Stamp or Instance already recognizes like "orient (vector4)" etc. This would mean the user doesn't even have to use the stamp function for simple things and can take full advantage of Houdini's powerful Instancing. To do that, just like last time I created Folder (Multiparm Block List) but this time I specifically renamed it to Attrib_List (This will be very important in the VEX Code as I will be referencing this integer parameter) and added three parameters to it:
globalVariable# - Toggle
type# - Ordered Menu (Contains a List of Options to select Int, Float, Vector or Strings)
Attrib_Name# - String
Till now these parameters serve no purpose as they are just a bunch of information, we need to store them in variables and use them to declare our attribute names. In this case ill press the "+" and create 5 attributes and their types.
Let's take a look at the VEX Code that will use this information:
//Lets store the number of attributes created in an integer
int cnt = chi("Attrib_List");
/*Now we need to store the names of the Attributes, to do this I am using an array to create a list.*/
string attrib[];
//Finally lets declare some variables to use later
int i, type, global;
/*The next step would be to create a Loop that will iterate on the "cnt" and append each name in every parameter to the array as well check to see if it is a global variable (One value for all points) and its type*/
//declare attribs
for(i = 0; i <= cnt; i++)
{
type = chi("type" + itoa(i));
global = chi("globalVariable" + itoa(i));
append(attrib, chs("Attrib_Name" + itoa(i)));
}
Now that we got our information stored kept we can use it to set attributes, their type and their value on each point.
Let's run a quick check to see if our array string attribute has the names stored correctly from the parameters.
s@temp = ATTRIB_ARRAY[index_number]
s@temp = attrib[0]
In the geometry spreadsheet, you should be able to see the value as you keep changing the index of the array.
Why was this useful and easier than hard coding the names and types?
This will now allow us to simply use all this information provided by users and declare values for custom-named attributes immediately allowing users to add and subtract attributes, change their type and use one value for all anytime without changing too much in the code. It will allow artistic freedom without the tedious work of taking care of and not breaking things.
How do we use this Information?
We can create a dictionary or library to reference depending on the situation or as in this case I have used If Else and Else If Conditions to keep things simple. Inside the If Else condition I used a setpointattrib to declare the name and type of the attribute, I did this because it was easy to control and the setpointattrib changes the attribute type depending on the variable it has been fed. That means that if I declare a variable called "val" and set it to "string" the setpointattrib will set my attribute also to string but if I change my type to "int" it will create my attribute as an integer.
int val = chi(attrib[i] + slidercnt);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
Let's take a look at the second half of the VEX Code:
//declare variables
int cnt = chi("Attrib_List");
string slidercnt = itoa(@ptnum);
string attrib[];
int i, type, global;
//declare attribs
for(i = 0; i <= cnt; i++)
{
type = chi("type" + itoa(i));
global = chi("globalVariable" + itoa(i));
append(attrib, chs("Attrib_Name" + itoa(i)));
//check if global variable toggle on
if(global == 0)
{
//check type
if(type == 0)
{
int val = chi(attrib[i] + slidercnt);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 1)
{
float val = ch(attrib[i] + slidercnt);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 2)
{
string val = chs(attrib[i] + slidercnt);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 3)
{
vector val = chv(attrib[i] + slidercnt);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
}
else
{
if(type == 0)
{
int val = chi(attrib[i]);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 1)
{
float val = chf(attrib[i]);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 2)
{
string val = chs(attrib[i]);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
else if(type == 3)
{
vector val = chv(attrib[i]);
setpointattrib(geoself(), attrib[i], @ptnum, val, "set");
}
}
}
Similar to Last time we set up a Parameter Interface that has the equivalent names to the Attrib_List names and now we have a fully working system that Artist can control without worrying about the VEX Code.