ConstraintNetworks

From cgwiki

Constraint Networks

Overview

Download scene: File:constraint_networks_end_result.hipnc

Houdini allows you to build rigid body constraints with polylines. The lines represent the constraints, and the ends are attached to the rigid body objects by name matching. If no name matches, then they get attached to the world.

Constraint networks can be built with 'connect adjacent pieces' and a few wrangles, but more interesting results can be had by procedurally modelling the constraint edges, offsetting the constraint ends, and mixing multiple constraint types.

Simple approach with connect adjacent pieces

Constraint network diagram 01.jpg

From skimming the docs and looking at other peoples setups, here's what we need to do. In the above diagram the packed rbd objects are blue, the constraint polylines are green, and the points of the polylines are red:

  • packed geo have @name
  • points of the polylines have a @name that matches to the packed geo they'll be linked to
  • polyline prims have @constraint_name, used to match it to the constraint network type in dops
  • polyline prims have @restlength to say how long they should try and be


Constraint network capture 01.gif

The above gif shows how I've built constraint networks thus far. Connect adjacent pieces (which creates the @name attrib on the points), adjust the distance threshold and min connections to wire the points together, set @constraint_name in a primitive wrangle to 'con' (nice easy name to remember), and create the constraint network and hard constraint relationship dop to point to 'con' as a name, should see the constraints appear. How does it sim?

Constraint network capture 02.gif

What? Oh, the prims need a @restlength attribute. Without it the constraints assume they should be of 0 length. Inserting a 'convert line' sop before the prim wrangle will add a restlength for us. Now when we sim, we get this:

Constraint network capture 03.gif

Nothing happens. The constraint lengths are maintained, there's no other forces in the scene, so it all looks motionless. Good, but boring. Lets add some gravity.

Constraint network capture 04.gif

Whoops. We better lock down one of the ends of this chain.

Lock constraints to the world

If you look at the prim wrangle, and inspect the geo spreadsheet in points mode, you can see that the points have a @name attribute, which matches to the names of the packed geo. That's how the constraint network knows how to connect things; it matches on name. If @name is an empty string, that constraint becomes pinned to the world. In a wrangle here I set the group to 0 (ie grab the first point), and in a wrangle type @name="";. Let's see what happens:

Constraint network capture 05.gif

Sure enough that constraint is pinned, and the chain swings around that point. Unfortunately the first cube falls to the abyss. Why? Well, now none of the points have a @name that is 'piece0', therefore its an unconstrained object, and falls to its death. How to fix?

NOTE: In 16.0 and earlier, if @name on the polyline point couldn't find any packed geometry with the same name, it would also treat it as a world constraint. In 16.5 this is no longer the case, it only works if @name is an empty string. A lot of earlier setups (mine included) would use a @name like 'world', these setups will need to be updated!

Create an anchor

Anchor point 010a.gif

This is what we wanna build; a new little mini line near the first box, one end has @name of 'piece0' so its pinned to that box, the other has an empty name so its pinned to the world.

Coming up with a clean procedural way to do this isn't as intuitive as I'd expect. My current method is as follows in gif form (it's a long one, 2m10s, look at the time indicator in the lower right to know when it'll loop) :

Anchor point 01.gif

Those steps are:

  • remove the old pin-to-world point wrangle, we don't need it
  • isolate the packed geo we want to pin with a blast node
  • use an add sop to convert it back into a point
  • transform a copy of the point away a little bit, and merge it
  • add sop to convert those 2 points into a line
  • convert line sop to get @restlength
  • prim wrangle to set s@constraint_name='con'
  • point wrangle to set one of those points to have @name=
  • merge with the original constraint lines
  • sim, make merry

Constraint type position vs all

Lets have another look at the setup so far; polylines between the objects, an extra little one for the first object pinned to the world, it all does its rbd constrain dance:

Constraint type 01.gif

