The above video is a thing that wasn’t really supposed to be a project, but turned into one 🙂
This series of blog posts will break down how I made it!
This first post will be some background on the project, and how I set up the movement of the squab and spawned the initial points for the tubers that are attached to it.
This whole thing was a feature exploration of CHOPs that went off the rails a bit.
While working on another Houdini rendering project at home, I needed to dynamically re-parent an object half way through an animation.
Luckily, there is a shelf tool for that!
When I ran it, Houdini created a constraints network, and it seemed like nothing else had changed.
The object was suddenly dynamically parented at that frame, but there were no attributes, or connected nodes, or anything that I would expect to see generated.
Just a new network, and a reference to the constraints on the geometry node at the obj level.
So, magic basically?
Get to the chopper
I’ve never really used CHOP networks before, and it seemed like a good time to see how they work. Much like the other contexts in Houdini, there is an endless amount of learning and exploration that can be done here, but I started out watching the great “Introduction To CHOPs” videos by Ari Danesh (@particlekabob).
My squab video was the result of me getting distracted and going off on a tangent while watching the training!
If you’re interested in CHOPs, I’d really recommend watching those videos. I’m not going to go very in depth over things that Ari already covered.
Setting up the squab
In case you’re not familiar with it, the “squab” is a test asset that ships with Houdini.
If you happen to know who made the squab, please let me know and I’ll edit this post with that info 🙂
I decided I wanted to create tuber like growths off the side of it, with bulbous end parts that would emit spores, which travel up the tuber in a pulse.
The first network to dive into sets up the points on the squab that will spawn tubers, and also sets up the FEM (soft body) data for the squab.
I won’t go into details on the two bottom right network branches: These are selecting some points that are fixed for the FEM solver, and mostly standard nodes created by the FEM Organic Mass shelf tool.
The left “Tuber points” branch scatters some points on the squab body, taking the normals from the surface.
I didn’t want many tubers coming out towards the front of the squab, so I deleted points based off the magnitude of the Z component of the normal (a Z value of 1 means the point is facing straight forward in “squab space”, since the squab is aligned to the world Z).
The next issue is that some of the generated tubers would crash through the squab geometry.
I didn’t need to entirely solve this, since it’s a dark scene with enough going on to mask some intersections, but there were some pretty obvious bad ones:
The first thing I tried worked out well enough, which was to ray trace out from the tuber points and see if I hit any squab geometry. If I hit geometry, I delete the point.
It’s a little ugly, but here’s the VOP that collects the hits:
There are two non-deterministic random nodes, and to force those into the loop body I’ve just exposed the “type” as a constant, and fed it into the loop. Makes no sense, might not be necessary, but it gets the random nodes into the loop body 🙂
That’s part of what makes it messy.
Each iteration of the loop is a sample, the number of samples is a parameter exposed to the network.
I use a SampleSphere node to create sample points on a cone around the normal, with an angle of 45 degrees. I use the vector to those points as the raydir of an intersect node, and trace out from the point and see if I hit anything. I store the max of the hitprim into an attribute, and then I just delete any points where this “hitval” is greater than 0 (the default hitprim is -1).
You can see that running this pass removes quite a lot of invalid tubers, I didn’t mind it being too aggressive.
A smarter person would have done this non procedurally and just manually placed points, I probably need to start doing that more often 🙂
Proceduralism for the sake of it is a great way to waste a lot of time…
On the main network graph, there are three Transform nodes that I’ve coloured aqua (the ones toward the bottom of each of the three network branches), these are fed data from the “motionfx” CHOPs network.
I’m using random noise to move the body of the squab (and the attached tuber points) around.
The “Body Motion” is almost straight out of the tutorial by Ari Danesh, here’s what the “motionfx” network looks like:
First thing to note, the tuber points and chops body get animated in exactly the same way.
The top left of the graph I use channel nodes to create transforms for the tuber points and the squab body:
Then I merge them together, and work with 6 channels for the rest of the network.
However, this is unnecessary!
I could have worked with a single set of data, and then made the export node write out to the multiple transforms. This is something I learnt from the tutorials after I’d implemented things this way 🙂
Move yo body
The Body Motion group of nodes was largely trial and error: I added a sine wave to some noise, and added some filters and lags until the motion looked nice.
Not very scientific, but here’s what the waveform results of each of those nodes are:
That’s over 600 frames, btw.
And that gives me something like this:
I wanted to get a sort of floating in water currents feel, and I was fairly happy with the result.
I also wanted the body to rotate a little with the movement.
I tried a few things here, such as a CHOPs lookat constraint, various VOP things.
In the end, I did a very hacky thing:
- Took the position of the original waveform, and moved it one unit down in Y
- Applied a lag to that, then subtracted it from the original position waveform
- Multiply it by some constants
- Rename it to be the rotation channels
If you imagine the squab body as a single animated point, this is like attaching another point a little below it, and attaching this new point to the first point using a spring.
Then, measuring the distance between the points, and using that distance as a rotation.
A bit of a weird way to do it, but it gets the job done! 🙂
I’ve overexaggerated the rotation and lag in this gif just to make it obvious:
In future posts, I will break down the creation of the tubers, some of the FX work, and also creating the sound in CHOPs!