Thursday 23 November 2017

multiple colour sets on alembics, for Maya

This probably contradicts something I've written before, but you CAN export multiple colour sets in Houdini, for alembicking. The key is in the attribute creation. Make sure you use an explicit attribute create node, specify a float, of colour type. Oh and make sure it's on the vertices, because Maya. It will now show up along trusty ol' Cd in Maya's Color Set Manager.

Thursday 9 November 2017

alternative to copy stamping

Copy Stamping is a bit slow, here's another way of copying things using point attributes.
EG - a bunch of points comprising of cubes, spheres and donuts.


  1. get a bunch of points!
  2. give them an id attribute eg 1,2,3,4..which will represent cube,sphere,donut. The attribute randomise node is quite good for this. There is a setting called Discrete Values which you can tweak with weighting. Eg. 20% value 1, 40%value 2, 40% value 3. Lets call the attribute ID
  3. Create a For-Each-Loop network. Set the mode to "points". By default it is set to process "pieces". Uncheck the use "name" bit. This is to do with the fracturing rigid body workflow.
  4. Connect the cube, sphere and donut to a switch node. In the index box type: point("../foreach1/",0,"ID",0)    this references the current point being processed by the foreach loop and reads it's corresponding ID value.
  5. Inside the foreach loop add a "copy to points" node. Connect the switch node to this.
  6. This should all work now!

Friday 29 September 2017

VOP For Loop usage

The inputs of the VOP For Loop are a bit annoying.
Length - this is the number of loops to be made. It is the i<10 part of the loop.
Index - you don't have to set this unless you need to start with a value other than 0. eg, you want to start the loop with for(i=3;i<............)
The rest is just for any attributes/values you need to use.

connecting points again..


Here're two expanded ways of connecting groups of points together!




The first method relies on you creating an attribute in a preceding point wrangle called "id". This is the value you'll search for, when making connections. The "destination" points go into the first input, the origin points go into the second.

int count = findattribvalcount(1,"point","id",i@id);

for (int i = 0; i < count; i++) {
    int find = findattribval(1,"point","id",i@id,i);
    
    int prim = addprim(0,"polyline");
    
    vector p2 = point(1,"P",find);
    
    int pt = addpoint(0,@ptnum);
    setpointattrib(0,"P",pt,p2);
    
    addvertex(0,prim,@ptnum);
    addvertex(0,prim,pt);
}


LINE BY LINE

int count = findattribvalcount(1,"point","id",i@id);
//count number of points that have the "id" value
for (int i = 0; i < count; i++) {
//start for loop, for the number of points it has found
    int find = findattribval(1,"point","id",i@id,i);
    //get point number for point that has the id value. The last i is the index of the for loop.
    int prim = addprim(0,"polyline");
    //add primitive, of polyline type
    vector p2 = point(1,"P",find);
   //create position vector based on point number found 
    int pt = addpoint(0,@ptnum);
//create point at the position of current point
    setpointattrib(0,"P",pt,p2);
    //set position of just created point to the vector created
    addvertex(0,prim,@ptnum);
//add vertex to the primitive at current point position
    addvertex(0,prim,pt);
//add vertex to the primitive at found point position
}





This method doesn't need the "id" value, but just grabs the closest point to it. Again the many destinations go into the first input and the few "origins" go to the second.

int nearpt = nearpoint(1,@P);
int prim = addprim(0,"polyline");
vector p2 = point(1,"P",nearpt);
int pt = addpoint(0,@ptnum);
setpointattrib(0,"P",pt,p2);
addvertex(0,prim,@ptnum);
addvertex(0,prim,pt);


LINE BY LINE

int nearpt = nearpoint(1,@P);
//get id number of point from second input to currently processed point's position
int prim = addprim(0,"polyline");
//create primitive of polyline type
vector p2 = point(1,"P",nearpt);
//set vector to nearpt's position
int pt = addpoint(0,@ptnum);
//add point at currently processed point's position
setpointattrib(0,"P",pt,p2);
//set position of new point to position of nearpt.
addvertex(0,prim,@ptnum);
//add vertex at currently processed point's position
addvertex(0,prim,pt);
//add vertex at nearpt's position

Wednesday 27 September 2017

writing alembics for maya - path attribute

