Houdini - Constraint Networks Basics
A constraint is a single primitive polyline connecting two points. Anything not this will be ignored.
The points tell Houdini what they constrain through a @name
attribute. The bottom point, in this case, constrains something called “thing”.
If @name
is an empty string [the top point], then it is a “world contraint” e.g. it’s pinned to wherever its position happen to be.
IMPORTANT The
@name
attribute must exist or the constraint will not be created. If it’s empty, we must still declares@name = ""
.
The polyline between them has an attribute @constraint_name
which is a string (in this case “con”).
This is what must exist in the Spreadsheet at the very least:
All this gets fed and wired inside a DOP like so:
The Constraint Network’s SOP Path
is set to the incoming object. Then the logic goes something like this.
-
I’ve got 2 points. One point has
@name
on it. Find something on my left that matches@name
. -
There is a polyline connecting these 2 points with
@constraint_name
. Find a relationship on my right whoseData Name
matches@constraint_name
.
We end up with this:
Centroids
Houdini automatically “digs its way” to a centroid. In our example, the point just happens to be at the centroid of the sphere.
If the sphere is away from the point, Houdini builds an additional line from that point, to the centroid of the object.
Rest Length
All constraint relationships (soft, hard, spring, etc.) have a “Rest Length” paramater. This is the length the constraint – the polyline between two points – attempts to maintain when a simulation runs.
Here are two examples.
The moment the sim starts, the balls are “yanked up” because the constraints (red Hard, yellow Spring) are “snapping” to their rest lengths [above it’s 1, below is 2].
If we don’t want this “snapping”, we need to:
-
Get the length of the polyline before it enters the DOP.
-
Store the rest length on the polyline and have the Constraint Relationship use it.
Luckily, Houdini already calculates the length of primitives and stores it in an intrinsic. So, in a Wrangle running over primitives, we simply need to write:
@restlength = primintrinsic(0, "measuredperimeter", @primnum);
Checking the Primitive Spreadsheet, we now have both a @constraint_name
and a @restlength
.
IMPORTANT: Inside the DOP, make sure the Constraint Relationships have their Rest Length set to 1. Any other value will override @restlength
.
Constraint Networks and Packed Primitives
If the incoming RBD object is a packed primitive, setting the node to match @name
wouldn’t make much sense since we need a way for the constraint network to find the actual pieces inside the packed primitive.
To solve this, we simply give each packed primitive piece a @name
attribute.
Assemble
and Copy to Points
can both output packed primitives.
Assemble
gives us @name
for free. With Copy to Points
[right tree below], we first create @name
on the points, which automatically gets transfered to the packed primitives after the Copy.
All three networks produce this same result: