Peach Tree Generator in Houdini

This is my dailies blog for a peach tree generator I am creating for my final project for VSFX 406: Concept Development for Visual Effects. I intend to use this as a chance to become more familiar with vectors in Houdini.

Project Scope

End goal: The goal of this final project is to create a procedural tool that creates a peach tree. I intend to use this as a chance to become more familiar with vectors in Houdini.

Finished shots: 3–5 5 second turntables of various configurations of the peach tree tool.

Equipment used: SCAD’s computer labs, Houdini 17.0.352


Update 1: Trunk and Branches

The basic vector code was based off of a low-poly tree generator made by Ryan Gold, a classmate of mine.

Making the trunk:

First, in a geometry SOP, plop down an add node and add a point at the origin. Now let’s put in a point wrangle and start mucking around with vectors.

Let’s spawn the trunk. In the object level, make a parameter called trunkLength. Go back down to the geometry level and put down a for-each loop. Here’s the settings for the for-each loop:

Now put a point wrangle inside the for each loop. Here’s the code for it:

Now we have a line that will become our trunk. One problem — there are a bunch of points in the exact same spot. Put down a Fuse SOP to solve that. Then put down a Group SOP and name the group “trunkGroup.” Finally, put down an Attribute Delete SOP and delete all attributes except P.

Making the branches:

Wire a Polypath SOP underneath our trunk to start making our branches. Now put a Carve SOP underneath it, and check on “First U” and “Second U.”

Put down a point wrangle. In this wrangle, we’ll be determining which points of the trunk will grow branches.

Now put down yet another point wrangle. This one grows the first segment of each branch.

Now put down a for-each loop. The settings are the same as the previous for-each loop, except use ch(“../branchLength”) as the iteration amount. Wire a point wrangle into the for-each loop. Here we go:

Now let’s fuse all the branch points together with the Fuse SOP, delete all attributes except P with the Attribute Delete SOP, and put the bottom point into the trunkGroup that we made earlier. I did this by plopping this bit of code in a point wrangle:

Now let’s merge the trunk and the branches together.

First, put down a Fuse SOP with no values changed. Next, put down a Fuse SOP, but set it to only affect the trunkGroup and set the Distance Value to 2. Now that the trunkGroup has served its purpose, we can delete it with the Group Delete SOP.

Put down a Smooth SOP, with the strength set to the parameter ch(“../smoothAmount”) from the object level. Use a Sort SOP to sort all the points “By Y.” This way, there won’t be any weird thicknesses in the final branch geometry. Now, put down a point wrangle.

The next point wrangle makes sure that the ends of the branches are the thinnest.

Now, put down a Polywire SOP to actually get the shape of the tree. Change the Wire Radius to @width. This changes the thickness of the Polywire to follow our width attribute. Divide the tree. Then subdivide it using OpenSubdiv Bilinear to prevent smoothing. Subdivide it again, this time using OpenSubdiv Catmull-Clark to introduce some smoothing.

Moving Forward:

  • Getting a better smooth on the trunk
  • Adding leaves and blossoms

Update 2: Adding Leaves

Making the leaves:

The leaves are formed from a semicircle. Settings of interest:

The points of the leaf are then moved around in a point wrangle to get a more pointed shape on one end:

It is then rotated -30 degrees in x and then merged with a line. For the line, a spare input is added. This spare input is connected to the transformed line. Line settings are as follows:

Fuse the points together and then use an Add SOP to delete the geometry but keep the points. Now it’s time to add the polygons that make up the leaf. Put the following code into a detail wrangle:

Reverse the polygons (if the fact that the polygons face the wrong way is bothersome) and then mirror it over the Z-axis. Put down a Bend SOP to bend the leaves. These were the settings I used:

Preparing the leaves to be copy stamped:

Make three parameters at the object level: leafHeight, leafDensity, and leafAngle. Connect a Resample SOP to the Smooth SOP of the trunk. Reference the leaf density parameter in the Length parameter of the Resample SOP. Next, use an add node to delete the geometry but keep the points. In a point wrangle, use this code to delete points:

After the point wrangle, use an Attribute Delete SOP to delete the yVal point and detail attributes. Put down another point wrangle. This one randomizes the orientation of the leaves:

Now, put down a Copy to Points SOP. Plug the leaf into the first input and the points that were just made into the second input. Delete all attributes except P and merge it with the trunk.

Update 3

A more accurate way to place the leaves:

After the class was over, I decided to remake the leaf scattering because leaves don’t grow from a certain point upwards. They grow on the ends of branches. Simply put, my old method worked, but it was wrong.

Let’s get to it.

First, at the object level, delete the leafHeight parameter and replace it with leafScale.

Connect an Attribute Delete SOP to the Smooth SOP that was created in the trunk. First, in a point wrangle, find all the end points that aren’t in the trunk and put them in a group. Also, make an attribute to store the number of neighbors each point has. If a point has 1 neighbor, it is an end point.

Here’s the code:

In the next point wrangle, if a point is in the End Point Group that was just created, store its neighboring point in an attribute called @neighborPoint.

Put down another point wrangle. Not all of the end points connect directly to a branching point. Let’s find the points that aren’t branching points and find their branching points.

Now, in an Add SOP, delete all geometry but keep the points. It’s time to add lines only where we want leaves to grow. Throw the following code in a point wrangle:

In yet another Add SOP, remove unused points. In a Resample SOP, set Length to be ch(“../leafDensity”). In an Add SOP, delete all geometry but keep the points. Delete all groups and attributes except @P, and put down one last point wrangle. This wrangle determines the rotation of the leaves.

Plug this into the copy to points node from Update 2. Now, this peach tree is growing leaves properly. One more thing: remember that leafScale parameter at the beginning of this update? Set uniform scale in the transform node at the end of the leaf nodes to equal ch(“../leafScale”) instead of 1.

Houdini / Technical Artist. SCAD Visual Effects ‘20. Lives and breathes Houdini, Nuke, Unreal, and (sometimes) Maya.