Advanced Grooming Tips and Houdini to Unreal Engine Tutorial

Jonathan Coetzer has shared an extensive tutorial on some advanced tips and tricks for grooming in Houdini 19 and told about a simple method for Houdini to Unreal Engine workflow.

Introduction

Thank you for checking out this tutorial, my name is Jonathan Coetzer. I am a CFX artist in the film and commercial industry. In this short tutorial, I will be going over some advanced tips and tricks for grooming in Houdini 19, specifically pertaining to curls and braids. I will also go over a simple method for Houdini to Unreal Engine workflow.

Skin Setup

For the base geometry in this tutorial, we will use a MetaHuman from Unreal’s MetaHuman Creator. The base geometry of the head is exported from an Unreal Engine scene as an FBX export. The FBX can then be imported into Houdini using a simple File node. A few simple operations follow to prepare the geometry for the grooming process.

Firstly, a Transform to bring the geometry into the Houdini scale and a Delete to isolate the highest res LOD head mesh as the import will bring in all LODs from Unreal. A blast follows to clean up some problem areas such as the eyelashes and the eye lenses. Lastly, delete all the unnecessary attributes such as Cd(color) that are carried in from the import and close up the mesh to allow for an easier VDB process for the groom later on.

This could be done quickly with a Polyfill or as shown above by extruding out the base edge loop followed by a polyfill to create a solid volume.

Base Groom and Curls Using Clumping

Using the geometry we have prepared as the skin for our groom we will drop in the first Guide Groom. The basis of the grooming process in Houdini is the Guide Groom Object Node which constitutes the workspace for our guide setup and guide grooming process. 

Start with assigning the Null output of our skin geometry to the SOP path of the Rest SKin Source. Next, change the override of the density to skin attribute and change the name to your requirement. In this case, I have left it as default density. Click on the icon next to the name. This will create an Attribute Create and Attribute paint Node above the node you assigned in the SOP path.

Using the attribute paint simply fill the geometry with a value of ‘0’ (Blue) and paint in the area of the head where you want the guides to be scattered with a ‘1’ value (Red). Also, adjust the density of the guides to a medium-density as shown in the image above.

After that return to Object level and go inside the Guide Groom. Create a guide process (set length) node. Change the mode to "multiply" and activate randomness, then adjust the min value to be slightly below the max. This will create a little more breakup in the length of hairs generated going forward.

Go back to Object level and place a Hair Gen object node. This is the node used to generate the hair curves around the guides created by the guide groom. To assign the guide groom as the groom object for the hair gen, simply drag the guide groom node to the parameter field of the hair gen node labeled Groom Object. The result should read "../guidegroom".

Assign the density attribute created earlier in the same fashion using the skin attribute override. Adjust density to the desired number and then repeat this process for thickness. This will grow hairs across the head and due to the nature of the attribute paint tool having a falloff, will make the hairs on the border of the density attribute thinner and allow a better-blended hairline.

Should you see gaps where the hair doesn’t grow evenly on the head, adjust the influence radius until full and use density for skin attribute override if required.

Going inside the Hairgen, place a clump node and connect the skin input. The clump node is a very powerful and versatile tool in Houdini's grooming kit. Using it you can achieve a wide range of effects and looks. In this case, we will be making use of the curling feature in an unintended way to simplify a usually complex process. 

Using the clump node set the base parameters:

  • Clump size is small, around 0.004;
  • Crossover rate High to blend hairs across clumps add breakup to the scalp;
  • Adjust hair width scale to 4 to thicken clumps;
  • Increase stray rate to desired value;
  • Change the clump profile to a convex shape instead of concave;
  • In the fractal clumping tab increase the iterations to introduce some breakup.

After the base parameters, we go to the curling tab. The basis of the technique used here is to overdrive the frequency, set the amplitude low and drive the frequency to a value in the range of 1000-1200. Feel free to play around with these values as you may discover some interesting results. By slowly adjusting the amplitude now you will see that it has begun to act like a size control for the tight curls generated.

As an added modifier add a set length guide process and, using a skin override, paint an attribute to decrease the length of the hairs near the hairline to make the groom feel more natural.

For the next step, we will be using a similar approach to create larger flowing curls for a large hairpiece for the character. Referencing back to our initial skin setup, create 2 spheres and elongate them with transform values. Then rotate it on the X-axis to give a tilt and do the inverse for the other. Merge the geometry and create a VDB with a VDB from Polygons node and adjust the voxel size lower to increase resolution. Next, convert back to a polygon with a VDB convert to create one smooth heart-shaped mesh. Add a Labs align and distribute or use an align SOP to bring the mesh to its origin.

