Digital Artists

Growing a Branching Network, Then Making Smoke Follow It

Karlis Stigis rasterises a space-colonization solver's branches into a velocity field and feeds it to Houdini's Pyro solver with Copy — then switches between ten networks to kill the loop's repetition.

Smoke simulation is easy to start and hard to direct. You get beautiful turbulent behaviour almost immediately and then discover that you cannot make it go where you want, because the solver’s job is to obey fluid dynamics rather than your composition.

Karlis Stigis, a 3D and motion designer based in Nuremberg, has a clean solution: grow a structure first, then make the smoke follow it.

The space colonization solver

The algorithm is from plant biology and it is three steps repeated:

  1. Search — active points find unused neighbours within a fixed radius
  2. Connect — each neighbour chooses the closest proposing parent
  3. Advance — newly connected points become active

That is it. From a seed and a cloud of target points you get a branching network that fills the available space without crossing itself, because every target point is claimed exactly once.

It is the algorithm behind most procedural tree and vein generation — originally from Runions et al.’s 2005 work on venation patterns and leaf veins, and it produces structures that look organic for a specific reason: competition for space is what makes real branching look the way it does. Branches do not grow into regions already served by other branches, in trees, lungs, river deltas or lightning.

Implemented in Houdini geometry nodes, which is the natural home for an iterative point-based algorithm like this.

Turning branches into smoke direction

Here is the part worth copying, and it is specific:

  1. The branching network provides velocity vectors along its paths — each branch segment’s direction is a vector
  2. Those are rasterised into a volume field using Volume Rasterize Attributes
  3. The result is merged with density and temperature fields from the emission points
  4. That velocity field goes to the Pyro Solver with the operation set to Copy

The Copy operation is the whole trick. Pyro’s source volume can be combined with the simulation’s existing velocity in several ways — add, maximum, and so on. Copy replaces the velocity in the sourced region on every substep.

Which means the branch directions are continually reinforced. If you used Add, the solver’s own advection and turbulence would progressively overwhelm your authored direction and the smoke would wander off the paths within a few frames. Copy overwrites, every update, so the smoke keeps being pushed back onto the network no matter what the fluid dynamics would rather do.

It is an authoritarian approach to direction, and that is why it works for art-directed smoke. You are not persuading the solver; you are overruling it in the region you care about and letting it behave naturally everywhere else.

The looping trick

The problem with a velocity field driven by one static network is that the motion becomes predictable — the smoke learns the paths and the shot stops developing.

Stigis’ answer: generate ten network variations from different random starting points, and during the animation use a Blast node expression that switches between networks at an increasing rate, selecting one at a time.

Two things that makes work:

The directions keep changing, so the smoke is repeatedly re-steered rather than settling into a groove. The motion stays dynamic and reads as less repetitive.

And the increasing rate gives the shot an arc. Slow switching at the start, faster toward the end, is a built-in intensification — the piece accelerates without the emission or the turbulence changing. For a loop, that is a way of getting development out of a system that has to return to its beginning.

Rendered in Solaris and Karma.

The generalisable idea

Use a procedural structure as a force field.

That is the pattern, and it applies far beyond smoke. Any solver that accepts a velocity, force or target field can be steered by geometry you generated separately:

  • Curves from a space-colonization or L-system growth, driving smoke, fire, or particle flow
  • A mesh’s normals rasterised into a volume, to make particles crawl over a surface
  • An SDF gradient, to push a simulation toward or away from a shape
  • A vector field derived from a drawing, which is how you get a fluid to spell a word without keyframing anything

The separation is what makes it controllable: one system decides where things should go, a different system decides how they move. Trying to make one solver do both is where art-directed simulation usually goes wrong.

Worth reading alongside the Houdini primer we published last week if the node names are unfamiliar — and the bubble solver built from Wētā’s research for another case of an artist building the solver rather than using the shipped one.