Today at work I was loading some really heavy geometry into Houdini that needed FX added to it. Its came in from Maya with thousands of primitive groups for different numbered parts of the geometry. If you tried it before you will know that unpacking heavy geometry with a lot of groups is any easy way to fill up your ram. In this cache filling 64GB and the cracking Houdini after filling the swap as well.

I really wanted to keep the incoming part numbers because so parted where linked to other parts with different names and not all part where connected with connectivity so I quick Connectivity SOP trick wouldn’t do the job. Luckily I could access the groups while the geometry was still packed primitives so the solution was to convert the groups to a single numbered attribute and get rid of the groups before unpacking or converting to full Houdini geometry. So that is the back story and here is my solution.

string groups[] = detailintrinsic(0, "primitivegroups");

In vex you can use the Detail Intrinsic function to write all the primitive groups to a string array, you can do the same point edge and vertex groups. So that’s step one, pretty easy right? The is were it get a little more tricky. The groups are named something like:

  • asset_foo_0001_bar
  • asset_foo_0002bar
  • asset_bar_002_blabla
  • asset_bar_0003_blabla

Combining all the foo and bar groups is easy using a group combine SOP.

But what takes a bit more thinking is extracting the numbers so you have an attribute that reads like this:

The bad naming above with different padding and some numbers not having underscores was deliberate as that is what I was dealing with. VEX has a couple of functions to handle string manipulation and the really interesting ones for this problem are the re functions, there are a couple re_find(), re_match() and a few other ones. If you have never seen these before or have and wondered what they are for, well they are what is called regular expressions or regex. Regex is a sequence of characters that define a search patterns. These are usually use by string searching algorithms like in this case in VEX in Houdini.

To demonstrate I will how it works lets apply a re_find() to the first group string “asset_foo_0001_bar”. The pattern \d finds all the digits in a string while \D finds all the non digit characters.

s@num = re_find(r"\d","asset_foo_0001_bar")
returns = 0
s@numAll = re_findall(r"\d","asset_foo_0001_bar");
returns = [0,0,0,1]

If the above code makes sense lets look at searching for 4 numbers in a row. To find that the pattern is \d{4}.

s@num = re_find(r"\d{4}","asset_foo_0001_bar")
returns = 0001

You can get a lot more advanced with these patterns but all I will add is \d{3,6} which means find strings of numbers between 3 or 6 which compensated for one of my groups having less padding than the others. The lack of an underscore in string two doesn’t even matter with this method so that is taken cares of as well.

With step two sorted step 3 will be easy, all we need to do is use a foreach loop to go through the group array and find the group numbers for primitives that belong to that group and write that to an attribute. The code for that run over primitives with a list of primitive groups looks like this.

//convert numbered groups to a numbered attribute
string groups[] = detailintrinsic(0, "primitivegroups");
int prim = @primnum;
string elemnum;

foreach(string i; groups)
{
    //if the current primitive is in group i
    if(inprimgroup(0,i,prim) == 1)
    {
        elemnum = re_find(r"\d{3,6}",i);
    }
}
s@number = elemnum;

This is just scratching the surface of what you can do with regular expressions, its a great way of seaching for values in a sting when you are not 100% sure the string pattern is all was the same. There are many more patterns you can make and online help like regex101.com makes it super easy to test and debug.

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *