Simulating Cornrows

How to simulate the cornrows?

For full credibility, The Cornrows Setup must be ready for simulation. Since it's not made with the regular Houdini grooming pipeline, the simulation part will be pretty much off-pipe as well. A bit of a hack, but it works. I am not a cfx artist, so take this with a grain of salt. I've done cfx in small production where this kind of hackery would fly. Still, this will probably not be the way to go in a studio with an established pipeline. 

Download Sample HIP File

Plan

I split the groom into three different parts for starters: braids, scalp hair, and guides. Scalp hair is pretty straightforward. All it needs is to be wrapped to the skin with a point-deformer. The braided part gets a bit more complicated. Some of it can be point deformed, but the tips need simulation. The idea is to deform the braids inside a for-each loop one by one with tubes created from the simulated guides. I couldn't get the guide-deform node to deal with the braids and get clean results. I faced weird results in orientations caused by the simulated guides and braids. So I created tubes from the guides and deformed the braids with the tubes geometry. To wrap the braid groom to the tubes properly, it needs to be done inside a for-each loop. Each braid needs a connectivity attribute that matches the corresponding guide for the for-each loop to work correctly. 

Preparation & Attributes

First, the preparation of the attributes for simulation. The braid groom and the guides need an integer attribute called class created with a connectivity node. I created this attribute on the guides and then transferred it to the braids. I found it to work well if I transferred the attribute in the graph right after multiplying the braid curves. It's essential to check that all the needed attributes will transfer properly and not get lost in the graph. The rest of the attributes that the guides need is a pin group to define which part of the guides will be pinned to the animation. I wanted the part of the guides that are connected to the scalp hair to be pinned. To make the pin group, I used this simple script in point wrangle with guides in the first stream and the scalp hair in the second stream:

if ( xyzdist(1,@P) < chf("treshold") ){
    setpointgroup(0,"pin",@ptnum,1);
}

Additional attributes I created were to control the simulation parameters. For example, for the bend stiffness, I used this script and adjusted the ramp to get more control over the sim:

float bend = 1-chramp("bend_ramp",@curveu);
f@bendstiffness = bend;

Of course, you would create as many attributes as the simulation requires to get the desired look. But as this setup is just for proof of concept, I didn't go further with tweaking the simulation.


Simulation

In this case, the simulation I'm going for is a simple shake of the head. To get the simulation graph started, the guides need some animation. This can be done with a point deform node. Similar thing to the scalp hairs. Guides to the first input, rest skin to the second, and animated skin to the third. After this, I plugged the animated guides into a vellum configure hair node, set the Pin Points parameter to the pin group, and checked the box: Match Animation. Next up in the graph is a vellum solver. There are many parameters to set in these two vellum nodes to get the feeling of the simulation right. I always find this part very tricky, and it takes a lot of time and patience.

Creating tubes from the simulated guides

When the guides were simulated and started to look decent, I added a smooth node to relax the points. To turn the guides into tubes, I used a polywire node. Creating tubes from moving curves gets a bit hairy. I found that if there is no up vector specified, the polywire will do weird orientations. In this case, the polywire nodes up vector must be set to 1 on the x-axis to make the tube stable. I found this to work in this setup since the animation is pretty straightforward. Still, it might be that the up vector needs to be set dynamically if the character is rotating more. A vector created from two points on each shoulder could possibly do the trick to prevent the tubes from flipping around if the character turned. I also found a problem that the class attribute didn't transfer over to the tubes as a primitive attribute for some reason. So before the polywire nodes, I promoted the class attribute to a point attribute and then back again to a primitive attribute.

Deforming the braid inside a for-each loop

The groom, rest tubes, and simulated tubes need to be merged together to get the deformation working inside the for-each loop. Inside the for-each loop, they need to be separated again. To split the parts inside the loop, they all need a unique path attribute. The path attribute is simply a string primitive attribute that contains some word. In this case, for example, I created a primitive wrangle for the braids with this line:

s@path = "braids";

Same thing for the rest tubes and sim tubes and then merge the three streams together. This stream will then go into the for-each loop.



The easiest way to create the for-each loop setup is to create the node "for each connected piece" and delete the created connectivity node. The for-each loop will loop over every class attribute, in this case, every braid with its deforming tubes. 

Inside the loop, I split the stream into parts using delete nodes. For example, the braids are separated from the stream with the operation of the node set to "delete non-selected" and group expression: @path=braids. Then I created a point-deform node and wired the groom and tubes accordingly. 

After this, the braid can be merged with the scalp hairs, and the sim is good to go. 

Previous
Previous

Transfer skin point attributes to hair primitives with VEX

Next
Next

Procedural Cornrows Study