CVEX Wrangle & VOP Nodes

Guest Author: Jonathan Granskog

It’s no secret a great deal of the fancy Houdini stuff happens inside those crazy CVEX Wrangle and VOP nodes. However, this is true for many applications that have the ability to script effects or manipulate geometry, etc. Usually, out of the box parameter settings or presets won’t cut it. In most cases you need to dive in and get your hands a bit dirty. These things don’t come for free people!

If you’re coming from another application, this might be a bit overwhelming. But like many things in life, we all need to start somewhere. For those of you coming from Cinema 4D, you can think of VOPS as just Xpresso and the CVEX Wrangle nodes as Mograph Python Effectors. Luckily for us we have talented Houdini artist Jonathan Granskog (@JonathanGranskg) to give us some examples on how we can make use of these nodes that can leap a tall building in a single bound1.

Take it away Jonathan!

Geometry Creation

So what do you do when you have a complex algorithm that you want to use to create geometry or maybe you want to procedurally fill holes in meshes? Houdini has these very nifty functions that you can use in all your CVEX Wrangle/VOP nodes (this includes the Volume VOP! I’ve used it to create points in voxel centers):

addprim()

addpoint()

addvertex()

and their opposites:

removeprim()

removepoint()

There is no removevertex() function because removeprim() and removepoint() will delete their connected vertices behind the scenes. One very important thing to keep in mind is that all the geometry is created after the node has run through all of your geometry components. Here’s a simple example of a function that creates a triangle and adds a color attribute and sets it for the points. Notice the order of how the geometry is created.

int draw_triangle(vector v1, v2, v3) {
  //create geometry
  int first = addpoint(geoself(), v1);
  int second = addpoint(geoself(), v2);
  int third = addpoint(geoself(), v3);
  int prim = addprim(geoself(), "poly");
  addvertex(geoself(), prim, first);
  addvertex(geoself(), prim, second);
  addvertex(geoself(), prim, third);

  //setattributes
  addattrib(geoself(), "point", "Cd", {0,0,0});
  setpointattrib(geoself(), "Cd", first, {1,0,0}, "set");
  setpointattrib(geoself(), "Cd", second, {0,1,0}, "set");
  setpointattrib(geoself(), "Cd", third, {0,0,1}, "set");

  return prim;
}

draw_triangle(set(0,0,0), set(1,0,0), set(0,1,0));

First we create the points of the corners of the triangle and afterwards we create a primitive that has no connection to the points so far. That’s where the vertices come in, they connect the primitive to the points. The order in which you add the points to the primitive, via the vertices, is important because it determines the normal direction of the primitive.

If you don’t want a closed polygon you can use polyline instead of poly when calling addprim(). And if you want to copy a point, including its attribute values and groups, you can use a point number instead of a vector value when calling addpoint().

One small thing to notice is that I also have the Attribute Wrangle node set to run over Detail (only once) meaning that it will like it says only run once. This is a very simple way to create geometry from scratch in VEX and I like to think of it as being similar to something like Processing in a way where you can create everything with code. The Null node is only there because the Attribute Wrangle/VOP needs an input.

Here’s something more advanced:

//tri-strip creation code
int triangles = 10;

float base = 1.0;
float height = 1.0;

int pts[] = {0,0,0}; //array to store ptnums

float x = 0, y = 0, z = 0;
int k = 0;

//fist tow points will not create a triangle
pts[k] = addpoint(geoself(), set(x,y,z));

x += height;
z += base/2;
k++;

pts[k] = addpoint(geoself(), set(x,y,z));

int prim;
//create the points, a new triangle is created each loop
for (int i=0; i < triangles; i++) {
  z += base/2;
  x += (x > 0) ? -height : height;
  k++;
  k %= 3;
  pts[k] = addpoint(geoself(), set(x,y,z));
  prim = addprim(geoself(), "poly");
  // we need to switch the vertex creation order
  // to keep normal pointing in the same direction
  if (i % 2 == 0) {
    addvertex(geoself(), prim, pts[0]);
    addvertex(geoself(), prim, pts[1]);
    addvertex(geoself(), prim, pts[2]);
  } else {
    addvertex(geoself(), prim, pts[2]);
    addvertex(geoself(), prim, pts[1]);
    addvertex(geoself(), prim, pts[0]);
  }
}

Using the geoself() function is very important when you’re creating geometry because it gives you a reference to the current geometry.

Removing points or primitives works exactly in the same way. With the removeprim() function you can choose if you want to delete all the connected points as well.

One simple example where I’ve used removeprim() was when I wanted to create a bunch of small debris particles for a destruction simulation. I fractured a box and using a Foreach node centered each of them at the origin.

Then using a stringedit() I modified the name attribute from piece* to *, then there were only numbers left in the attribute, but still as strings! Then I could use atoi() to convert the string to an integer inside my Attribute Wrangle and compare it to the current frame to only keep one piece. Then you can cache these out and copy them to particles and stamp a random frame onto a Timeshift to copy random pieces to your particles.

if (atoi(@name) != @Frame - 1) {
  removeprim(geoself(), @prim, 1);
}

 

Here is another example of something you can easily accomplish by creating your own geometry in VEX, a simple copy of the popular Plexus plug-in in Adobe After Effects. All it does is check whether nearby points are within a certain distance from the current point and if there are any points close enough it will create a polyline between the two points.

 

float pc_radius = 100;
int pc_neighbors = 25;

float max_dist = 0.2;

int handle = pcopen(0, "P", pc_radius, pc_neighbors);
int pt_found;
vector pt_pos;

while (pciterate(handle)) {
  pcimport(handle, "point.number", pt_found);

  if (pt_found == @ptnum) continue;

  pcimport(handle, "P", pt_pos);
  float dist = length(pt_pos - @P);

  if (dist < max_dist) {
    int prim = addprim(geoself(), "polyline");
    addvertex(geoself(), prim, pt_found);
    addvertex(geoself(), prim, @ptnum);
  }
}
Plexus Effect
Plexus Effect

 

PS. Here’s a helpful link with some more advanced functions you can use to access other components of your geometry if for example, you only have a primitive number.

http://www.sidefx.com/docs/houdini15.0/vex/geometry

And of course, if you prefer VOPs everything works the same in VOPs. Just look for the corresponding nodes, they have exactly the same names as the functions.

Grab Houdini scene file here: Houdini Scene File

Reference Links:

http://www.sidefx.com/docs/houdini14.0/vex/functions/addvertex

http://www.sidefx.com/docs/houdini14.0/vex/functions/addpoint

http://www.sidefx.com/docs/houdini14.0/vex/functions/addprim

http://www.sidefx.com/docs/houdini14.0/vex/functions/geoself

http://www.sidefx.com/docs/houdini14.0/vex/functions/removepoint

http://www.sidefx.com/docs/houdini14.0/vex/functions/removeprim


 

1. I’m a Spider-Man guy myself.

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.