Idea
The combination of the interactive real-time world in Unreal Engine with the fully controlled, pre-simulated world of Houdini. One of the first explorations of this idea led to the creation of a tree in Houdini that can be simulated and animated in various ways, and then placed in a real-time environment. Everything is saved and exported in the FBX format as if it were a character.
Main challenges
One of the main challenges is the granular control of individual branches; unfortunately, trees have more than can be exported as a rig. A balance needs to be found in how we accurately replicate the skeleton-mesh relationship.
The process
- It all starts with creating the tree itself. The SideFX Labs toolset was used here, which is well-documented. In the link below, you can find a playlist of tutorials discussing the use of these tools:
https://youtube.com/playlist?list=PLXNFA1EysfYkiIWvM3CBXO-TsYE1H42dK&si=r76iv6renf0BoJRd
Final step:
The node highlighted in red is responsible for the final level of branches, which are the branches where the leaves are scattered. However, due to reasons discussed in the "Main Challenges," they are not included in the rig, so editing this node internally is required. More details about this editing will be explained in the step of assigning weights from the skeleton. - The skeleton itself is already largely created as a second output in the Labs nodes (in the first image, the null is labeled "OUT_Tree_Skel"). These are simply curves on which the branches are based. An important step is to resample these curves, where we actually define the number of bones. This is done by setting the number of segments in the "resample" node. This ensures more natural behavior during the vellum simulation, with longer segments being stiffer. Before this, the "branch_level" point attribute is promoted to the primitive level and renamed as "class" for future convenience.
- 'Set level pt group' creates point groups based on the branch level attribute and generates a group for the starting point of each branch (each branch is a primitive).
- 'Snap to closest' shifts each starting point to the closest point on the previous level. This allows us to fuse it later. There is a better solution for creating a new point using primuv, but it's more complex. However, it provides more accurate results; sometimes, the shift may be significant, especially when snapping to the trunk.
- The last step is creating attributes for the vellum simulation: Thickness and Stiffness. You can set up a system with better control over the levels and also tweak the density attribute. These attributes can be used to scale constraint parameters.
- The Vellum solver uses mostly default settings with subtle pop wind inside You can add more constraint iterations and substeps if the tree isn't stiff enough, even with the highest stiffness possible.
- A quick and dirty way to create a rig from this simulation is to fuse everything and use the Rig Doctor at the end. It’s not an ideal solution, but it’s fast and good enough for this case. If you're looking for a more proper and robust way to use Vellum with KineFX rigs, you can refer to Entagma's KineFX course.
- The last step is to create weights from this rig on our mesh. We need to merge level 4 into level 3 due to the bone count limitation mentioned earlier.
A bigger challenge is merging the branchID attribute. That's why in the first screen, the last 'branch generator' node is opened and slightly modified. We need to inherit the branchID from the parent, which is why the line where the new branchID is set is commented out.
(Screenshot from inside the last level of the branch generation)
The level attribute is used to split each segment. BranchID is used in foreach loop to separate each branch to avoid weighting neighbour branches in the last level. In this use case for the last level proximity capture was good enough, for the rest of levels biharmonic was used with defaults parameters. "fbx_material_name" on primitives was used to assign material for leaves in unreal engine. - Export from Houdini is essentially default. The only change is the Axis, set to Z-up as shown in the screen below. In this scenario, the rig has 5,500 bones, and the mesh has 1.5 million points (2,300,000 triangles).
- Import to Unreal 5.5 is also done with default settings. We can see in the skeletal mesh asset that the entire rig is imported successfully with the proper hierarchy. Starting from version 5.5, we can also enable Nanite on skeletal meshes.
Labs tree tools come with UVs on both the branches and leaves. The leaves material is created from a simple photo with basic color/UV control parameters, while the branch material uses a bark texture from FAB.
Ideas for improvement
The main future plan is to create an RBD simulation with soft glue constraints using the same export approach. This will allow for more complex destruction simulations. Additionally, the weighting and simulation rig itself can be tweaked more precisely.
From an optimization perspective, chunking a large rig before export should improve the CPU bottleneck, as we get smaller hierarchies. The RBD approach addresses this issue, as each piece would be its own rig.