Sim a forest of l-system trees
Download hip: File:vellum_forest_lsystems.hip
A thing I found surprisingly tricky was to take the default lsystem tree and convert it to vellum. It'd flop about, fall apart, no matter what I tried. I got a better feel for vellum after watching the John Lynch masterclass a few times, taking notes (see below).
So, here's the summary:
- create a lsystem
- append a vellum configure hair. This was my first aha moment: when simulating wire/skeletal things, use vellum configure hair, not cloth!
- append a solver, watch it fall to its doom. Better pin the root down.
- insert a group sop after the lsystem, set group type to 'points', base group 0, ie, the first point
- on vellum configure hair, set pin points to group1
- sim now. floppy tree.
- on vellum configure hair, the bend stiffness is too low. set it to 1, sim. Less floppy. 10? Little less floppy. 100? Hmm, not much change. 1000? 10000? 1000000?
- Next aha moment: If you do powers-of-ten jumps in stiffness but don't see any change the higher you go, the constraint iterations are too low!
- Jump to the solver, set constraint iterations from 100 to 1000, sim. Aha! Stable tree!
- Dive inside the solver, connect a popwind before the force output null, wind strength 0.1 on x, noise amplitude 0.25. Nice subtle rustling.
That's one simple tree. Lets see what we can do to push this a bit and learn some more.
- On the lsystem increase the generations from 7 to 8, which grows an extra set of twigs
- Sim again, the tree will slump. More iterations?
- This time we'll use substeps. Set substeps to 2, sim again, the tree is stable. Can play with the ratio of substeps to constraint iterations, remember 1 substeps with 100 constraint iterations is roughly the same as 2 substeps at 50 iterations, but will solve more accurately (and be a little slower).
- can disable collisions to speed things up a little, don't need them for now
The hip does more stuff (colliders, breakable pin constraints, plasticity, scale to a forest etc), but recognizing wireframe things need hair constraints rather than cloth, and how to identify when the number of constraint iterations are too low, were the important lessons here.
Probably worth pointing out what the second vellum configure node is for. In the first stage I pinned using the existing vellum configure hair node. When done this way the pins will inherit the same stiffness values as the rest of the hair. To control stiffness and breaking, I removed the pins, made a new vellum constraints node, mode 'pin to target', and gave it the root group from before.
By default this is a permanent pin, which has almost no controls. By swapping the mode from 'permanent' to 'soft', the strength can be controlled and breakable can be enabled. To work out the breaking threshold I just hit a single tree with the sphere, gradually increasing the threshold until it looked like it snapped at the right time.
Download hip: File:vellum_footwork.hipnc
Watched a few Entagma and Sidefx vids, saw a fun walking setup on Twitter, had a go myself. Knowing that vellum happily supports multiple constraints doing different things, this has:
- a cloth constraint to pin to the animated feet and animated head
- a pressure constraint to keep the mesh inflated a bit
- a strut constraint for internal strength
- a strut constraint with inverted normals to pin the overall mesh to itself so arms are pinned to legs etc
There's a few delta mush nodes here and there to keep it smooth, and the final connectivity sop and split was because only after I simmed did I notice the eyes had fallen out of the head and rolled around on the floor, those 2 nodes tag and delete them.
Vellum hair headbang
Download hip: File:vellum_hair_headbang.hip
Simple take on vellum for a hairstyle that needs to retain its shape when driven by animation. This uses a single vellum hair constraint with bend stiffness of 1,000,000. I use a resample sop to get @curveu for the guides, and create a group of @curveu<0.2, and define that as a pin-to-animation group on the hair constraint.
A important part of this setup is how to have the hair follow the head.
How to NOT constrain the hair to the head - Attach to Geometry
Like most people I first left the groom static, had the animated head geo, and used a 'attach to geometry' to bind one to the other. This is fine for binding a vellum flag to a moving pole, or other simple effects, but for hair the hair acts as if its on a frictionless 360 hinge at the root; it has no sense of maintaining its orientation relative to the head, the system just collapses into a heap.
The right way - Guide Deform
What you really want to do is make the guides inherit the scalp animation pre-sim, then let vellum layer on the jiggly sim parts of the motion afterwards. You can do this with a guide deform. Give it the hair, the static head, the animated head, the guides will bind themselves onto the scalp in a rigid way. Now that the guides are doing the right thing, you can use the 'pin to animation' controls so that the roots are locked, but the rest can slop and slide around.
Possibly more interesting here is how myself and the fine students at ALA are doing groom; its all in sops, no hybrid hair obj things. We think this is easier to read and work with, you may think otherwise.
Also note the absence of guide groom nodes; I've watched a few demos that make it seem amazing, but you only have to play with it for a few minutes if you're familiar with Houdini to realize its alarmingly non procedural. It's the edit sop on steroids, and all that that implies. Great for fast tweaking, but doesn't fit well into a procedural workflow. I totally get that there'll be cases where you have no choice but to work that way, but I'll be avoiding it as much as possible.
But hey, don't listen to me, watch this amazing demo by Igor Velichko that proves I know nothing at all. :) https://vimeo.com/331103963
Softbody tet anim using force
Download hip: File:vellum_tet_animation.hip
Similar to one of the rbd tricks earlier, a rest and deforming copy of the object are read into dops. Each point on the sim reads its matching rest and deforming point, one is subtracted from the other to form a vector, that vector is used as a @force.
I'm surprised how well and how fast this works, and that it really moves through space; other attempts so far would just wobble and flop about at the origin, but never actually move forward. Lots of gross fleshy things to be done with this setup!
All the setup of the tets, solid embed etc were shamelessly stolen from the shelf 'vellum tet' preset'. :)
Download hip: File:vellum_grain_cookie_sticky.hip
A question from a patreon supporter landed at the right time, I'd been doing a lot of vellum the past few weeks, so had ideas of how to tackle this question. Look at the John Lynch masterclass from about 2hrs51m to see the basis of this. Usual disclaimers, probably better methods, not tested in production, but I think it's a fun little example.
The cookie shape is booleaned and connectivity'd so each piece can be identified. It's then converted to vellum grains, but because the vellum grains sop doesn't keep the connectivity information, I run this in a for loop to restore it.
There's then 2 glue constraints and a pin-to-target constraint. The first glue is internally per piece, note that the group types are all set to 'point', and the cluster field is enabled. The second glue is similar, but I explicitly limit the constraints to act on the firsts piece, and to only try and find targets in the second piece. In other words, its glue across the gap of the break.
The pin to target is so the grains will follow the pieces when they're animated, but here I want pretty much all the grains to follow, with just a thin layer of grains at the gap to be allowed to flow freely. Rather than select these by hand, I grab the boolean cutting plane, colour it black, colour the grains white, and use an attrib transfer with a short distance and a little blur so that most of the grains are white, and fade to black over the cut. I can then make a group from colour, and use that group for the pin to target constraint. Note that the pin group type also needs to be in 'point' mode, grains expects points for all the things (obviously), but vellum by default uses prim groups.
The pieces are animated, and end in a TARGET null. The vellum solver is told to use that as the anim target (on the advanced tab), with 5 substeps.
To get the sticky/stretchy behavior involved some quick wedging of stiffness, damping, breakable and plastic values for the constraints. Having done this a lot the past week I'm getting better at dialing in values, and predicting what needs to happen. Low stiffness allows more give and stretch. Setting plasticity values allows for less elastic rubbery behavior and more sag/slump. Raising damping can help reduce vibrating grains, but can introduce slowmotion dragging as the constraints eventually seek their target. Breakable constraint values are similar to finding stiffness, you want to find the value where everything breaks, then where nothing breaks, then find that middle value so things juuuust start to pull apart, but not too much.
Post sim is an attempt to apply this motion back onto the original geo. Again a for loop is used to treat each piece separately, which has been subdivided and uv'd.
Download hip: File:vellum_walker.hip
Sasa Budimir is brilliant. He frequently posts lovely things that show pairing a talented animators' sense of timing and style with the power of Houdini is an unbeatable combination. When he posted an amazing hairball creature, I felt compelled to have a go.
The vellum side is pretty minimal, just hair constraints with pin-to-target on feet, knees, hips. The stuff that took some head scratching was how to procedurally generate the animated foot locations. It's a bodge of truncs and lerps and chramps, but does the job. Sasa was kind enough to allow me to post this quick cover version of his way more detailed and character filled post, thanks Sasa!
Here's a better take where the movement is driven by distance traveled rather than @Time, so it supports stopping and starting:
Download hip: File:vellum_walker_v02.hip
Foot planting setup
This foot planting setup is based off Sasa's gif, but I think the core approach is a little different. It starts the same, a point is animated along a path, then a set of feet points are generated at origin, that set of feet is copy-to-points'd to the animated point so they slide along the path.
I trail the feet points for the length of the sequence, and timeshift to the last frame. Then an add sop converts these trails to lines (oh, just remembered I could do this in the trail sop directly, idiot).
Those trails are lifted a bit, then ray'd onto the terrain. Now we have a terrain-avoiding path per foot.
And now the tricky bit, the walk cycle generation. I decide the number of foot steps I want, say 15. Multiply the timing information from the original point by 15, so that each point has a timer that is 0 at the start of the sequence, 15 at the end, lets call this @timer.
Now split that into the numbers before and after the decimal point; before is t = trunc(@timer),after is f = frac(@timer). I could reconstruct the original @timer by going t+f, but before doing that, we'll put f through a chramp.
Why? Because now we have a variable that cycles 0 to 1 on each step. If left in a default ramp it will smoothly and linearly go from the start of the step to the end, but with some ramp shaping I can make the foot hold still for a bit, move forward quickly, hold at the end.
Now I add t and f again, divide by the number of steps, so these values go 0 to 1 again, and use that to lookup the matching location on the path with primuv.
Hopefully this gif makes it clearer:
To get the foot to lift and drop, I use f in a chramp again, start it low, go high, then low again, and add that to @P.y.
This works, but all the feet move at the same time. By adding a little per-foot offset to the @timer value, eg @timer += @ptnum*ch('foot_offset');, you get staggered feet timing.
Make a copy of all the feet, lift them a bit, make another copy, lift and scale together, you've made knees and hips. Join those points together, there's legs.
There's still issues with all this, if I increase the number of feet the whole system stretches too long, it bunches up at the end, it's hard to get the exact timing I want, buuuut... it sorta does what I set out to do. Makes you really appreciate Sasa's work and how much character he gets in his creatures, he's putting way more care into them than I am!
John Lynch Advanced Vellum workflows
Just some scribbling while I watch the masterclass for the 5th time, I keep forgetting the important bits...
Nothing revelatory yet from my part, this is all just bullet points from John's presentation! I'll do another sweep at some point to add gifs and stuff. John has made a collection of hips to go with his presentation, you can find it here: https://www.sidefx.com/tutorials/advanced-vellum-workflows-h17-masterclass/
- 1st vs second order integration. 1st is what old grains used, vellum default is second. pbd projects where the particle will go based on its velocity, then takes short steps moving towards that goal until its ‘solved’, or you run out of iterations. 1st order integration doesn’t take into account curved motion, ie constraints, so often inaccurately predicts where the particle should go. This means 2 things, it requires more iterations to get to a good result, but its also constantly losing precision, losing energy, getting less accurate results that take more time.
- second order does a more accurate prediction of where the particle should go, meaning both less solver iterations required, and the result is more accurate. The example is a swinging rope with only gravity; 1st order loses energy and stretches, 2nd order suffers that much less.
- This can be visualised by peeking at @Ppre (P predicted), compare results.
- 5 substeps is recommended, make sure to lower constraint iterations to compensate, otherwise you’re needlessly oversolving
- in real world sims, turn on wind drag (default 0.1)
- xpbd /2nd order’s kryptonite is collisions; without being taken care of it does a bad job of predicting where things will go post collision, and can look like bouncing/too much energy. Max acceleration can fix this, 100 is the default and possibly too high, lower to 25.
- Way to split apart constraints into batches that won’t directly affect each other. Why? So they can be run in parallel on the GPU
- LIke usual GPU stuff you watch to send large batches of dumb things once, vs lots of little batches, or worse, frequent updates. Graph colour should generate as few sets as possible, and if you want to update stuff over time better to change attributes rather than be adding/deleting primitives, which require a expensive GPU update
- visual analogy is funky tartan patterns; each prim doesn’t have any neighbours with the same colour.
- default will calm to around 8 batches
- the batch color sop is clever to understand connectivity and whatnto, so more separate pieces of cloth don’t slow down as linearly as you’d expect
- hair batches even more efficiently, often batches of 4
- tet meshes graph colour worse, cos there’s more internal connections, eg 80 batches
- 5 substeps at 20 will get better results than 1 substep of 100 (lower velocities per substep, therefore predictions more accurate, therefore less work for solver and constraints, but of course slower sim times)
- smoothing iterations = how to solve the unsolveable. eg you have infinite stiffness constraints, but you’ve pulled your cloth into a shape where they HAVE to stretch.
- example of cloth with only distance (stretch) constraints, no bend, but reduce rest length to half. The solve is biased so that later graph colour batches are correct, but the first ones run are undersolved, get unnatural prim sizes where some are big, some are small; those sizes correspond to the graph colouring batches.
- smoothing iterations just averages the result and distributes evenly.
- can’t just use this by default though, as it takes too long to converge.
- example here was sphere bound over a pig, convert to cloth, high stiffness, rest length low, collide. Ears get bad stretching. Boosting smoothing iterations helps, but doesn't eliminate.
- this is due to undersampled collisions. Collisions are expensive, and by default are solved less often than constraints. in this case, boosting constraint iterations fixes rest of the issues (the demo went up to 50)
Jeffs Iteration Crib Notes
How to deal with Iterations:
- Substeps - More expensive, but gives a better solve - especially for higher stiffness values
- Constraint Iterations - Increase for higher stiffness value to control excessive deformations - great for cheaper solver at high resolutions
- Smoothing Iterations - smoothing ops, to smooth out errors of excessive deformations, or constraint errors
- Collision Iterations - Uses the Detangle sop - lower frequency iterations - complicated and time consuming - increase when collisions are fighting against constraints or other collisions
- However, its probably better to increase substeps and decrease constraint iterations for a more accurate solve - and to reduce load on the constraints - but is more expensive
- the way to make old grains follow animation was to change mass to to 0. Don't do that with vellum (ok you can, but it's discouraged)
- instead look at the pin types, the permanent type uses pops 'stopped' to just follow animation directly for 100% 'this follows target animation'.
- as a matter of style, vellum constraints assume you're feeding them static geometry. when passed to a solver constraints generally only set the initial state, so having them recalculate over animated geometry is a waste. You you need to feed a solver animated geo, you can use the target option instead.
- That said, if target isn't specified, and vellum is expecting animated geo, it looks to the first input. A valid workflow in that case is to timeshift lock stuff, setup your constraints, then reapply animation just before the solver. There's no penalty for working that way.
- soft constraints when done on the cloth node use the same stiffness values as the rest of the cloth. if you don't want that, use another vellum constraint node in 'pin to target' mode, set the stiffness you want.
- to remove these over time, dive inside the solver, use the 'vellum constraint properties' dop. make sure to set a named group earlier in sops, refer to it down here, and towards the bottom of its parameters you'll see a 'remove' toggle. use an expression on activation at the top of the dop node like $SF>30 to animate it.
- making cloth from patterns?
- planar patch from curves, joined with vellum constraints, weld points.
- use the auto generated groups for left/right/top/bottom to setup weld pairs
- vellum post process, apply welds to hide the seam completely, do proper subdivision as a single surface
- simple tearing, on the constraint, enable ‘breaking’, set a limit. on the solver, visualise stress, set the upper limit to the breaking number you set.
- to keyframe in dops, vellum configure constraints, use a wrangle or something to set weld to -1 at a given time.
- stitch points is a soft (like a spring) constraint vs the hard weld constraint. softly bind the front of a jacket, collar to shoulders etc
- ‘rewire verticies’ is the sop under the hood for a weld. it detaches the first point completely, and binds everything to the second. in sim the first point position is updated, but is floating free. its updated in case you decide to use breaking constraints, where the prims will be reattached to the first point again.
- edge fracture is the node to break a shape up into triangles of cloth, ready to be welded and go through the process above.
- if you use the ‘scale by attribute’ option for vellum and that attribute doesn’t exist, it defaults to scaling by 1.
- example to animate welds off used a group sop with bounding box, animated the box. in vellum use a geo wrangle to look up that sop, if point in group, set weld to -1
- edge fracture also lets you define a curve input. can use this to draw on surface, then fracture on that curve
- balloon inflate and burst example: (about the 1h17m mark)
- inflation done in dops, configure constraint, animating rest length to increase over time.
- if weld break in this state, the balloon stays kind of rigid and full. the pressure constraints don’t understand the baloon has popped, still trying to measure the volume and apply their constraint.
- instead use a wrangle to compare number of welds to input geometry; if different, delete the pressure constraints.
- to make the balloon fly across the room rather than just collapse, 2 things are done; detect where the broken welds are, and generate info to feed to pop wind to boost it in a certain direction
- broken welds are put in a ‘broken’ group, can get the average location of these to setup a vector
- this vector is stored as v@air
- in vellum constraints, drag for normal vs tangent is what gives lift, confetti motion. it links to pop wind, hence here he drives the pop wind with the @air vector
- edge fracture with draw curve, you don’t have to have curves fully intersect; you can just draw a small curve in the middle of a section, it’ll put an isolated tear at that point which can be welded
- to use voronoi shapes with edge fracture, delete inline/shared points (divide -> remove shared edges?) , use that as a curve input to edge fracture
- best done in dops with ‘vellum constraint poperty’ dop
- similar to pop property which you’ve never used. :)
- thing to keep in mind is to not be changing constraint count, geo count. that forces a graph recolor, a recook for the gpu, that kills performance
- better to be changing attributes, leave geometry alone. JUST LEAVE IT ALONE
- example here is a bed-sheet reenacting the mission impossible scene; its suspended from wires
- set rest length to 0.5, it smoothly moves up
- why smooth? high damping on the constraints, low stiffness. remember that trick.
- aha, keyframing restlength on the cloth constraint has no effect. vellum just looks at the state on the first frame, ignores the rest. explains a lot!
- could randomize those initial restlengths by inserting a attribute randomize, multiply for example
- dive inside the solver, make a vellum constraint property (VCP), set the group to match the constraint, enable restlength, can keyframe this.
- fiddly example to lookup animated attributes from sops within the VCP vexpression, match from point to constraint prim, change lengths.
- vellum rest blend (VRB) is another way to feed animation, similar to wire/fem
- [ question: does that only affect profile+inflation, or can it translate, follow targets? ]
- VRB in sops can be used to ‘bake’ in an initial state, like a drape
- complicated example here with trees, tori, cloth, need to pull that apart
- stuff made during sim like objects get close together, that sorta thing
- Vellum Constraints DOP (VC)
- sticky collisions this way
- example of hair bead curtain over sinewave swinging sphere
- VC node, each frame, group type primitive, target path chref’d to static object sop path
- ‘keep unique within group’ enabled, will make sure constraints are only made once instead of the usual solver replication/breeding madness
- example using VCP to get stretchy non-breaking tentacles
- he uses 'dopconstraintgeo', its the same as using 'opinputpath' as far as i can tell
- to make sticky wall walkers, ( 2:10:00 ) make a vellum constraints in dops, merge it with your vellum source. set the following:
- create constraints on 'each frame'
- constraint type 'attach to geometry'
- target path your wall (its the third input to my dopnet, so `opinputpath('..',2)`
- max distance short, i use 0.012
- low stiffness, say 50
- breaking enabled, low threshold of 0.01
- hoop toss, throw lots of loops of rope/hair over a column ( 2:13:30 )
- in vanilla state its all a bit bouncy and jittery
- quick way to fix is to enable auto sleep on the solver, set a velocity threshold. Works, but a little heavy handed (its setting permanent pin constraints by setting @stopped)
- can see the autosleep working by enabling 'pin to target' in the vellum object visualizer (might need to expand the constraint radius a bit)
- getting fancy is to use the layering+layer shock; add a point attrib on the incoming geo (not the constraints) which is i@layer = int(@Frame);. The layer shock feature of the solver will detect this, and for collisions treat geo with a higher layer as 'lighter', imparting less energy.
- going from default, to layer attributes, to auto sleep, the visual feel is water balloons, vs water balloons filled with gravy, to water balloons filled with quick drying cement; each one has less energy, less oscillations than the previous.
- handy cheat for working with hair in dops for viz; enable thickness, also enable 'extrude' checkbox at the end to get tubes rather than spheres per point
- the cunning solution here is to create a manual constraint setup that is like autosleep, but soft pin constraints with low stiffness and high damping. Create a pop group named 'slow' set its vexpression to if (length(@v)<0.01) ingroup = 1;. Append a vellum constraint:
- create constraints: each frame
- constraint type: pin to target
- group type : points
- group name : slow
- pin type : soft
- stretch stiffness: 10
- damping ratio: 0.5
- balloons 2:19:35
- strings are setup with sop vellum constrain hair
- balloons are setup with sop vellum constrain for cloth and pressure
- groups are made for string start+end, balloon knot
- separate vellum source nodes are used for strings vs balloons
- means can use isolated pop forces for each; strings get drag, balloons get pop wind on +Y
- dop vellum constraint weld from string end to balloon knot (mentioned elsewhere that its better to constrain from string/hair to cloth),
- dop vellum constrain string start as a target constrain to lock to origin, this will set @stopped to 1
- can use a pop wrangle to set stopped to 0 after a given time to detach balloons:
- float t = fit(@Frame,30,70,0,1);
- @stopped = rand(@ptnum)>t?1:0;
- Can have the rest state for geometry change over time, mostly in reaction to forces and collisions. So the rest angle can be adjusted so things stay bent, restlength can be adjusted so that things stay stretched.
- threshold, rate, hardening are the primary controls:
- threshold : what is the angle/length ratio beyond which rests values will start to be altered
- rate : how quickly will it blend to that updated rest value; metal will update quickly, springy bamboo very slowly (it can be bent for a long time and still return to its original state. Higher numbers mean it'll be bent (and stay bent) more easily.
- hardening : how will it behave after being bent; can use this to dampen down how much plastic-affected grass will continue to be moved by wind, for example
- the grass example is fast and stable if you give it appropriate initial conditions; no self collisions, scale is important, not too many points on the line. Like most of vellum, stray beyond that and you'll spend a lot of time wedging and testing.
- quick example setup:
- line, 10 points, length 0.2
- group the root point
- scatter lots of them on a 2x2 grid
- hair constraint:
- pin to animation, group 'root'
- bend stiffness 10
- enable plasticity
- threshold 6
- rate 5
- on solver:
- self collisions disabled
- no ground plane
- gravity set to 0
- inside solver, add a pop wind, wind velocity -0.5 on x, 0.5 noise
- keyframe a sphere to run over them, the stalks will bend down
- as mentioned, turn on anything seemingly innocuous (ground plane, gravity), get all kinds of weird stretching or jittering.
- can take this sim, timeshift freeze it, gamedev sweep into lines, point deform for simple renderable setup.
- false colour mode on the solver visualize tab, 'bend angle', can be used to determine a good threshold for plasticity.
soft bodies and tets
- your assumption that there was a Right Way you were missing, no, its as it should be:
- take your geo, remesh it, solid conform it. VC distance for surface behavior, VC tet volume for volume, sim. Point deform your original mesh by this.
- need to play with the tet fibres stuff next...
- can do funky fresh things with grain glue, if you cluster the point the VC glue at those clusters with low stiffness, you get clumping
- make sure to set the group type to 'points', even if you don't use groups, otherwise the constraints won't be made properly.