Procedural Tree Generator

The basis of this post was inspired by Entagma’s excellent tutorial on the space colonisation algroithm. I took this, modified it slightly, and worked to get a clean, animated mesh over the branching structure. This process took much longer than I anticipated. I will only go over the high level process, as it would take too long to go into depth with all the iterations.

To start with, I simply modeled a half cylinder, and applied some distortion to it for a slightly irregular shape. This was with the goal of creating a shape that looked like a fan coral. I then followed the same process as the Entagma tutorial to create the space colonisation algorithm.

tree1.png

This first iteration was based on generating an inverse relationship between pscale of the polywire and distance to the seed points. It started out quite well, however I wanted more control over the drop off in scale so needed to start with a linear relationship.

tree3.png

This is how it looked with a linear falloff, and adding a ramp control to the scale. This gave more control over the look, however a few issues were starting to appear. The branch ends close to the base were too thick and there was no control over this, it was also a hard edge with no rounding. I also observed that if a branch was smaller than the radius of the wire it connected to, then the polywire would invert and make bad geometry.

tree4.png

I tried copying distorted spheres to the intersection points, as well as smooth spheres to the ends. I then converted the surface to VDB, smoothed and converted back to polygons. This helped to smooth out the ends, and fixed the bad geometry. However even with a poly reduce node the polygon count was much higher, and the look was arguably worse.

So instead I tried to alter the branches, I would push them out along the normal to the branch, however this was a bad idea. Branches were then able to connect to new points, would would behave unusually, and lead to significantly more broken geometry. Turns out the polywire really doesn’t like sharp angles. So I went and tried to remove small branches.

Peek 2019-03-15 14-54.gif

I created a set of wrangles, which would go through the tree, set the ends and branching points, and was able to remove any branches that were short. This was controllable to a user specified level. It was also placed inside a for loop, in case that removing a branch left another small branch in place. By iterating over this a few times, all branches of a given length were almost guaranteed to be removed.

Next I wanted to try and have control over branches individually, so I started by creating two groups of branches, one to be a main “thicker” branch, and the other to be smaller secondary branches.

tree01.png

I was not particularly happy with the look of having only two classes of branches, but this gave some groundwork for creating a hierarchy of branches. Also I realised that during the resample, some branch points would get assigned to the main branch due to chance, so when the different branches were blasted away, some gaps formed. Using a length attribute created during creation, I was able to inverse the actual distance to the base, and was able to taper off each end nicely.

tree02.png

I tried something completely different, and the result was finally looking nice … on the surface. To achieve this, I created a new mesh from the base to each end. So the internals of the tree were completely unweildly, and the boolean node was not a happy chap trying to deal with it. Booleaning (booling? I’m not sure what word to use here) each piece separately may have worked, but I gave up waiting. Converting to VBD and back gave a good result, but the poly count was much higher, and again it took too long, I wanted to be able to animate it growing within human timescales. At least I had added some nice additional controls and achieved a look I was after.

Tree03.png

After some more work, and more terrible ideas, I finally got the result. I created a hierarchy of branches, where the longest path to the base was most important. The thickness of the higher priority branch always overrode the smaller priority branch. This allowed for each branch mesh to grow from their individual start, either the base, or the branch it connects to.

coolbeans.gif