These are all hard constraints. Well if they're hard, why are they rotating? Especially the first object that should be pinned to the world? The reason is the default constraint behaviour is to pin position, not rotation. To tell it to do both you add a extra prim attribute to the polylines, @constraint_type, and set it to 'all'. Here's what happens:

Constraint type 02.gif

The constraints now work like rigid wires, and lock all the rotation down. Sometimes you'll want one or the other, or maybe even a combo of the two, its handy to know you can do this. It also supports only constraining rotation (by setting @constraint_type to 'rotation'), Julian Johnson has some good examples for this on odforce: http://forums.odforce.net/topic/30476-constraint-network-constraint_type-rotation/

More interesting constraint networks

Again, lets look at the sim, pay attention to how the constraints lines move in relation to the boxes:

Better constraints 01.gif

While the sim is working, the constraints move through the boxes like they weren't there; if anything its as if the boxes are constrained to the points, which doesn't feel quite right. Instead, compare to this setup:

Better constraints 02.gif

Ah, the constraint ends are now sitting on the faces of the boxes, it all looks a little more believable. How has this witchcraft been achieved?

With some tricky procedural modelling. Here's the two constraint setups:

Better constraints 03.gif

Simple enough; while the original looks like an unbroken line, the new setup is just little single edges between the blocks. When that is fed into the constraint network, Houdini just deals with it. This is more powerful than it seems at first glance. If constraints don't need to go through the centroids of the packed geo, you can model constraints like you might do in real life, and it'll behave as expected. Eg, shifting the constraints to the lower front corners of the boxes:

Better constraints 04.gif

Or more interesting, using a 'copy and transform' to make multiple copies of the constraints. Note that if you specify enough links, the setup does what you expct and can no longer rotate, even with leaving @constraint_type in its default 'position' method:

Better constraints 05.gif

Constructing those interesting networks

This is where your procedural modelling tricks come in handy. You've been learning all those tricks right, and not just diving into dops headfirst? I hope so.

It's all a bit more complicated than it appears at first glance, but the payoff is you can feed in fairly arbitrary packed geo setups, and get what you expect.

Full disclosure; while writing this tutorial I've rebuilt this about 4 times in completely different ways. I still reckon there's an easier way, but this'll do for now.

5th time's a charm! I was definitely overthinking it in the previous version (which is linked at the top of this page), the following method is much cleaner and easier. Basically, use a primitive sop to scale each polyline around its centroid:

Constraint network build v5.gif

  1. Connect adjacent pieces, set max connections to 2, and search radius high enough to make edges (2 in this case)
  2. Fuse in unique mode to split the verticies so each prim is unique
  3. primitive sop to scale each prim down to the right size
  4. transform to move the pivots to the corner
  5. copy and transform sop to make a matching prim on the other corner
  6. convert line sop to get restlength

Swapping hard constraints for spring constraints

Download scene: File:constraint_networks_end_result.hipnc

Here's where all the hard work starts to pay off. In dops, you can just swap out the hard constraint node for a spring constraint. Change the name its looking for, blam, you got springs:

Spring constraint 01.gif

Well, almost. I forgot to set the world constraint to use the same 'con' name, but more importantly, the default spring strength of 1 is way too low. Here's me going from 1, to 1000, to 10000, to 100000, only then do the springs start to behave:

Spring constraint 02.gif

The mistake above hints at what you can do next, make some constraints have the name 'hard', the rest 'spring'. In dops set the hard and spring constraint nodes to look for those names, merge the two nodes, and feed that to the constraint relationship node:

Spring constraint 03.gif

Constrain a sheet of grids

Grid springs flipbook.gif

Download scene: File:rbd_grid_springs.hip

Same workflow as above, but in grid form.

  1. Assemble and pack your geo
  2. Connect adjacent pieces
  3. Convert line
  4. Fuse in unique mode so each little segment is isolated
  5. Primitive sop! As much as I dislike it, its perfect here for scaling the polylines down around their individual centroids
  6. Set attrs, etc

Further reading


On to part 2, where we use animated constraints to drive rbd shapes, and ultimately make some walking creatures: ConstraintNetworks2