Vellum and 'growing' constraints in the dop network:
I had this idea to grow strings, and for whatever reason it led me to some deep dive into DOPs to poke at the inner workings of vellum. As this was a bit fiddly, I’ve decided to document it here for later reference, and maybe it will be interesting for someone else one day.
Here’s how the end result can look:
Some noisy filaments - what's new?
At a glance this is nothing particularly groundbreaking and I am sure that there are many approaches to get something like this for a specific shot or a specific use case, with various trade-offs etc.
For this, though, I really ended up getting to grips with vellum, handling state of specific grains and building new constraints dynamically etc. so it was a great learning experience. The part I was determined to solve was to have grains dynamically and organically ‘grow’ constraints frame-by-frame. I think I imagined there would be lots of other cool things I could do when I cracked that technique but in all honesty once it was done my attention dropped right off and I have only been back to tinker a couple of times. Nevertheless, let’s get into the details.
Instead of breaking down the scene shown, I will build a simplified version from the ground up to show it as clearly as possible.
Simple vellum grains:
Super simple flat cylinder of grains, gravity, floor plane, easy peasy, right?
The only extra thing is that we create a random 0-1 value per grain called ‘startpt’ and a group called ‘gluepts’ which starts with one point in it. Can be random but I chose point 1.
Inside the solver:
Add Your Heading Text Here
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
The complexity is all inside the solver. If you have ever delved inside the vellum solver and its interior, you will be aware it is quite a complex system, but once you get the hang of reading it things make more sense.
What we want to do is the following:
- Control the leading point(s) so we can move them around
- Add very nearby points to a group
- Build a vellum constraint per new point to connect the grain to its neighbour like a string
- We need to limit max neighbours/constraints to a low number to force string-like forms to emerge – that is part of the trick
- If we balance the various values, we should be able to get strings growing between points and moving around behind the lead point(s)
B:
A:
Important point, geometry wrangles inside DOPs need to be set to operate on ConstraintGeometry instead of the typical Geometry (there are multiple geo streams in vellum nodes – more on that later!
This wrangle iterates over primitives (the constraints) and gets the points, adding them to the “gluepts” group. This ensures we always have a way to operate on all the constraint points.
Note – vellum has a copy of the points in the Geometry, and also in the constraints geo stream. I think it is used to map back and forth between the two, but it can sometimes get a bit confusing, so remember this!
B:
This is where some of the confusion happened for me. It struck me that I was wanting to do things with geometry and constraints at the same time, and how exactly do you do that in DOPs? There may be a neater way, but my research and experimentation lead me to discover the SOP Solver – Special Edition.
There is a specially setup SOP Solver in the tab menu called “SOP Solver (Constraint Geometry)” which I suppose means it was not all that hidden knowledge, but it did take me a minute to find it.
This SOP Solver lets you get an input of Geometry and ConstraintGeometry in the same context, and output them both after doing whatever you do.
For the most fiddly of vellum shenanigans, this is godsend! It is not exactly fast but it lets you do the thing you are trying to do which sometimes is enough.
When this was discovered, the actual network I needed was not huge or really complex at all.
It just takes in the groups from the constraint points which are set in the other DOP nodes and passes that to the Geometry points on the other stream.
C:
Here was a slight headache. Lots of head-scratching and frustration was caused by a bug/feature of vellum. Or I was doing egregious and evil things which were against the rules, one of the two. Inside DOPs debugging can be a bit fiddly as things often go stale or don’t update quite as you expect. Combine that with lack of understanding and actual bugs and it can be a hard time.
I was losing data or not seeing changes I expected, and it turned out (after much delving) that this was the issue:
For whatever reason, this node helpfully erases anything yo may have added to the points in the ConstraintGeometry stream. I guess it is not usually the set of points which are used for normal operations, so I can understand it, but it just so happened that I needed that data for my strange experiment. So I went and found where the attributes needed to be copied in and did so.
If anyone needs to, you an do this inside vellumconstraints node, there is a SOP Solver, and inside there the new constraint geo get passed out – you can intercept that and copy over the stuff you care about. Warning – make sure you understand how/why the geo might be different than typical geo in case of mismatches of indices etc. though in this case we are copying over point data so everything matches index wise. (Constraint prims are often shuffled due to graph coloring so watch out!)
Evidence of the hacking:
Once all this is done, the data can get where it needs to go and we see something happening:
The breakdown end result:
So, as per the goals, we want to drive the motion of some leading points, and grow the constraints organically, and let the sim make fun stuff happen with the trailing strings. This is of course as broad a field of opportunities as one might wish for so I won’t presume to prescribe what to do, but I can show the breakdown example.
There is a kind of state, controlled by those groups, and this is a bit how POPs work in general, so melding vellum and POPS is quite interesting. The lead point is attracted to a goal location, and the growing strings impart chaos to proceedings. Here they have a lifting force which fades off with height which is why there’s a yo-yo bouncing to their motion, but you could control this much better in a proper case.
Conclusion:
I want to come back to this to make it better as I am sure I was breaking some key principles somewhere with these hacks I had to do. But it was another lesson in not giving up, and finding a way to reach a goal. This kind of project can really help you get deeper into an area and understand how complex systems like vellum are working lower level, and sometimes sparks ideas for cool new projects.
Things I’d like to fix or improve:
- Make it all a bit more modular and reusable (not 100% sure how but would be nice!)
- Edge cases exist where errors in the groups cause the constraint to form a ring (SIMD stuff/race conditions most likely) and I would like to fix that
- With my newer comfort with detail wrangles, maybe I can do some of the constraint growth in a wrangle and that way ensure race conditions/parallelism are not an issue
- Try to move the logic into either Geometry or ConstraintGeometry and not both, I feel this is a mistake and there’s probably a way to work around it.