Anyone who as messed around with adding and removing vellum constraint with a custom setup will have noticed that vellum can be very sensitive to constraint changes with some disastrous consequences like this:
After a few fails attempts I striped it down to just working with a few wrangles no SOP solvers or inputs from a bunch of networks. There is nothing wrong with SOP solvers they are great but I wanted simplify the setup as much as possible for my own understanding of what is going on with vellum constraints. Below is the final result and if you want to skip the explanation the hip file link is at the bottom.
Starting is SOPs create a grid then a scatter node, set the scatter count to 1 point per frame and randomize the global seed with $FF. Now create a vellum configure grain sop and plug the scatter into the first input. Create two null for the two configure grain outputs we will use. Call on GEO and plug the first output into it, call the second one CON and plug the second output into it.
That is all we need from SOPs and at this point you might be asking why we need the constraints when there are no constraints set. The reason for that is the vellum source in DOPs will still add a constraint point for each point if we give it a constraint geo. That way there is no need to create the points from scratch in the DOPs.
Create a DOP network adding a vellum object, vellum source, and vellum solver. Hooking those up and setting the vellum source to continuous and pointing the sop path and the constraint sop path to GEO and CON Should give you a new point being added every frame with no constraint between them. At this point you can add some gravity and a ground plane as well, all together it should look something like this:
Now its time for the VEX. Create two geometry wrangles and before you do anything else in their data bindings tab change Geometry to ConstraintGeometry. Now that we are writing to the correct data set the first wrangle to run over detail. The wrangle will create a new constraint primitive every frame between the newly added point and the previously added point in the simulation, and because the vellum source is already adding a constraint point every frame all we have to do is get the right point numbers to add the primitive to. When adding the primitive and newprim group is added as well that we will need in the second wrangle:
/*Use the current frame to select the currently sourced point
and previously sourced point and add a primitive between them
the snipped is hard coded to start from point 0 with the frame
number starting at one.*/
int frame = int(@Frame);
if(frame > 1) //skip the first frame as there is only on point
pt1 = frame-1;
pt2 = frame-2;
int newprim = addprim(0, "polyline", pt1, pt2);
// store the new prim in a group
The second wrangle should be set to run over primitives and the group set to newprim so it only runs over the new primitive created that frame. All this node does is setup all the constraint attributes for the primitive. Play with the restlength value for some fun but don’t make it smaller that the pscale or you will get weird result due to unresolved intersections. Once the attribute are set the newprim group is set to 0 because the attribute only need to be set once on the primitive.
// set all the constraint attribs for the new constraint
@dampingratio = 0.01;
@restlength = 0.15;
@restlenghorig = 0.15;
@stiffness = 1000;
s@type = "stitch";
@group_glue = 1;
//important: remove the prim from the newprim group
@group_newprim = 0;
We are almost there! The constraints should only be set once per frame lucky there is a node for that. Drop down a gas intermittent solve node and thick the check box that says Only Once Per Timestep and connect the wrangles together and connect the output of the second wrangle to the
gas intermittent solve. To make sure the wrangles are the only thing affected by the Intermittent solve drop down a merge node and plug the source stream into the merge and then the intermittent solve.
And that is it hopefully everything works and does not explode 🙂
Special thanks to Julian Johnson for helping problem solve this.