Select a single point on the middle of the top of the character's head around the top rear of the scalp. Blast out the point select and input it into a copy to the points node. Place a transform node above the left input of the copy to points and adjust until the mesh is correctly positioned. Then add a normal node, clean node, and remesh node in a chain under the copy to points, this ensures the mesh is usable for the grooming process.

Now that the next skin object is set up, create a new guide groom node and repeat the steps we used in the base curls process except for the density override and add a set length guide process with randomness for the breakup. Inside the guide groom object node, place a guide groom node and use it to delete the guides that intersect the scalp.

Make a new hair gen and place a clump node as we did before. And then set up the base parameters:

  • Clump size is small, around 0.02;
  • Crossover rate set to 0;
  • Adjust hair width scale to 4 to thicken clumps;
  • Increase stray rate to the desired value;
  • Change the clump profile to a convex shape instead of concave;
  • In the fractal clumping tab, leave the value at default to ensure uniform curls.

In the clumping tab, the values are slightly different than before setting up amplitude slightly higher to around 0.0123 and removing the first point on the amplitude ramp modifier will create uniform amplitude along the curve of the guide resulting in a large voluminous curl. Then overdrive the frequency value to 1200 as before. Again feel free to experiment with these values for different results.

Add the same guide process (set length) as before to make the tips of the curls feel more natural. An important note here is to leave the method on cut and extend as the scale would result in a breakup in the uniformity of the curl.

Braid Setup

I have always found braids an interesting problem to solve when it comes to grooming. The multiple challenges associated with making a good realistic braid are often compounding only present themselves as you try further integration with conventional hair setups. It is my hope that the braid setup demonstrated here can prove useful in providing a basis to expand upon. 

For the base curve which we'll use in the braid setup, do the following:

  • Under the copy to point in the skin boolean the heart shape geometry and the final blasted out of the base head mesh. Set the operation to seam treating both objects as solid;
  • Smooth the result;
  • Blast out the unwanted curves;
  • Transform the curve to the desired position moving the pivot transform to $CEX, $CEY, and $CEZ respectively.

The primary approach in this technique for braid generation is creating a base curve shape that will be chained onto a path curve. Step by step instructions:

  • Add a Line, set the Points to 9, and leave the rest of the parameters at default. Group point 1-3 as A and 5-7 as B;
  • Translate A by 0.15 in X and copy the parameter. Paste a relative reference in a new transform below in the X channel and add a *-1 to the end i.e:(ch("../width/tx")*-1). The first transform acts as the width control;
  • Group point 1 and point 5 as C and point 3 and 7 as D;
  • Translate C by 0.35 in Z and copy the parameter. Paste a relative reference in a new transform below in the Z channel and add a *-1 to the end i.e: (ch("../thickness/tz")*-1). The transform above acts as the thickness/height control;
  • Translate point 6 In X by the width relative reference*1.1 i.e: (ch("../width/tx")*1.1) and then translate point 2 by the inverse i.e: (ch("../width/tx")*-1.1). Note these values can be adjusted to increase or decrease the outer peaks of the braid;
  • Pull two chains off of the Peaks Inverse transform and transform the left chain by 0.625 in Y and the right chain by 0.137 in Y;
  • Copy and transform each chain by 2 copies with a transform of -1 in the Y. This creates an offset Reference flag for the two chains in conjunction with the Peaks Transform root to see the positioning and offset of the braid segments;
  • Blast points 4-11 on the Left Chain and 7-14 on the right which brings the offset curves back into 1 high length to match the root;
  • Sort the point order in Y;
  • Polypath to combine the primitives and merge the chains. Add any other post deformational transforms here;
  • Merge the previous merge with Peaks Inverse Transform Node. This is the basis of the braid geometry;
  • For the far-right chain, the input add an object merge the input curve comes in here;
  • Add a poly frame for corrective and a second poly frame for changing the tangent to N. This allows us to use N as forward direction. 
  • Add a transform under the merge. This is the global scale control, change the uniform scale to 0.008;
  • Resample the curves to 25 max segments this will act as the base resolution control;
  • Add a corrective smooth;
  • Add a chain for each connected piece loop. Connect the line from the poly frame of the Input curve to the second input of the chain. The Chain SOP parameters are:

    - Under Chain pattern, the Number of Pieces changes to an explicit number and is set to 20 or personal preference. This will act as the frequency of the braid;
    - Change Map Length Using to Fraction of Curve Length;
    - Open Deformation Drop Down. Enable the scale, this can be used to scale the braid, and easily and with the built-in ramp can be used to taper the braid;
    - Enable Rotation, use this to rotate the braid to face desired direction/orientation, and use the ramp to add further art direction and control to the rotation. For example, this is set to 109;
    - Open fusing and set snap dist to 0.49;
    - Open the alignment tab;
    - Set forward direction and up direction to Y;
    - Change curve up control to Curve Normal which was set on the input curve previously with a playframe;
  • Add a smooth corrective to the output for each loop;
  • Pull off a chain to the side and add a poly frame with the value set to desired thickness to visualize the braid as geometry tubes and check for any issues. Below you can see the mesh preview.