Covered this in an older post, but this is for more straightforward cases when you want to define a group and shape node name for Maya purposes. We do this to avoid multiple shape names in Maya (eg. lots of pSphereShape1's or multiple Houdini Merge listings ; Alembic will take whatever the penultimate node to your ROP-alembic is called!)

In a primitive wrangle, this bit of code will create two text entry boxes, so you can input a group name and a shape name. If you were to call the group "squareGrp" and the name "square", then the resultant hierarchy would be "squareGrp/square/squareShape" in Maya.


string group = chs("MayaGroup");
string name = chs("Name");

group += chs("groupSuffix");
name += chs("geoSuffix");

s@path = group + '/' + name + '/' + name + 'Shape';


Remember to tick the "build hierarchy" box in the ROP-Alembic node & also to tick "use path".

Saturday 16 September 2017

Entagma snippet : drawing lines between a set of two points

This is useful when you want to connect two bunches of points together.. You'd think it'd be easy right?

Scatter, say 50, points on a grid. Then another 50 on another grid (or any shape..it doesn't really matter). Move them about a bit, then plug them both into a point wrangle (first two inputs).
This code will draw a single primitive edge between the points, paired by @ptnum (so you could do some sort of sorting beforehand, I guess):


int npnt=addpoint(0, @opinput1_P);

int nprim=addprim(0,"polyline");

addvertex(0,nprim,@ptnum);

addvertex(0,nprim,npnt);

Lets tackle each line.

int npnt=addpoint(0,@opinput1_P);
First we make a new point. Point wrangles only ever consider the first input's points. So we need to add the other input's points into the mix. I think the 0 corresponds to the @ptnum attribute.. So it looks up the relevant point in input1 and then puts it at the position specified by "@opinput1_P". That's a handy bit of VEX shortcutting there.

int nprim=addprim(0,"polyline");
Here we are creating a new primitive, of polyline type. Nothing is there yet...

addvertex(0,nprim,@ptnum);
Now we add a vertex to the primitive we just created. Firstly, we add the point we're currently processing.

addvertex(0,nprim,npnt); 
Next we add the vertex we added at the beginning (our currently processed point's counterpart in the other group).

That's it!

set colour according to bounding box.

now that the old Point node is more or less dead and buried, we have to rely on wrangles or vops to set our colours in fancy ways.

To give an object a gradient of colour based on it's bounding box (eg. black-to-red, from -ve to +ve on the x axis) we can use the relbbox function.
In a wrangle, we can type

@Cd=set(relbbox(@P.x),0,0);

tadah!

Tuesday 15 August 2017

Shattering an animated object. Eg. flying saucer smashing into something

Say you want to make a moving object smash into bits. Eg. A flying saucer that's been hand animated, which then needs to break apart dynamically.
As usual this isn't going to be straightforward :)

Shatter and pack geometry as usual, only what we need to do is ensure the points are not active. You can be double sure by laying down a point wrangle and setting i@active=0;

In your DOP network, make sure the RBD is not an active rbd as initial state. Set it to deforming static object. This should be done in the drop down menu. Now if you hit play, the object should not simulate at all & only follow it's given animation. "Overwrite Attributes" is NOT ticked.

We will use a sop solver & a point wrangle within to set the active value to 1. I've found using an activating shape like a box to set points into a group (using the bounding option) works best for this. eg. the saucer rbd points don't become active until they pass through said box. The attribute "deforming" (an integer) must be set to 0 once the "active" value switches to 1. This is so it no longer animates, or as Houdini refers to it, "deforms".
We use a sop solver so that the active value stays at 1 and doesn't reset to 0 once it passes through the activating shape. What we also need to do is use this sop solver in conjunction with the Bullet solver. This is done with a multi-solver.

Things I've found that are a bit problematic are glue constraints... Will look into this.
Update on glue - 

Houdini 16.0.504.2 has a weird thing... The Constraint Network's "Overwrite with SOP" attribute's default value is supposed to only import the SOP on the first frame...but it seems to behave as if it's always importing it. As a result, set it to 0 (zero), so that the animation of the object is ignored. This seems to make the glue constraints work properly.

https://drive.google.com/file/d/0B2eKYZ42BvalZnFaY0NZMkhwb3M/view?usp=sharing

Monday 17 July 2017

pyro - "custom wind volumes"

Sometimes you want to have pyro behave a certain way in a certain area. Eg.  the smoke should go from left to right, then suddenly shoot upwards after a few seconds.

Instead of fiddling with the advection or velocity updates, it's a bit simpler to create a separate pyro source that only emits velocity.
Simply create a source as you normally do, but remove it's density & temperature. Remember to scale these to zero in the DOP area too!

Friday 23 June 2017

latticing VDBs/volumes

Bring in your VDB however you need to.
Plug it into a VolumeVOP and create an addpoint node. Plug P into the ptvalue input.
Next create a setattrib node and plug your addpoint's ptnum output into the setattrib's i1. Plug your density into the value node and name the parameter "density". Jump back out of the VOP.

This will have made a volume grid of points that represent your VDB, each containing the corresponding density value. The number of points created is dependent on the resolution of your VDB, although I guess you could duplicate points and hope that they interpolate nicely?

Next, add a Timeshift node after the VOP and freeze your volume at the point you think it occupies the most space. Eg. if it's a trail of cigarette smoke, it's last frame. Create a Bound node for this.
This is now the lattice you can transform and deform.
Then make a Lattice node and plug your Volume VOP into the first input, the output of the Bound into the 2nd and then finally whatever your transform/deforms are into the 3rd.

So far, we've transformed a bunch of points, that hold our density values.. Now we have to recreate our volume..


Connect a Bound node to your deformed points. We're making an empty volume that encompasses the limits of your deformed sequence. Add an Iso Offset to this, set the Output Type to Fog Volume, Mode to Ray Intersect and name it Density. You control the effective resolution with the sampling. Next let's copy the density back into your empty volume.

Make a volume VOP, plug the Iso Offset into the first input & the lattice into the second. Jump in and make a Point Cloud Open node. Connect the P to the P and the OpInput2 into the File input.
Create a Point Cloud Filter and set it's signature to Float Channel and label the Channel "density". Plug the Point Cloud Open's handle into the Point Cloud Filter's handle input. Finally plug the value into the volumevopoutput's Density..

Your blank volume now has a deformed version of the original's density!
Sit back, relax and pretend you're resimming now.

Tuesday 20 June 2017

Pyro UPRES

Setup a Pyro as you would normally..This will be your low res sim. In a Geo sop somewhere, make a DopIO node and choose the pyro preset to make sure you're importing all the required fields from the low res sim. You could file cache this out..

Then..make a new Dop network. Inside this, create a smoke object and plug it into a Gas Upres node.
Point the Gas Upres node's Initial Data/Low Res Sop Path to a DopIO node you made earlier. Alternatively if you've cached it out to VDBs or bgeo.sc's you can switch the source to "file" and point it to that cache.


I've found that putting a copy of your low res sim's Source Volume helps a lot. Plug that into the last input of the Gas Upres. Switch it's Velocity setting to COPY, since you'll want to copy it from the lowres sim.

You might have to play with the smoke object's initial size settings, so that it encompasses your entire sim size. Oh - and change the division size to your desire resolution..we are upres-ing after all.

Mess around with extra dissipation or turbulence in the Gas Upres node...

That should be it.

Monday 19 June 2017

Pyro.. without shelf tools

Setting up Pyro manually...


  • You'll need to plug your emitter geometry into a Fluid Source node. You might want to turn off empty interior. As always, label with a null. OUT_SOURCE. Add a scalar volume and label it temperature. Your pyro won't react properly to buoyancy otherwise. THANKS HOUDINI.
  • It's a good idea to create two bounding boxes - one for the source, one for the padding. Make the padding way bigger than the source, freeze the time so it doesn't jump around in the simulation. You don't have to freeze the source bounding box as the solver only takes the first frame anyway. Label them with nulls, with something like OUT_BOUND and OUT_PAD.

  • Inside a dopnetwork -
  • You need a Source Volume node. use your OUT_SOURCE as your volume path. Initialise it to Source Smoke. Set the Velocity to Add. Otherwise it will just keep overriding the velocity.
  • You need a Smoke object. You might as well link the Division Size to the same parameter in the Fluid Source you created earlier. For the size and centre parameter boxes, use these respective expressions with the relevant paths and axis variations - 
bbox("../../geo1/OUT_BOUND",D_XSIZE)
centroid("../../geo1/OUT_BOUND",D_X)

  • In the Creation tab, you'll probably want to tick ON Solve on Creation Frame. This gives the system some density on frame 1, so it won't immediately shrink and implode on itself.
  • Next you need a Gas Resize Fluid Dynamic node. This just keeps track of the size of the simulation. Tick ON Clamp To Maximum, set it to From Object and point it toward OUT_PAD. Nice and easy, no expressions required. You still might have to faff with the padding values in the Bounds tab....
  • Lastly, but not least - you need a Pyro Solver node. Plug the Smoke Object into the first input, the resize into the second and the Source Volume into the last.
That should all work! The Solver contains most of the turbulence/shaping controls for the simulation.
You now have a basic pyro setup without using shelf tools. YAY.

Monday 12 June 2017

random rotation with POPs

To get random rotation with POP particles, add a point wrangle at SOP level with a more specific version of the following code-

v@w=rand(x-value,y-value,z-value);

Then in the dop network, add a POP-torque node and set the amount to zero, so that it takes the initial "w" value. "w" is angular velocity..all according to keikaku.

Thursday 8 June 2017

installing QLIB...what to stick in your houdini.env file

#QLIB
QLIB=C:/Users/threedee/Documents/houdini16.0/qLib-dev
QOTL=$QLIB/otls
HOUDINI_GALLERY_PATH = &;$QLIB/gallery
HOUDINI_OTLSCAN_PATH = &;$QLIB/otls/base;$QLIB/otls/future;$QLIB/otls/experimental
HOUDINI_TOOLBAR_PATH = &;$QLIB/toolbar

Monday 22 May 2017

voronoi fracture woes & exporting alembics to maya

Voronoi fracturing is often used to create destruction fx. It also creates a lot of dirty geometry, which leads to pain when exporting your geometry to Maya -

"UVs aren't per-vertex or per-polygon per-vertex, skipping"

 This also plays havok with motion blur and any other vertex attributes you might have in play.

Using a For-Each loop, or For-Each subnetwork (if using the subnetwork, attach a Connectivity SOP first, with a "class" attribute, so the For-Each knows what pieces to run over. You type "class" into the Attriubute field of the ForEach Subnetwork parameter box) use Clean SOPs to fix any nasty geo that might have been generated. You'll want to tick most of the boxes - your mileage may vary with the Non-Manifold option.

This probably won't fix the problem still - the fracturing process can make a lot of stray edges - 2 point primitives, which don't play nice.

drop down a Primitive Wrangle and use this code-
i@vertnum = primvertexcount(0,@primnum);

It creates a variable called vertnum that counts how many vertices you have in each primitive.

Follow this wrangle with a blast that has
@vertnum==2
in it's Group box. This will kill any stray edges & hopefully fixes everything!

Tuesday 16 May 2017

Getting data from strings

for example, once you've shattered something you end up with a lot of "pieces". Piece1, piece2, piece56000.
You might want to use the number as a seed value.
Usually the piece number is stored in the @name attribute.
In a wrangle, you can strip out the word piece, as follows... (and use atoi, to convert the string number to a number number)


s@testval=s@name;

@testval=strip(@name,"piece");
f@randval=rand(atoi(@testval));

voronoi shatter pieces not staying as a chunk

Sometimes..most of the time, your voronoi shatters that have thickness won't behave correctly. The sides will fall off. Boo.
What you have to do is run all the pieces through a Foreach loop and Fuse the verts back together.

This could go just before your assemble node

Sam's Rigid Bodies notes

Backup of Sam's Rigid Bodies notes

Rigid Bodies

General


When creating a rigid body object the main ingredients to create anything dynamic is to have the following nodes: RBDpackedobject, rigidbody solver (not rbd solver), gravity, groundplane, merge (to merge groundplane and gravity), output.

When Houdini computes rigid bodies for collisions, it converts them to convex hulls. Convex hulls is like creating a sphere around your geometry and shrink wrapping it around your geometry. The geometry won’t be perfect but it will try to be as close to your original geo as possible. You can change the method of the geometry representation in the rbdpackedobject DOP. This can be changed to things like sphere or boxes depending on your desired simulation look.

When working with packed geometry all points are 4x4 transformation matrixs. It looks something like:

[X] * [ 0.0 0.0 0.0 0.0 ]
[Y] * [ 0.0 0.0 0.0 0.0 ]
[Z] * [ 0.0 0.0 0.0 0.0 ]
[1] * [ 0 0 0 1    ]

Green means rotation and red means translation. The X Y Z 1 represents each point. The bottom numbers aren't anything you need to worry about.

Voronoi Fracturing Geometry

Random Fracturing - Iso offset

When fragmenting your geometry, place an isooffset and then a scatter. This will place points inside the geometry instead of on the surface. These points you create will kind of be the center of the vorononi pieces.


When scattering you can turn on relax iterations, this will recompute the point placements when changing the amount of points on the geometry. You can add a noise deformer under the isooffset SOP to break up the scatter placement of the points.

Plug in a turbulent noise and clamp it between 0, 1 or max it with a constant. You can also plug a ramp parameter after the max DOP to push the low and high values, just like a remap in maya.

If you want to break up certain areas on top of the original voronoi fracture, you can create a foreach loop.

Inside the foreach loop, place a null, scatter and a voronoi fracture. Plug foreach_begin into the null > scatter > voronoi fracture 2nd input. Plug the foreach_begin into the first input of the voronoi fracture. On the for each begin, click create meta import node.

On the scatter node, scatter the points by density instead of force total count.

Create a switch node and plug in the foreach_begin and voronoi fracture and type the following into the select input:
rand(+3008+detail("../foreach_begin1_metadata1/", "iteration", 0)) < 0.4 && npoints("../scatter4/") > 1.

You can change some of the values to get the desired look you want.

On the foreach_end change the attribute to name.

NOTE: It’s a good idea to push more scatter points across the area of impact.

Precise Fracturing Points - Painting


If you want to create an even more precise voronoi you can paint where you would like more fracturing to happen.

To do this make sure your geometry has enough detail as you will be painting directly onto the points., if it is quite a low detail you can place a divide and turn off convex polygons and turn on bricker polygons.

Once you are happy with the detail of the mesh, place a paint node down. Paint on the mesh with a white brush where you want more detailed fractures to happen.

Then place a point wrangle and type the following:
@Cd = lerp(@Cd.x,1,ch("blend"));

This will blend the white and black parts of the mesh so there is a gradient of points/fracturing. You can then place two blast nodes down and separate the white and black into two separate branches. Use @Cd.x>0.5 & @Cd.x<0.5 to do this. Make sure to change the blast to points.

Place a scatter after each of these and then type in the desired amount of points you’d like to scatter in the more condensed (white) areas and the less condensed (black) areas. Once you're happy with the amount of points merge these two back together.

Then place an attribute randomise down with the attribute name “rep”, change the max value to something like 10.

Place another attribute randomise and give it the name “pscale”, increasing the min value.

You can also place a point replicate to replicate points around the points you have created. If you do this, you can change the method to a shape instead of quantity.

After this place your voronoi fracture. You can change the look of the fracture by going back to the paint SOP and painting certain areas differently, or you could change the scatter amount on the less dense areas for example.

Precise Fracturing Points - Procedural


If you want to create an even more precise voronoi you can paint where you would like more fracturing to happen.

To do this, place an add node or curve. For the point method, add your point and turn it on. Use a transform node to where you’d like the more precise fracture to happen. For the curve, draw your nurbs curve to whatever shape you want and resample the curve.

From the geometry, place a polygon to VDB on a separate branch. Lower the value of the VDB to get a higher resolution VDB. Also change the the VDB to fog.

Then place down a volume VOP and plug the VDB into the first input and point or curve into the second input.

Inside the volume VOP place a pcopen VOP and plug in P and second opinput, promote the radius and maxpoints. Double click on the promoted radius so the parameter node appears.

Then place a pcfilter after the pcopen and a pcnumfound which will also go after the pcfilter in a separate branch. Add a compare after the pcnumfound and change the test to greater than.

From the pcfilter add a distance into the second input, “P” from the global input goes into the first input. From the distance, add a fit range and plug it into the first input. The second input will be radius parameter that was promoted earlier.

Finally, multiply the fit range against the compare VOP and plug the multiply into the global output.

To break up the edges of where the smaller fractures will be, you can add a turbulent noise and add it to the multiply that you have created.

On the SOP level you can change the search radius so the search area is larger or smaller, depending on your desired look.

Place a scatter node after the volume VOP. From your VDB from polygons, place another scatter node down on a separate branch. Change the force total count on both these scatter nodes and merge them together. Remember to turn off relax iterations.

On the second branch you can place an attribute randomise down with the attribute name “rep”, change the max value to something like 10. Change the dimensions to 1 as it is a float.

Place another attribute randomise and give it the name “pscale”, increasing the min value. Change the dimensions on this 1 also as this is a float.

You can also place a point replicate to replicate points around the points you have created. Turn on generate from attribute and type rep. Then you can increase/decrease the points per point.

Finally, voronoi fracture the scattered points.

Creating the name attribute


If you are going to fracture some of the pieces that you have already fractured like the random fracturing method above, you won’t be able to rely on the name attribute. To get around this, place a connectivity SOP and change its method to primitives. Then a point wrangle and type the following:

s@name = sprintf("piece%d", @class);

If you are assembling the geometry and have copied your geometry to make a building lets say. You will need to rename your geometry as you will have multiple geo with the same name attribute name.

To do this place a point wrangle and type the following:

s@name_orig = s@name;
s@name = sprintf("inst%d", @ptnum);

The first line is saving the original name given in the first primitive wrangle. The second line is renaming all of the pieces with their own unique name attribute.


Assemble - Geo ready for Simulation


When working with rigid bodies, it's best to pack your geometry. You can do this by using the “pack SOP”. The pack SOP packs all the points, vertices etc into 1 points. It is like instancing in maya. When you pack the geometry, Houdini creates something called intrinsics. This is all the information of the geometry packed away in attributes. The reason you pack all your geometry is because Houdini can compute the simulation a lot faster. You can have tens of thousands of pieces of geometry packed into single points and you can will still be able to simulate a lot faster than if you tried to compute each piece of geometry that had 2000 points.

NOTE: When the point is created it is created as a centroid. This centroid stores attributes like velocity (V), angular velocity (W).

Instead of using the pack SOP, use the assemble SOP. This is the same as the pack SOP except it comes with some extra attributes like “name” or “class”. The assemble node is handy when wanting to fracture geometry. The assemble node can give the voronoi an attribute called “name” or “piece”. This will give each piece created from the the voronoi and Id number.

Working with Constraints

Constraints - Noise (More control)


If you are fracturing the geometry and want to constrain certain pieces together, It’s best to use 2 assemble nodes.

The first assemble SOP will give each piece of geometry a name attribute. To do this turn on “create name attribute” and “connect inside pieces”. The output prefix should be called “piece” you can add a prefix to this if you are using multiple assembles on different pieces of geometry. Place a null down after this and called it “name”, you will need this later.

The second assemble comes after the name null created before, on this one turn off create name attribute and turn on create packed geometry and connect inside pieces. Delete the output prefix name.

To create your constraints, you want to do this on the unpacked geometry. So you will need to do it on a separate branch from the second assemble which packs the geometry ready for simulation.

So, in a separate branch create a connectadjacentpieces SOP. Change the connection type to “adjacent pieces from surface points”. Play around with the search radius and max search radius to get the desired amount of points each piece will look for to connect too. Change the max connections to something like 1 or 2.

Once happy with that, you could place a primitive VOP and create a turbulent noise that is connected into a fit range, lowering the source max so the lines created from the connect adjacent pieces don't have a gradient from black to white. You will be able to visualise this if you plug the fit range into the Cd of the output. Finally plug your fit range into a bind export and name it “strength”.

Facet your primitive VOP and then place an attribute wrangle and type the following:

s@constraint_type = "all";
s@constraint_name = "pin";

Finally, place a primitive SOP down and turn on “do transformations” and change the scale to 0.

NOTE: Strength is a recognised attribute inside the DOP network.

NOTE: If you are using the 2 assemble node method, make sure you change the connection type on the connectadjacentpieces node to “adjacent pieces from surface points”.

If you have colliding static geometry, it’s best to pack this geometry too. This is so you can bring it in as a rbd packed object inside the DOP network.

Constraints - Expression (Random)


Another method instead of using a primitive VOP to create your strength is too place a primitive wrangle and type to following:

s@constraint_name = "glue";
f@strength = 1.0;

In the primitive wrangle created earlier, you can also add an expression to make a super strong constraint to a certain amount of points. To do this type:

if(rand(@primnum) < 0.15){
   f@strength = 10000;
}

The value after the @primnum can be changed to whatever you would like, this will control the amount of points selected. The strength value is the strength of the glue.

Constraints - Expression (Clustering)


After you have placed your connectadjacentpieces, drop a pointVOP down. Inside, create a voronoinoise and promote the frequency. Then create a bind export and give it the name “cluster”, changing it to an integer.

After this, place a primitivewrangle and type the following:

Int pt0 = vertexpoint (0, primvertex(0, @primnum, 0));
Int pt1 = vertexpoint (0, primvertex(0, @primnum, 1));

Int cluster0 = point(0, “cluster”, pt0);
Int cluster1 = point(0, “cluster”, pt1);

if(cluster0 == cluster1){
s@constraint_name = “Glue_Inside”;
} else {
s@constraint_name = “Glue_Outside”;
}

f@strength = 1;

This is essentially saying that from the connect adjacent pieces lines created earlier and the clustering VOP. If you are from the same clustering piece you are really strong. However, if you are connected to another piece from the connectadjacentpieces and not from the clustering VOP, you are not as strong.

You will be able to control the strength of inside pieces and outside pieces differently which can really help your simulation.

Constraints - Metaballs & Forces


Using this method will delete the glue from the radial force of the metaball.

NOTE: Hard constraints, like the methods above give a much more realistic look and are easier to work with.

A good way to create forces to your rigid bodies is to add a metaball force. To do this, create a metaball and add a force node, this is the same as adding a wrangle and typing in the force expression.

You can place the metaball where you would like then add it to a switch with a null attached. You can add an expression into the switch so it only applies the force occasionally. Something like “$F==1003”, this will switch to the metaball every 1003th frame.

In the DOP network, plug in a popmetaballforce into the solver and connect the SOP path. Negate the force scale because by default a metaball force implodes instead of exploding.

Sometimes you might want to visualise the constraints frame by frame, Houdini doesnt do this manually so you have to set it up yourself. To do this, place a SOP solver and plug it into the constraint network.

Inside there, place an object merge and merge in the your rbdpackedobject from the DOP level, you wont want to bring in everything, just the geometry, so your object merge should be something like: ../../rbdpackedobject1/geometry/.

Add a pointwrangle, first input is the relationship_geometry, second input is your object merge. Inside the wrangle type the following:

int pt = findattribval(1, "point", "name", @name);
@P = point(1, "P", pt);

You then want to place another object merge, this time, you want to bring in your metaball OUT null. Place a group node and plug the metaball into the secondinput and the wrangle into the first. Change the bounding type to bounding object, and call the group active.

You will need to promote the group to the primitive level using a group promote and adding the group activate. Then copy the group “activate”, to the wrangle stream, using a group copy.

Place another wrangle and apply it to the activate group and type the following:

@group_broken = 1;

Finally clean up the groups with a group delete and plug it into the OUT. You may need to lower the glue strength on the outside pieces to see some real distruction.

Activating rigid bodies manually


Sometimes you may want to control where the simulation starts or the speed everything falls, To do this you will need to create active groups.

After placing your assemble node that packs the geometry. Create a group node and name it “active”. Turn on bounding box, from here you can either animated the size and center of the bounding box or you can plug in your own shape that animates. To get better, more realistic results, plug in your own shape. Something like a sphere with a noise deformer on it. On the group node, make sure you turn the bounding type to bounding object and change the group type to points.

You can create multiple active groups so the simulation starts in multiple areas. One key thing to remember is to change the initial merge to “union with existing”. If you don't do this, you will keep overwriting each active group node.

Once you are happy with the group activation animation, place an attribute create and name it active. Make it an integer and make sure the group at the top has the active group created before. Also change the value in X to 1.

After the attribute create, put down an point wrangle and name the group “fixed”. Inside the point wrangle type the following:

i@active = 0;

This will keep all points that aren't active from the group stationary. To visualise which pieces are being activated over time you can create a blast node on a separate branch from your attribute wrangle and type the following:

@active==1

You can actively control sections of your simulation, like the height threshold, so if pieces are closer to the ground, they don't break (a bit like foundations on a building). To do this, place a point wrangle after your assemble and type the following:

if (@P.y < ch("height_threshold")){
   i@active = 0;
} else {
   i@active = 1;
}

Click the small slider on the right of the box to create a height threshold slider. On a separate branch add a delete node and type @active=0 into the group name and change it to delete non selected and change it to points. (This is more for visualising, this will not go into the simulation).

DOP network - rigid bodies


To fracture the geometry that has been set up. Inside your DOP network place a bullet solver and plug it into a constraint network. Inside the constraint network DOP, change the “constraint network” to whatever the constraint nulls called that was created earlier.

Create a hard constraint relationship DOP and plug it into the second input of the constraint network. Change the data name to “pin”. This attribute should have been made earlier in the connect adjacent pieces branch. Change the rest length to 0 and increase the constraint force mixing.

You can also work with SOPs on a DOP level. To do this, create a sopsolver and plug it into the third input of the constraint network. You may want to do this to control the things like the break threshold of the constraints.

If you want to control the break threshold of the constraints, go inside your SOP solver create a primitive wrangle and place it under the relationship geometry SOP. Then type the following:

if (f@force > ch("breakThreshold") * f@strength) {
   //i@group_broken = 1;
   removeprim(0,@primnum,1);
}

You can click the small slider button on the primitive wrangle and promote the attribute to the DOP level. This will be easier when controlling the threshold.

Above the bullet solver you need to plug in your fractured geometry and static geometry if there is any. Place a RBD packed object and connect your fractured packed geometry into the SOP path. Make sure you tick “overwrite attribute” and rename it “active”.

If you need to plug in static colliding geometry, make sure that is packed too and create another RBD packed object. All you need to do is merge this with your fractured (moving) packed object. Make sure that the static geometry are the first inputs.

Your geometry be rolling around a bit more than it should be, this could be because the convex hulling has rounded the edges off. To help this, go to your RBDpackedobject and lower your collision padding to 0.1.

On the RBD packed objects, on the physical tab you can change the friction and bounce properties of the object. As a starting point, lower the friction and bounce.

NOTE: You can connect POPs into the DOP network when working with rigid bodies, like the drag force for example.

DOP import to SOP level


When bringing the simulation to the SOP level you may not want the ground plane or some other constraints etc. You can choose what objects you want to bring out of the DOP network by typing in the name of your object on the DOPnetwork SOP > Object Merge > Object.

Another way to do this is (which is a better way, as you can do this in different Geo Nodes) to place a DOP import SOP. Choose which DOP network you are wanting to import, type in which object you want to bring out of the DOP network into the Object mask.

When done with simulating, you can move point by point your heavy geometry to the pack geometry position. If you want to move everything you can just unpack the simulation. However, to move point by point you can place a point wrangle after a null under the DOP network and type the following:

matrix M = primintrinsic(1, "packedfulltransform", 0);
@P = @P * M;

Plug the null into the second input and the unpacked geometry into the first input. This technique is basically moving each point to the new location.

Adding a post displacement


As the voronoi fracture is a bit basic in terms of detail, you can add a post displacement. This can be done at render time but it's sometimes nice to visualise what the displacement looks like before rendering.

You may even want to do the post displacement and then a render time displacement to get extra detail. As you might be working with high resolution geometry already, you may as well add this bit of detail.

NOTE: Doing this method will make your scene a lot slower as you are subdividing the mesh quite a lot. Obviously this can be controlled to what your desired effect.

To create the displacement you will need to displace your fractured object at a rest position and transform the pieces back to the the simulated position.

Place an object merge and bring in your geometry at a rest position. Delete any colour on the object. You will want to divide your mesh using a divide SOP so you can add detail. Change the size to whatever subdivision you’d like.

Create a bound SOP and blast away the top and bottom edges of the bounding box. Place an attribute VOP. Plug the divide into the first input and the blast from the bound SOP into the second input.

Inside the attribute VOP place an xyzdist plugging “P” into “pos” and “opinput2” into “input”. Plug the xyzdist into a fit range. Sliding the source max will control part of the displacement later once the rest of the VOP is set up.

Create a trubulent noise “3D” and promote all the parameters. Plug “P” into “pos”. Also create a constant vector and change the values to 1, 0, 1.

Once you have these 4 VOPs created, place a multiply and connect the turbulent noise into the first input, the constant into the second input, and the fit range into the third input.

Then place an add VOP and plug “P” into the first input and the multiply into the second input. Finally, plug the add into the output VOP “P”.

Outside the VOP you will want to place a transform pieces, plug the displacement VOP just created into the first input and your cached simulation into the second input. Make sure you change the attribute to “name”, this should be default anyway.