Welcome to the blog post follow-up to our first Houdini tutorial on our YouTube channel.Â Below you will find all of the links, code, and information about thisÂ tutorial.

Â

Â

This tutorial breaks down a simplified version of an effect that we are using in an upcoming short-film that we are working on. It's super useful for creating magical disintegration effects.

Â

Â

It'sÂ also a common movie effect when you re-imagine itÂ a bit.

Â As seen in Vaseline's latest ad

Below you'll find a more in-depth explanation of each VEX snippet used.

Inside the solver, we have the following in our attribute wrangle:

Â

int pts[];

vector pos;

int maxpts = chi('max_pts');

float rad = chf('radius');

if (inpointgroup(0, 'spread_grp', @ptnum)) {

Â Â Â

Â Â @spread=1;

Â Â pos = @P;

Â Â pts = nearpoints(0, pos, rad, maxpts);

Â Â Â

Â Â foreach (int pt; pts){

Â Â Â

Â Â Â Â setpointgroup(0, 'spread_grp', pt, 1, 'set');

Â Â Â

Â Â }

}

Let's break it down.Â

Â

Â

Firstly, remember that this is run for every point, every frame.

Â

int pts[]Â is an array that is created. It is left empty but it will get points to place inside the array at every frame.Â

Â

vector pos is a vector that will hold the position of the currently processed point (Houdini runs through each point in a geometry stream/input systematically and the currently processed point can be fetched by using @ptnum).

Â

int maxpts is the maximum number of points that we will search for to infect at each frame.

Â

float rad is the radius (in Houdini units) around the currently processed point to search for our maxpts.

Â

chi('max_pts') andÂ chf('radius') are the two channel parameters to be created; an integer and float respectively. This means that you can adjust these parameters without actively changing the vex code.

Â

if (inpointgroup(0, 'spread_grp', @ptnum)) returns a 'true' or 'false' if the currently processed point from geometry stream 0 is in the group calledÂ 'spread_grp'. We know that the point that we created earlier is in this group, so this will return true for one of our points.

Â

@spread=1 sets the spread attribute to 1 for the point that is in the 'spread_grp'.

Â

pos = @P sets the pos variable that we created earlier to the position of the currently processed point (@P) which we know to be infected.

Â

pts = nearpoints(0, pos, rad, maxpts) populates our array that we created earlier. It uses the nearpoints function to take the points from geometry stream 0 (the attribute wrangle's first input) and place them into the array if they are within the radius (rad)Â and around our infected point's position (pos). Only find a maximum number of points decided by maxpts.

Â

foreach (int pt; pts) runs through all the points in our array called pts and assigns the current array value to the int pt variable.Â

Â

setpointgroup(0, 'spread_grp', pt, 1, 'set') is used to place each point that our foreach runs through into our 'spread_grp'. pt tells it which point.Â '1' is used to tell it that it must go into the group and then 'set' sets the value to 1.

Â

This runs every frame. It findsÂ points near our spread group to be addedÂ into the spread group and then sets their spread value to 1. The next frame it takes each of those newly added points and does it again. This creates the infection/propagation/spread effect that you see.

Â

This setup alone can do some interesting things. For example, dropping the number of max points (maxpts), deleting the uninfected points (delete points by expression: @spread<1) and then connecting the infected points with a 'Connect Adjacent Points' node creates an interesting growth network following a shape.

Â

Â

Â

Â

There are other ways to create a spread or propagation solver. Ben Watts has a great way to do it with VOPs over here.

Â

In the nextÂ attribute wrangles, we have the following:

Â

if(@spread>0){

Â Â setpointgroup(0,Â 'released_grp', @ptnum, 1,Â 'set');

}

Â

This is used to place each 'infected' point into a group called 'released_grp'. This is used to define which fractures are still part of the animation and which have been released so that they can be affected by wind and gravity.

Â

i@deforming=1;

f@mass=chf('weight');

f@density=0;

Â

These are the parameters used by the Rigid Body Solver.

Â

i@deforming is the parameter used to determine whether or not a piece of geometry is fixed to an animation or not.

Â

f@mass is the parameter used to give objects weight. When it is multiplied by density, the product of the two is the value used to determine if a piece of geometry is affected by wind/gravity/forces etc. If the value is greater than 0, the object will blow around, fall, etc. If it a value of 0, then all forces are ignored.

Â

f@density is the value that is multiplied by mass to give the value that determines weight.

Â

We set density to 0 because we want all of our points to be deforming but not be affected by gravity and wind.

Â

In the next attribute wrangle, we set the following for all released points:

Â

i@deforming=0;

f@density=1;

Â

Thus, our points no longer follow animation but and are now affected by forces. This allows pieces to fall away from the geometry as it breaks apart.

Â

All the links that are referenced in the tutorial are below:

Â

The phoenix geometry from Sketchfab is here.

Â

Houdini VEX documentation can be found here.

Â

Thank you for watching and reading!

Â

If you have any ideas or requests, please feel free to comment and we will get to them as soon as possible.Â

Â

Â