Place a for each connected piece loop, inside the loop place a poly frame, this can be used to force adjustment should need to arise, for this example un-tick all boxes.

  • Off to the side create a circle with the uniform scale of 0.004, this will be the control for the thickness of each braid piece;
  • Scatter points across the surface of the circle forcing the total count to 250, this is the density of the final Hair that is generated and can be adjusted later to the desired levels;
  • Add a connectivity node-set to the pint, this will generate a class attribute per point;
  • Add a poly frame with Bitangent name as N;
  • Connect this to a copy to curves node with the copy to curves second input connected to the poly frame in for each loop we created above. The copy to Curve parameters are:

    - Target Up Vector Y-axis;
    - Add an attribute called class applying to points by adding it at the bottom under the attributes drop-down tab.
  • Place an add node, select polygons tab, and set to add by group and add to attribute, setting the attribute name to the class. This will connect a curve between the points we scattered earlier;
  • Add an attribute noise to the output for each loop (do not do this if you plan to deform this mesh using this setup in Houdini, you would need to point deform it as a rest position);
  • Add a final resample to act as a final Resolution control to control the resolution of the final product, in this example set to Maximum segments, 250;
  • Add a color node set to random from the attribute and set class as the attribute name, this will generate a random color per strand to better visualize the result;
  • Finally, add an attribute create and make it a float value called width, set this to 0.0001.

As we can see, the final result is a full braid loop. You can apply the exact same shader to standard hair grooms. The system is flexible and can easily be made into a tool, one could add different base curve profiles for various braid types, to build the setup into a fully packed HDA to generate ropes and braid curves for various needs and requirements.

Feel free to add any other elements to the setup we have so far like eyebrows or accent curls, or even more braids using the techniques shown above. 

Export from Houdini to Unreal Engine

The first step to exporting the hair setup from Houdini to Unreal is the caching process. Start by making a simple empty geo node on the object level labeled export, inside the object, merge in all of the outputs you wish to cache. Merge all of the outputs and under the merging place, attribute promote.

In the attribute promote, find the width attribute and promote it from a point class to a vertex class then change the new name to "groom_width" and select "delete original". This is so that Unreal Engine reads this as the hair width when it imports the alembic file. You can find a full list of other groom attributes that can be read natively by Unreal Engine here.

I have selected UE 4.27 for the purpose of easy MetaHuman workflow, however, the same would apply to UE5. Next place an Alembic ROP and using the default settings write out the static hair alembic to your desired file location.

The first thing to do in Unreal Engine is to search for the hair under Edit > Plugins. Enable the alembic groom importer. Unreal Engine will prompt to restart.

After the restart, simply take your alembic export and drag it into the content browser of the UE scene. A dialogue will be shown requesting the conversion settings for your groom, I prefer to do this post-import and clear the transforms after but should you know in advance feel free to execute those transforms here. 

As shown above you can see the changes in the groom's transforms. Also, note that the width is correct when run through Houdini to Unreal scale conversion.

Lastly, to adjust the groom material, you can open the groom material found in the properties menu on the right of the Unreal viewport. Double clock the material to bring up its Blueprint and make any adjustments to your preference. In this example, I simply adjusted the color to more closely match what was present in Houdini.

Thank you for taking the time to check out this tutorial. I hope that it has proved useful.

Jonathan Coetzer, CFX Artist

Join discussion

Comments 2

  • Anonymous user

    This is great! Thanks for all that effort!

    0

    Anonymous user

    ·2 months ago·
  • Anonymous user

    That is amazing bro, thanks for the tutorial, I can't wait to practice this. :D

    0

    Anonymous user

    ·2 months ago·

You might also like

We need your consent

We use cookies on this website to make your browsing experience better. By using the site you agree to our use of cookies.Learn more