Are you finding it challenging to recreate that signature Lush Cosmetics fizz in your own 3D scenes? Do complex particle setups and fluid simulations in Houdini leave you second–guessing your approach?
It’s easy to feel stuck when you can’t get the bubbles to pop or the surface to react like a real bath bomb. Inconsistent timing, noisy simulations, and unclear shading steps can bring any project to a halt.
This guide addresses those frustrations head–on by walking you through a clear workflow for a realistic fizzing bath bomb effect. You’ll gain the confidence to build each stage from scratch.
We’ll cover geometry setup, particle and fluid dynamics, shading, and rendering, with concise explanations of key concepts so you won’t get lost in technical jargon.
By the end, you’ll have a repeatable process for creating a high–quality CGI bath bomb in Houdini, ready to impress clients or add to your demo reel.
What reference images, scene scale, and assets should I collect before starting the Houdini workflow?
Begin by gathering high-resolution reference images of the Lush Cosmetics fizzing bath bomb from multiple angles—top, side, and especially the interior cross-section. Capture the powdery surface details, pigment swirls, and fizzing bubbles as they emerge in water. These references inform your Houdini procedural textures and simulation behavior.
Next, establish your scene scale to match real-world dimensions. A typical bath bomb averages 6–8 cm in diameter, so set Houdini’s unit system to centimeters and confirm object size in the Geometry node’s Display options. Accurate scale ensures correct pyro and fluid simulation resolution without overspending voxel memory.
Collect and organize essential assets:
- PBR texture maps (albedo, roughness, displacement) for the cracked shell
- Noisy height fields or voronoi patterns to drive surface fractures
- Low-poly proxy geo for early blocking and high-poly for final displacement
- Prebuilt foam and bubble particle setups or shelf tools to jumpstart fizz sims
Finally, source environment HDRIs and water splash references. A neutral studio HDRI helps test material response under even lighting, while water surface captures guide your FLIP setup. Having these assets ready streamlines your procedural workflow, letting you focus on node logic rather than hunting images mid-simulation.
How do I model the bath bomb and set up layered paint, seams, and UVs for simulation-driven emission?
Start by creating a polygonal sphere in Houdini, setting Rows/Columns to 64×64 for even topology. Feed it into a Subdivide SOP to smooth the surface, then add a subtle height variation with a Mountain SOP or VDB from Polygons workflow. This gives the shell a natural imperfection while maintaining clean UVs.
To define the seam and shell thickness, duplicate the sphere, scale the copy down by your target thickness, and run a Boolean Difference between the two. Group the resulting border edges with a Group SOP (Edge Group by border). Apply a PolyBevel on that edge group to simulate the narrow crack where the bomb will split, and name the group “seamEdges” for downstream reference.
Next, unwrap UVs for both inner and outer shells. Use a UV Texture SOP set to Polar to generate a base layout, then feed into a UV Flatten SOP, isolating each shell via primitive groups. Pack UV shells into one tile so that each layer can share a single UDIM. Store an attribute “shellID” (0 or 1) so shaders and solvers can distinguish inner from outer.
For layered paint and simulation-driven emission, paint masks in an Attribute Paint SOP, driving Cd and a custom float “layerMask.” Augment with an Attribute VOP or Wrangle to introduce per-point noise—remap noise to [0,1] for subtle variation. Export UV-based emission by copying “layerMask” into vertex. In your POP network or Pyro source, sample “layerMask” via uv space to control particle birth rate or smoke emission, ensuring paint dissolves realistically.
- Sphere SOP → Subdivide → Mountain
- Duplicate & Scale → Boolean Difference → Group (seamEdges) → PolyBevel
- UV Texture (Polar) → UV Flatten → Pack UVs → Attribute Create (shellID)
- Attribute Paint → Attribute VOP/VEX → Copy to vertex for emission mask
How do I create a production-ready fizzing particle system that mimics CO2 bubbles and effervescence?
POP network: emission sources, birth rate, velocity and buoyancy
Start by placing a POP Network inside your DOP context and connect a Source POP to your bath bomb geometry. Use surface emission to spawn particles along the dissolving shell. Drive your birth rate with an animating attribute (e.g., a ramp on dissolution progress) so fizz ramps up as the bomb dissolves.
- Initial velocity: randomize normals (0.1–0.3 units) via POP Source Velocity tab
- Buoyancy: add POP Force with negative gravity (e.g., -0.2) to simulate CO2 lift
- Drag: use POP Drag (0.1–0.2) to dampen acceleration and avoid jitter
- Turbulence: apply POP Wind or Gas Updraft for small eddies and swirl
VEX/attributes for per-particle lifetime, size, and color-driven emission control
Inside a POP Wrangle, initialize per-particle lifetime and size with VEX. For example:
- f@life = fit01(rand(@id), 0.5, 1.5); // randomize lifespan
- p@age = 0; // reset age on spawn
- p@pscale = 0; // start at zero for growth ramp
Then in your solver wrangle:
- f@age += @TimeInc;
- if(@age>@life) removeprim(0,@primnum,1);
- f@pscale = fit(@age,0,@life,0.02,0.1);
To drive emission from specific colored zones on the bomb, transfer the source’s Cd attribute into the POP Source’s emission group. In a wrangle:
- vector c = point(1, “Cd”, @ptnum);
- if(c.r < 0.2) @dead = 1; // only spawn where red channel exceeds threshold
This approach yields a nuanced, production-ready fizz simulation where bubble birth, growth, and buoyancy are all governed procedurally in Houdini.
How do I simulate surface dissolution and color dispersion into the water (coupling particles, VDBs, and FLIP)?
To recreate a fizzing bath bomb, we treat the solid shell as a dissolvable volume and couple its release particles to a FLIP fluid sim. First, build a VDB that defines where the shell thins out. Then drive particle emission from that VDB and transfer color attributes into the water via advected FLIP particles.
Step-by-step workflow:
- Generate a high‐res VDB of your bomb shell and remesh it with VDB Resample to control dissolution zones.
- Inside a POP network, emit “dissolve” particles where VDB density drops below a threshold using a VDB sample SOP.
- Assign a per-particle dissolveRate attribute based on local curvature or noise to vary fizz intensity.
- Use a Particle Fluid Interaction (PFI) DOP to push these particles into your FLIP fluid container.
- Advect a custom “color” attribute on FLIP using Gas Advect Attributes so the tint spreads naturally.
Create the VDB emitter by VDB from Polygons, then plug into a Volume Sample inside POP for birth mask. In DOPs, wire your POP Solver into a PFI Solver alongside the FLIP Solver. Ensure your dissolve particles carry Cd (color) and a density scalar. The PFI node will inject momentum and attributes into FLIP.
Finally, drop a Gas Advect Attributes node on the FLIP container. Specify Cd and density fields to be advected along FLIP’s velocity field. This captures the dispersion of pigment and fizz foam, giving you a realistic cloud of color swirling outward from the bomb’s surface.
How should I shade and light the bath bomb, bubbles and colored dye for photorealism (including AOVs and shader tips)?
Start by assigning a Principled Shader to the bath bomb core. Introduce a subtle cellular-noise-driven bump map to mimic the powdery surface. Enable Subsurface Scattering (SSS) with a low radius (2–5 cm) and warm midtone to retain the slightly porous look. Drive the SSS weight with a grayscale mask to confine scatter to the bomb’s interior and leave edges crisp.
For bubbles, build a two-layer surface: an inner clear water layer (IOR 1.333) and an outer thin-film layer. Use the Thin Film VOP to vary thickness (50–200 nm) via Perlin noise, producing realistic iridescence. Set specular roughness extremely low (0.005–0.02) and plug the film output into the layer’s coat weight. This yields sharp, prismatic rim highlights.
Shading the colored dye requires a volume shader. Export density and Cd fields from your FLIP sim and feed them into a Volume VOP. Implement Beer-Lambert absorption using an absorption coefficient vector matching your pigment. Combine scatter and absorption to control color saturation at depth. For backlit shots, add a weak emissive ramp to enhance translucency under strong key lights.
Configure AOVs to streamline compositing: create Ci_diffuse, Ci_specular, Ci_sss and Ci_volume AOVs in Solaris or Mantra ROPs. Output a separate Cryptomatte for each material to isolate passes in Nuke. Collect a Z-depth pass for accurate depth-of-field and volumetric fog integration. Finally, use a direct_light AOV to fine-tune rim and fill-light contributions without re-rendering.
How do I cache, optimize, and export simulation passes to keep iteration fast and compositing-friendly?
Long simulations can cripple your workflow unless you adopt a disciplined caching strategy. In Houdini, you want to separate heavy dynamics into discrete passes—geometry, particles, and volumes—so you can tweak one without re-simulating all. Use the File Cache SOP or a ROP Geometry Output for each pass, writing out compressed bgeo.sc for geometry and OpenVDB for volumes.
Start by running a low-resolution proxy sim. In DOP networks, reduce grid resolution or particle count with the Gas Resize Fluid Dynamic or Filter By Range nodes during early iterations. Once your timing and look are locked, step up to full detail and write out final caches. This two-tier approach slashes preview times.
- Use File Cache SOP with “Load from Disk” enabled to skip cooks.
- Crop volumes with the Crop node to limit VDB bounds.
- Pack points or use instancing for repeated fizz droplets.
When exporting for compositing, bake out motion vectors, depth, normals, and ID masks. In SOPs, use an Attribute Create node to store velocity (v), and export channels with a ROP Geometry Output, specifying “Add velocity as point attribute.” For volumes, convert density to .vdb and add temperature or temperature-to-color ramps if you need fire or color overlays.
To keep file sizes manageable, enable gzip compression on .vdb and .bgeo.sc outputs. For a more scalable farm workflow, integrate TOPs: dispatch your cache exports via the Geometry ROP TOP node. This lets you monitor job status, retry failed frames, and use HQueue without leaving Houdini.
Finally, organize your pass exports in a clear folder structure—/cache/lowres/, /cache/highres/, /export/geo/, /export/vdb/. Use consistent naming conventions: bathbomb_geo.$F4.bgeo.sc, fizz_vel.$F4.bgeo.sc, fizz_density.$F4.vdb. This ensures your compositing artist can reference each simulation pass unambiguously and hook into Nuke or After Effects with minimal setup.