This repo contains documentation for the Procedural Rock Generator Tool in Houdini. There is no code associated due to Houdini's node network structure.
The Procedural Rock Generator allows a user to input a base shape to create procedural rock structures. Artists can edit multiple properties including target polygon counts, number of pieces created, and several noise settings. The tool creates both a high poly and a low poly version of the assets. The details of the high poly asset are exported as a normal map and can be applied to the low poly asset which has autogenerated UVs. The HDA can also be linked to a TOPS network for easy export.
Features include:
- Create a rock model from any input base shape
- Edit rock properties including target polycount, number of pieces, piece height ramp, and more
- Edit noise settings such as frequency, amplitude, and offset to get the perfect look
- Autogenerate uv maps for low poly assets and normal maps for high poly assets
- Export options auto center pivot and rotate for easy import into Unreal Engine 5
The basic worflow for the using the tool in Houdini to importing assets in Unreal Engine is as follows:
- Create or import a base shape mesh into Houdini
- Connect base mesh to the Rock Generator HDA node
- Edit any parameters as neccessary according to art direction
- HDA will output 2 meshes - high poly and low poly (low poly has autogenerated UV maps)
- Export meshes (Noncommercial Houdini only allows .obj format)
- I exported via a simple TOPS network pointing to the high res output and low res output of the HDA
- Export a normal map from the high poly mesh (this can be done through Houdini Labs Maps Baker node if not noncommercial version)
- Import low poly mesh into Unreal Engine (or both meshes if wanted)
- Apply materials and normal maps to low poly mesh
Here are some examples of the rocks in Unreal Engine 5. All materials and ground/sky assets are from UE sample Valley of the Ancient project.
The basic workflow of how the tool works is as follows:
- Connect input shape
- Create silhouette of base shape and move silhouette to ground plane
- Scatter points onto silhouette grid (number of points = number of pieces that will make up the final rock)
- Voronoi fracture based on the scattered points
- Add noise for variation of piece outlines
- Ray grid to base shape outline to get min distance and max distance attributes
- Create mask attribute based on the min and max distances
- For Each Connected Piece loop
- Randomly rotate to create variety
- Randomly scale to create variety
- Voronoi fracture to create rock like cracks and blocks in the final shape
- Delete small prims to ensure mesh integrity
- PolyExtrude based on mask attribute
- Mountain node to create variation in overall shape
- VDB -> Convert VDB to smooth out intersections
- VDB Fog volume -> Convert VDB
- 3 Volume Vops containing different noise volumes for large details
- Noise via attribute vops to create large and small rough patches (cuts) into rock
- Delete small parts to ensure rock integrity
- Move mesh to center and rotate z up to prepare for export to Unreal (these steps can be turned off via a parameter)
- Normal node
- HIGH_RES_OUT
- Remesh with target polygon count as a parameter
- Auto UV
- Normal node
- LOW_RES_OUT
Base meshes can be very simple. The tool measures height data by creating a silhouette grid on the ground plane and measuring the ray distance between the grid and the original mesh. A mask attribute is then created with minimum and maximums set by the height data. This mask attribute controls the height of each piece when it is polyextruded upwards. This attribute can be controlled by the artist via a ramp parameter. This allows for different height data trends, such as linearly going from minimum height to maximum height, creating sharp contrasts between min and max height, or favoring one end of the spectrum (more taller heights vs more shorter heights).
Here is an example of the autogenerated UV maps for the low poly assets. There are several settings in the Houdini AutoUV node that can be altered for better maps. I chose UV Autoseam for this process as it was faster than shortest path and created evenly shaped islands. I turned on merge small islands and tried to add a lot of island padding so that the normal maps would not blend islands together as easily. It's not perfect and there is some stretching but it was good enough for these environmental assets.
I went through several iterations of this tools in order to match artistic direction. At first the artists mentioned they wanted a rock generator for assets that would be scattered on the floor of a canyon level. Due to schedules and time zone delays, I wasn't able to get concept art at the beginning. This was my first attempt at a procedural asset generator that would include low and high poly assets so I wanted to get started in order to understand that workflow. This was my first iteration of a rock generator:
After getting feedback and some concept art images, I realized they wanted larger rock shapes. This was my second iteration where I mostly focused on getting a similar base shape:
After sending to artists, they approved of the base shape but did not think the noise was matching their vision. I agreed that the noise needed to be more rock-like to match the concept art. For the final iteration, I focused on combining a lot of different noise techniques to get blocky, sharp cuts and horizontal striations into the rock shape. This is an example of what can be created in my final tool iteration:
I ran into several limitations I did not prepare for in this project. Since this was my first time exporting assets outside of Houdini for use in another DCC, I did not realize the restrictions in using Houdini non-commercial. There were two main problems:
- Normal maps exported directly from Houdini had a big watermark that would affect assets in Unreal
- Assets could only be exported as .obj files Since this project is strictly a hobby project and we do not plan on getting any monetary gains with it, we did not have the funds to buy Houdini Indie nor thought it was necessary for this project.
In order to solve this issue, I tried several different DCC's to create the normal maps. First, I tried using Maya to bake the normal maps by importing the high and low poly assets. However, the results were very sharp and harsh. The artists and I agreed the maps from Maya would not suit our needs. After researching online, I found that the free xNormal program could fix our problem. I tested by comparing xNormal's output with Houdini's output and they were very similar. After confirming with the artists that the xNormal maps were suitable, we were able to create our normal maps without the watermark.
I did not have access to Adobe products for this project but in the future, I would like the try using Substance Designer or Painter to solve this issue because those are industry standard tools.
The artists on the project preferred using FBX file format. When I communicated this limitation, we talked about the differences between .obj and .fbx and what we needed for these particular assets. For example, these assets had no animation or scene data associated with them. The most important attributes to transfer were geometry data and uv data. Both of those aspects were available in obj format. As a result, at least for the first iteration, we decided that .obj was okay for these environmental assets.
Even though we are able to use .obj, I am working on a lightweight batch export tool to import these models in to Maya and export them as .fbx. This is also a workaround that artists can do manually if necessary.
I am working on getting blockouts for the specific level in our game from the artists. Once I get the base shapes, I am going create 1 to 2 variations for each shape using wedge attributes in a TOPS network. We are also discussing how many polygons we want for these assets. Since our team is using nanite, we can push the asset count higher to ~300k. For small to medium assets, this can eliminate the need for the low poly assets which speeds up the creation process.