Felipe Marceu shared the technical details of his Red Rock Canyon terrain and Yucca tree created procedurally in Houdini.
Hello there! My name is Felipe Marceu, I live in Osasco, São Paulo, Brazil. I have been working with CGI since 2007, primarily as a 3D generalist, now focused on VFX in Houdini. In 2018, I got hired by one of the major VFX content producers of Latin America, Vetor Zero, - there I learned and trained Houdini, and worked for big brands such as McDonald's, Coca-Cola, and others. I worked there for two years as a Houdini artist and I’m very thankful for this opportunity.
In 2020, alongside my professional career, I dedicated my time to developing a workflow for terrains and procedural assets and I am going to show a bit of the process and techniques I learned with it.
The Procedural Path
When I was in my third month at Vector Zero the VFX team was introduced to a technical challenge which was to develop a specific advertisement shot, with an effect related to fluids. At that time I was able to solve it even without much experience and I took all the VFX responsibilities in that project.
Some companies are fast-paced, so as an artist, you need to show fast and concrete results and, of course, to handle project changes as quickly as possible. With the procedural nature of Houdini, I could handle those changes, including some extra shots that the client asked for, - the first shot became five or six at the end of the project, and we were able to do it in the same deadline since in Houdini you have the possibility to go “back to the past” in the node chain and easily change it, propagating the results along the chain and adapting the original scene to new ones faster.
I was delighted to discover this procedural thinking. To get into the procedural world you must think about a way to create a system that relies on non-destructive parameters. Let's look at the example of the procedural Yucca ground plant that I did for this project. As soon as you define some parameters that rely on a system that could be changed and propagated along the whole asset chain, you can easily customize your asset, even randomize it along with the environment. This could be a game-changer closer to a project deadline.
The skills that I had to build along the way come from logical and spatial thinking and some programming notions will be needed as you progress into deeper simulations and projects. Houdini has 3 common programming languages: Hscript, Vex, and Python. The first two are widely used in everyday tasks.
A piece of advice: studying and using Houdini every day is essential if you want to develop your skills faster. To help you with this, I highly recommend checking out this page and look at all the study materials. There are great instructors like Rohan Dalvi, Robert Magee, Steven Knipping, and so many others that provide free tutorials to help you learn a whole world of possibilities inside Houdini. If you can afford a course, Rebelway, CGMA, Gnomon, and other institutions provide very detailed classes that cover major challenging processes of the software. Always look at the description and prerequisites of the courses to be able to follow without feeling confused.
I often take pictures on a trip or on a daily basis and really get interested in landscapes, beaches, mountains, and deserts. Each place on Earth has something special to show us, and I decided to use the Red Rock Canyon Desert, Nevada, as an inspiration for my project; it presented interesting challenges in terms of lighting, modeling, and texturing.
The first challenge was to reproduce and mix the shader materials to generate natural tiled maps with displacement and high definition with smooth transitions between them. I asked a friend about it and he told me that the workflow was very extensive to explain, so I had to create my own workflow. I will show it to help those who might be facing the same questions right now.
For the terrain, I used Houdini Heighfield nodes to sculpt mountains, generate erosion, and control the overall form/shape of the terrain.
Once I was satisfied with the terrain, it was time to create custom layers from masks to drive the texture and shading.
One of the best ways to create masks from heighfields is using the "Mask by feature" node. With this node, you can create masks from various aspects of your terrain, such as height, curvature, direction, etc. After that, we will redirect those masks with custom names such as slope_masked_01, slope_masked_02, ground_cracks, rocky_ground, dunes, etc. You can migrate do that by using Heightfield copy layer node. It was important to use these layers on the shaders as masks to blend between the types of terrain.
With the mask in hand, we can use the "HF data to COP2" node (COP stands for Compositing operators).
In this COP network, I built the system that bakes JPG of the custom masks in a unique numbered sequence that could be thought of as the way you want to stack the shaders, for example, rocks, moss, etc. Inside that COP, I created an SOP import node to import Heightfield Masks and defined 4096 x 4096 as the resolution for these black and white masks.
After I plugged a channel copy node for each mask, I plugged them all into a switch node with input index “$F-1”, to call each mask by a number as I play each frame. This method will be important to save them all at once. Take note of the sequence of the masks, because each number will be in the same position as the masks connected in the switch hierarchy. This switch node will be connected to an ROP file output to export a sequence of JPG heightmaps numbered following the frame number. To do it, hit render button.
Since these masks rely on procedural masks along with the geometry of the landscape and I was polishing and changing all the topology all the time at this point, this COP procedural solution imported and saved all the changes at the same time after the shaders took the updated images from the directory. I thought it was a better solution than a heightfield output for each of these masks since the heightfield output node has another structure of generating the masks that would be very heavy for my workflow.
For the shaders, I created a custom network of principled shaders compatible with Mantra (Standard Houdini render Engine). Inside those shader blocks, I created a Null called General_shader_controlers, custom parameters to control the displacement and bump for all the principled shaders of the specific environment shader network, and a parameter to control the tiled boxes of the principled shaders. This parameter gave me the exact number of tiles to achieve a natural size and repetition for each map such as rocky ground, Gravel_Dry_Ground, rocky_cliffs_brown, etc.
The textures are controlled by some layer mixes that add new layers of materials following the mask created in COPs previously, finishing with a null that I’ve linked to the material node in the environment chain (I will describe it below).
After creating these maps, we`re able to shade the main terrain.
After the Heightfield_out node, I put a visibility node to turn off the main terrain but maintain the heightfield proprieties and its layers, applying a Heightfield scatter node after that to populate the scene with shrubs, little trees, ground Yuccas, and some grass. The workflow included some HF scatters based on the different HF layers as tags. I made some of the common plants in SpeedTree but used the low poly versions packed in Houdini to optimize the memory. After that, I created some material nodes and applied the materials of the plants using tags taken from the HF scatter. To be able to apply the shaders without issues I promoted the tag attribute to primitive and checked the option Create style sheet attribute.
I added a branch right after the end of the HF chain to convert the Desert Heightfield to geometry, optimize it, and remove spare parameters which led to even more optimization. Then, I merged it with the vegetation scatters and, using the same method, applied a material node to the environment already converted and optimized.
Finally, I merged it with the hero Joshua trees that I’ve generated procedurally (described below), applied the material using the same material node method, and to finish, did a UV camera frustum deletion to remove the unused geometry and save more memory.
The second plane of the mountain range has been created with the same method I used for the first terrain. At first, I wanted to create the sky using an animated procedural cloud rig inside Houdini, but for optimization purposes, I took a free HDR plate inserted in the post-production.
The Joshua Tree (Yucca)
The Joshua tree is a kind of Yucca plant; its repetitive shapes and forms are a perfect fit for Houdini's procedural workflow. Let's take a look at how I built one.
This text is a little bit technical, but if you have some understanding of Houdini I hope you can reproduce it without major issues. I've created a line, then an attribute called pscale (a native attribute in Houdini). To have different point sizes along the line I created an Attribute VOP that takes p and splits it in floats. In Y I created a ramp and added this value to pscale using bind export named pscale. I used a sweep node with a line (origin in x) with the following parameter ch(“dist”) / -2 to make the line centered on the first line point. The sweep node generates the geometry of the leaf. I projected the UVs and did two bends to make the leaf close to the reference.
To generate the leaf groups in a kind of conical shape like in the reference I created 4 groups with circles and normals connected at p. I created a “for each” node structure that copies the leaves to these points with a bend node where the bend attribute is referenced to the iteration metadata of the "for each" loop. In each of the four groups, I scaled the circle in mode to create more closer points and make more narrow conical groups of leaves. After that, I merged them all.
To make the dried main leaves, I followed the same process, but with more bending on the leaves, fewer leaf groups, and normals pointing downwards.
To create the trunk dried leaves, firstly, I created the trunk and used two bend nodes to make the S shape of the trunk. After that, I added a transform node to rotate the trunk in a pleasant way. I used the same pscale technique demonstrated on the leaves to do the trunk and make it narrow along the way, connecting a polywire node with the wire radius that's in its turn connected to pscale attribute created earlier.
To do an aesthetic round end for the trunk, I made a group isolating the upper trunk line endpoint, creating a color attribute, and transferring it to the polywire points. With that attribute, I added a polybevel node at those polywire endpoints (this could be achieved in a non-procedural way if you like) and opened the UVs.
Now, returning to the trunk dried leaves, with the trunk already created I took the original trunk line and created two groups by range nodes called midpoint and endpoint. I combined the midpoints and endpoints groups with a group combine node and created color for this new group. Right after that, I transferred the attribute color to the areas that I wanted to have leaves with white. Then, I did a scatter by color, deleting the remaining points outside the white areas and generating custom normals to point outward the trunk. Finally, I copied the leaves from the leaf generator to the scattered points with a copy to points node and did a vellum simulation using the trunk as a collider, caching the results.
After I baked all these different parts of the tree, I imported them with a file node, used the material node to shade the different parts creating principled shaders for each part of the tree, added a transform node to move and rotate the whole tree, and even dropped more copies with different transform nodes, merging them with the desert scene.
Note: The Lookdev and textures of the Joshua tree were done in Substance Painter.
My exceptionally talented friend Luiz Benassi did a wonderful compositing work in Nuke.
Keep the Scene Organized, or It Will Get Crazy Later
Something that needs to be discussed when working with CGI and especially in more technical software like Houdini is the organization workflow. When I started to work in Houdini, I got lost very easily. For the most part of the projects, you will work with many node chains, importing and exporting data, changing this data inside subnetworks with another network inside. At some point, if you don't stop for half an hour and rename those generic nodes in a more intuitive way, you will have serious trouble in the near future.
If you keep things organized, after one week or two months when your client asks for changes, you will know what you need to modify without the need to pass through the chain of different nodes again. And if you work in a VFX team, it will help your peers to understand your project while you are on a deserved vacation or just aren't near to help them.
The next steps planned for this project may be delayed since half of my Ram is gone, but as soon as I get my workstation ready again I will make some “explosive” tests on that desert ground, or maybe another similar place of this vast environment.
Important information: since Houdini’s recommendation for more advanced scenes and simulations is 64 GB of Ram or more, less memory could result in some instability of the system. But simple projects could be done without problems.
If you have some money to spend, I highly recommend you using 128 GB or more if your motherboard allows it; and use Linux instead of Windows since Linux has better memory management for work in Houdini. Another useful thing that can be done in every project is to delete spare attributes and groups that were generated in the process and are not needed anymore to save memory and disk space on caches.
Thank you for reading this article, I hope it could help you in some way to achieve better results in your projects. Special thanks to the 80.lv team, Luiz Benassi for help with the Nuke comp, and Chris Hebert from Sidefx.