Modeling in Houdini using VDB SDF volumes

Tutorial / 14 May 2023

People in Modeler for Houdini Discord group were interested in SDF boolean operations. So, I created a simple example of SDF usage and shared some of my notes.

There are two versions of the same example file:

VDB_SDF_Modeling.hiplc - The original file, but it contains nodes from the Modeler 2023.4 plugin.

VDB_SDF_Modeling_Stashed.hiplc - A copy of the first file where I replaced all operations from the Modeler 2023.4 plugin with Stash nodes.

If you do not have a Modeler plugin, then download the second file, and you will still get an idea of boolean operations using SDF volumes.

The file contains examples of using the following nodes and operations:

VDB from Polygons (to convert polygonal geometry to SDF volume).

VDB Smooth SDF (to smooth edges of geometry similar to the results from polygonal round bevel).

VDB Resample (to change voxel density to increase object detail).

VDB Combine (to apply boolean operations: SDF Union, SDF Difference, SDF Intersection).

VDB Reshape SDF (to expand or narrow voxel shapes, similar to the Peak operation).

VDB Convert (to convert SDF into polygonal geometry).

Volume Deform (to deform voxel shapes by using Lattice from Volume node in conjunction with Bend node to deform point grid which represents the voxel grid).

Name and Attribute Edit String (to build a hierarchy of LOP primitives while working in SOP)

Notes about using SDF nodes:

  1. Increase voxel density only when necessary. Generally, I used a "voxel size" of 0.02 when converting geometry through "VDB to Polygons" and could move shapes interactively. However, in some cases, I needed narrower or smaller bevels and increased density to 0.01 voxel per unit in exchange for performance.
  2. After all operations, you can increase voxel density through the "VDB Resample" to get a denser and more detailed polygonal mesh from "Convert VDB".
  3. Use different smoothing modes to maintain performance. Instead of increasing the number of smoothing iterations in VDB Smooth SDF, try changing the operation type: Mean Value for normal smoothing, Gaussian for strong smoothing, Mean Curvature Flow for weak smoothing or smoothing small details.
  4. If you need to place one object inside another, for example, a button in a housing, use VDB Reshape SDF to expand the SDF before boolean subtraction.
  5. I didn't find a way to store color in SDF and pass it through boolean operations, so after converting to polygons by "Convert VDB", I used the "Bounding Volume" parameter in the "Group" node to select the area that I want to color using SDF volume.
  6. Deform objects in voxels through "Volume deform" instead of deforming them in polygons. This is convenient because the bend deformer, when used on polygons, will not be able to bend the area where there is not enough geometry, but through Volume deformation, you bend a point grid, so you can bend and deform even each pair of voxels.

Notes on modeling in SOPs within LOPs:

  1. To improve performance, prevent SOPs from constantly transferring data to LOPs. To do this, place the "Output" node inside the SOP and connect the geometry only when you want to transfer it to the LOP; otherwise, keep the geometry disconnected.
  2. The same goes for working inside the "Component Geometry" node: connect geometry to the default, proxy, and simproxy output nodes only when necessary; otherwise, the entire node tree will be recalculated with every change.
  3. Start building a hierarchy of LOP primitives while still in SOPs. Hierarchy construction will occur from top to bottom, from leaf to root. At the beginning (for leaves), add a "Name" node to create the corresponding attribute and enter the geometry name into it, for example, Mesh. Then add an "Attribute Edit String" node, specify that you want to edit the "Name" attribute, and in the Editor tab, set "*" (all existing names) in the "From" parameter. To the "To" parameter, add the name of the LOP primitive where you want to place the geometry, like "Primitive/*". Thus, the Name attribute will become "Primitive/Mesh". Further, continue adding Attribute Edit String nodes with the same parameters to assign more parents or group primitives after merging. The last Attribute Edit String will have the "/*" name set in the "To" parameter and will close the path (for example, "/Gamepad/Triggers/Primitive1/Mesh").

I've used the video as a reference for the model.