· 8 min read

Printing Vines

Designing a computational workflow to print a childhood passion.

Designing a computational workflow to print a childhood passion.

I want to be able to grow vines around any geometry and print the results.

Ever since I was in grade school, I’ve been obsessed with how vines grow. In class I would doodle vines all around the margins of the current assignment. Later in life, I was given a page (sadly separated) from a medieval manuscript with vines in the margin. My childhood doodles wanted to look like this.

Old Vines Book of Hours page, circa 1450

Now I look at the vines in my garden and ask the same questions that once flitted through my disorganized and unscholarly younger mind: How does a vine decide when to branch? When to have a leaf, or a flower, or fruit? How do they choose the direction of next growth? Do they try to avoid running into their own branches? Does the vine as a whole make these decisions, or does each growing tip decide locally for itself?

My go-to consultant (sister-in-law) on matters botanical says the answer to that last question is that there are a few (slow) global biases such as light and gravity, but vines are mostly decentralized systems using local sensing and decision-making. This matters because we are less likely to get believable vines using global optimization algorithms like shortest-paths or minimum spanning trees.

But we can try implementing all of these and see what looks best! I’ll use the Houdini pig as the underlying vine support structure, because it includes all sorts of challenges such as thin ears (we don’t want the vines to grow through them — no pierced ears for this pig!) and overhangs such as the mouth. The vines, leaves, and flowers will be a bit chunky, because we need to be able to 3D print these and have them remain sturdy. (Also, I was too lazy to pull out the gazillion leaves and flowers I’ve already designed.) There’s also some work involved in placing the seed points from which the vines grow, but we won’t go into that. All this has to end up as an automated workflow, so you can just pass it a geometry and the right vines grow.

I started with a local-sensing approach: the vine climbs along its support surface guided by climbing strength, wobble, and several other parameters. This keeps the vine tightly against the underlying geometry. To do this we use a SOP solver in Houdini, allowing us to simulate the growth frame-by-frame:

First 136 frames of the surface-vine simulation.

There are a lot of parameters to play with, and a lot of them involve the probability that a vine tip makes a certain decision at a point of new growth: whether to branch, grow a leaf, grow a flower, die, wobble in a different direction, etc. There are also bias parameters such as how strongly the growth should head upward or how hard a new branch should try to head away (on the surface) from its parent. Here are the available parameters minus the colors for flowers and such, since the list is pretty long:

Surface Parameters Parameters for the surface-based simulation.

The simulation looks viny, but there are a few downsides. Controlling the behavior of the vine parametrically is quite sensitive, and new vines really want to grow parallel to their parent and siblings. But some real vines are like this too — you get whole sets of young vines growing together in clusters in the same direction. What is less appealing is that vine stems grow right through each other. I implemented having vine tips sense if they were approaching another stem of the vine and shifting the point up and over the obstacle, but it actually looks pretty lousy and involves a lot of resampling the curve and patching nearby points. From a distance having self-intersecting vines isn’t so bad, but close up it isn’t satisfying.

Criss Cross Lots of self-intersecting vines.

So let’s try something different: a space colonization approach based on the work of Adam Runions [Runions, A., Lane, B., & Prusinkiewicz, P. (2007). Modeling Trees with a Space Colonization Algorithm. Eurographics Workshop on Natural Phenomena, pp. 63-70.]. This approach sprinkles attractor points inside a volume. Vines grow toward an average of the attractor points they see within a radius of influence and consume points within a kill radius. This is great for trees in free space, but we’re trying to grow along a surface. We can sprinkle the attractor points only on the surface, but I’ve found that this makes it hard for the vines to climb as much as we’d like, because the right balance of influence radius and kill radius on a surface is difficult to achieve automatically, and many vine tips get blocked.

Instead, I use VDBs to create a volume around the geometry and sprinkle the attractor points in that. This means that points often grow a distance from the actual surface, but so do a lot of real vines. This approach also carries the advantage of Adam’s original work that vines naturally avoid self-intersection. Whereas vines using the surface approach crawl, in the space colonization approach they compete. Because we can’t allow the volume around the geometry to be very thick, we still have a problem of nearby vines wanting to head to the same attractor points. I alleviate this by having vines use a random sampling of the attractor points within their radius of influence. Here are the viny results:

First 136 frames of the space colonization simulation.

Here too there are many parameters for influencing the vine growth, many of them shared with the previous method. But overall I like this approach better, because the placement of the attractor points provides clearer control for the outcome.

These are the two approaches I tried for growth using local decision-making, but maybe I shouldn’t discard global optimization solutions so quickly. Even if they aren’t what vines really do, are they good enough? So I tried two of these as well: a shortest path algorithm and a minimum spanning tree (MST). I used Prim’s algorithm (1957) for the MST.

In the shortest path approach, vines follow the shortest routes through a network of surface points, naturally branching as multiple paths share common segments near their roots. One of the problems with this approach is thus that many branches will follow the same paths, so you can get a lot of parallel vines. Here’s an example of the problem. There are too many flowers along the base vines because they are actually many parallel vines in the same place:

Shortest Problem Too many flowers in one place.

We fix this by asking a potential new flower to sense whether there are already flowers too nearby. If there are, it removes itself, but this is heading right back to local sensing. Other downsides are that there is no animation (the entire vine network is computed at once); it requires defining explicit endpoints; paths are often too direct since by definition they are trying to be short; many paths will converge near the seed points creating unnaturally thick clusters; coverage depends on end point placement; and the paths are constrained to follow the underlying graph edges, so the mesh structure is visible. Still, it looks like a vine!

Shortest Path Flowers too near other flowers have removed themselves.

The second global optimization approach we’ll try is the minimum spanning tree. Here, the vines grow as a single interconnected tree that reaches every point on the surface with no redundant paths, guaranteeing natural branching without parallel routes. The main downside is that the vine paths are constrained to follow the edges of the underlying point network, so the branching angles and path directions reflect the graph structure rather than looking purely organic. The branches tend to meet at roughly the angle of the polygon angles. With scattered points you will instead see the influence of the connection radius. Other downsides include no animation; it’s harder to control where specific branches grow since the algo finds globally optimal paths; coverage is total (without further pruning) since the MST reaches every point in the graph; any biases you set up tend to apply too uniformly; and the quality of the results is highly dependent on point distribution. It looks a bit like a vine, maybe:

MST The minimum spanning tree result

Here are all four methods next to each other:

Pig surface
Surface-based simulation
Pig space
Space colonization simulation
Pig Shortest
Shortest path algorithm
Pig MST
Minimum spanning tree algorithm

Overall, I like the space colonization approach best, since the way it spreads out lends itself to practical uses (if you consider jewelry practical), but let me know if you prefer a different one or have another suggestion to try. Send me email!

In a future post I’ll show how I use the vines for jewelry. I’ll use a fun bas relief technique.

Also, if you know any pigs in Houdini, tell them it’s probably not wise to stand still for too long.

    Share:
    Back to Blog