Ever stared at a 3D viewport, hoping to see realistic sand simulation pouring but instead got messy, intersecting particles? Simulating granular material in SideFX Houdini can feel daunting when you’re just starting out.
You might have followed tutorials that skip crucial steps or gloss over container setup, leaving you with unsupported grains or unstable results. Without a clear workflow, frustration builds and progress stalls.
This guide tackles those gaps by breaking down each stage of the hourglass sand simulation, from modeling the glass container to preparing particle attributes for stability.
By following a step-by-step approach, you’ll gain hands-on experience with essential tools, learn to adjust collision settings, and produce a smooth, realistic sand flow inside an hourglass.
What tools, files, and scene settings should I prepare before starting this simulation?
Before diving into the hourglass sand simulation, establish a consistent pipeline. Confirm you’re running a compatible build of Houdini (18.5 or later recommended) and have access to the Grain Solver in DOPs. Proper asset versioning and scene conventions prevent scale mismatches or solver errors later on.
- Houdini Tools: Houdini FX or Houdini Indie, Grain Solver DOPs, Python SOP (for custom seeding)
- Asset Files: Clean hourglass geometry (triangulated, watershed-UVs), sand particle template (.bgeo.sc), material library (glass shader, sand shader)
- Scene Settings: Metric units (meters), frame rate (24 fps), frame range (1–240), gravity vector (0, –9.81, 0), DOP substeps (4–8), collision padding (0.01 m)
Verify your file paths and environment variables (HOUDINI_PATH) to reference HDAs or custom shelf tools. Organizing these elements first lets you focus on solver parameters and caching strategies, rather than troubleshooting missing assets or mismatched scales during simulation.
How do I model or import the hourglass and prepare collision geometry for reliable sand interaction?
When starting your sand simulation, ensure the hourglass shell is watertight and scaled to Houdini’s unit system (1 unit = 1 m). You can model the glass in Houdini using a revolve pattern: draw half a profile curve in the XY plane and feed it to a Revolve SOP. If you import an external asset, use a File SOP and apply a Transform SOP to match scene scale.
Next, clean and thicken the mesh to avoid tunneling. Check normals with a Facet SOP (unify & recompute), fill holes via PolyStitch or Fuse SOP, then add thickness with a PolyExtrude SOP set to a few millimeters. This ensures the VDB conversion has volume to generate a stable SDF.
- Convert to a collision volume: use VDB from Polygons and set voxel size to around 0.002–0.005 for wall detail.
- Smooth the SDF: add VDB Smooth SDF to remove artifacts and guarantee stable collisions.
- In your DOP network, import this VDB as a StaticObject with SDF collision data feeding the POP Solver.
By following these steps, your grains will collide reliably with the inner glass surfaces, preventing leaks and ensuring realistic pile-up and flow behavior in the narrow neck of the hourglass.
How do I create and emit the sand using Houdini’s Grain/POP workflow?
Create source geometry and set emission attributes (density, velocity, rest)
Begin in SOPs by defining the sand volume. Place a Box or Volume container inside the hourglass region, then use a Scatter SOP to generate points (50k–200k) and enable relax iterations for uniform packing. Add an Attribute Wrangle to assign:
- pscale: particle radius (e.g., 0.002 for realistic sand size)
- density: material density (e.g., 1600 kg/m³ for quartz)
- rest: rest length, set equal to pscale so springs are uncompressed initially
- v: initial velocity vector (e.g., {0,0,-0.1} to drop grains downward)
Reference this SOP geometry in a DOP network using a Grain Object. In the Source tab, enable “Activate” and choose “All Geometry” for a one-time drop or switch to “Incremental” with an emission rate to simulate continuous pouring.
Configure Grain Solver core settings: particle size, mass, cohesion and friction
Inside the DOP network, add a Grain Solver and connect it to your Grain Object. Adjust these parameters for realistic behavior:
- Particle Size (pscale): match your SOP pscale; smaller values improve detail but increase compute
- Density or Mass: if you skipped @density, enter density (e.g., 1600) so mass = density×volume
- Cohesion: low values (0–0.001) introduce slight inter-grain attraction, preventing excessive dispersion
- Friction: controls sliding between grains and glass walls; 0.3–0.6 yields natural flow
- Separation Stiffness: increases spring strength in collisions to avoid interpenetration
Finally, increase the DOP network’s substeps (2–4) to stabilize collisions and consider enabling slight viscosity to damp jitter. Iteratively tuning pscale, cohesion, and friction will deliver a convincing hourglass sand flow.
How do I run, control, and cache the simulation for predictable results?
When you click Play in the Houdini timeline, DOP Networks cook on demand. For a stable run, set your global timeline frame range to match your simulation start and end frames, and switch Playback to “Play Every Frame” to force a full cook each frame rather than real-time. This ensures the solver has time for all substeps before advancing.
Inside the DOP Network, control resolution and accuracy via substeps and time scale. In the Grain Solver’s Dynamics panel, increase Max Substeps when collisions jitter or grains penetrate geometry. Use the “Time Scale” parameter to slow down the simulation for high-energy collisions, which reduces inter-penetration without raising substeps excessively.
Cache your sim to disk using a File Cache SOP or a ROP Geometry Output node. Point it at your DOP Import, set the file path to a padded frame pattern (for example $HIP/cache/sand.$F4.bgeo.sc), then define the frame range. Click “Save to Disk” to bake the geometry; subsequent playbacks simply read from disk, giving you consistent results and freeing the solver.
For reproducible behavior, lock down any random factors. In your Grain Source node, set the Seed parameter to a fixed integer so the grain emission and initial noise remain identical each cook. Avoid time-based expressions in attributes or noise patterns; if needed, use a Timeshift node to freeze procedural sources before they enter the DOP Network.
How do I shade, light, and render the sand and glass for a realistic final image?
Start by assigning a Principled Shader to both the sand and glass. For the sand material, enable subsurface scattering and set a low scattering radius (around 0.01–0.05 units) to mimic light penetrating grains. Use a noise-driven bump map: feed a low-amplitude Perlin or VOP noise into the Normal input to create micro-roughness. Adjust the Base Color to a warm beige and set Roughness to 0.4–0.6 for a soft matte look.
For the glass, create a separate Principled Shader with an Index of Refraction (IOR) of 1.45–1.50. Set Transmission to 1 and reduce Roughness to 0.0–0.02 for clear refraction. Enable Thin-Walled if you modeled only a single surface; otherwise, keep thickness and use the Volume tab to define glass thickness for accurate caustics. Add a slight tint in the Absorption Color to simulate real glass coloration over distance.
Lighting and render settings drive realism: add an environment light using an HDRI to capture natural reflections and diffuse sky light. Supplement with a rectangular area light above the hourglass to define highlights. In the /out context, use Mantra or Karma with path tracing enabled. Increase the Refraction and Reflection sampling to at least 32 to reduce noise in the glass caustics. Finally, enable deep shadow maps or ray traced shadows, and set Pixel Samples to 4×4 to strike a balance between quality and render time.
How do I optimize performance and fix common issues (tunneling, jitter, slow sim)?
Begin by balancing particle count and substeps: lower the Particle Separation in your Grain Configure or Vellum Configure to reduce total grains. Use packed primitives for collision proxies and cache out DOP networks early. Define a focused simulation region around the neck of the hourglass to avoid simulating empty space.
- Adjust Max Time Step and Min Substeps in the Solver to control integration precision.
- Enable per-frame caching (File Cache SOP) before heavy post-simulation nodes to skip re-simulation.
- Use the “Bounding Box” or “Volume Limits” in the DOP Import to limit data transfers.
Tunneling happens when fast-moving grains skip collision boundaries. In the Bullet or Grain Solver, increase the number of subdivision substeps or reduce the Maximum Time Step to 0.01 or lower. For Vellum, enable “Continuous Collision Detection” on the collision object and set Collision Padding to a small positive value to pre-correct thin gaps.
Jitter often indicates insufficient constraint iterations or overly loose rest lengths. In the Grain Solver, raise the Constraint Iterations to 10–15 and lower the Separation Scale closer to 0.95. In Vellum, increase the `velocity blending` and decrease `stretch stiffness` to damp rapid oscillations. You can also enable “Solve Interior Velocities” for more stable packing.
If your sim remains slow, try GPU-accelerated features: switch Vellum to OpenCL, or break your sim into smaller DOP networks and merge outputs. Cull static or off-screen grain clusters with a bounding volume and use a POP Wrangle to delete particles outside the visible region. Finally, monitor the Performance Monitor panel to identify node bottlenecks and iteratively refine.