Notes on Hair Making

Feb 2007

The ideal way to create hair is to model the shape using NURBS patches, create hair curves out from them and the curves can be animated. The process can always let you go back to change the patches to adjust the shape and rebuilt hair mechanically with automation.

Maya Hair is used to create hair pose from which hair curves is extracted. These curves will be used to create Shave hair for rendering purposes. The reason is that Maya Hair is very good in dynamics while Shave is very bad in it when the hair is long. Another reason is that the result of rendering Maya Hair in mental ray is very bad. Even if it is rendered in Maya renderer (which can produce good result), there is still an anti-aliasing problem (see the following figure). To void this, Shave is used.

Maya Hair

Maya Hair

The following is a procedure of how to create hair pose by modeling (and simulation).

  1. (Simulation only) Before generating hairs, you should have the head model, skeleton as well as the head's animation ready. Skeleton is required as it would be used to parent the follicles and hair constraints.
  2. Create NURBS patches with U running along the hair direction and U=0 being root of the hair. Number of span along V is 1. Both U and V ranges are from 0 to 1. Note that CV count along the U direction would affect stiffness of the hair.
  3. Select pathces and execute jcCreateHairClumps(n) to generate curves where n is the number of curves generated out from each patch.
  4. (Simulation only) Put all curves under a group which has a parent constraint (or parented) from the head joint.
  5. Select all curves or their parent group and choose Hair -> Make Selected Curves Dynamics. A hair system node would be created. Apply preset if there's any.
  6. (Simulation only) Select all curves or their parent group and choose Hair -> Convert Selection -> to Follicles. From the channel box choose Lock -> Base and Rest Pose -> Same As Start. Alternatively, this step can be done by exexuting jcModifyFolliclesbyGroup or jcModifyFolliclesbyCurves with preset.
  7. (Simulation only) From outliner, select Follicles corresponding to the hair curves of the inside layers and choose Simulation Method -> Passive from the channel box. Alternatively, this step can be done by executing jcModifyFolliclesbyGroup (if the curves are put under a group) with preset.
  8. Select hair system node, and choose Hair -> Assign Paint Effects Brush to Hair.
  9. Open hypergraph and delete paint effect brush created in previous step.
  10. (Simulation only) Select all curves and Hair -> Create Constraint -> Collide Sphere. Apply preset if there's any. Put constraints under groups which has parent constraint (or parented) from the corresponding joints (eg. head joint).
  11. (Simulation only) Apart from Collide Sphere and Cube constraints, hairs can be held by using transform constraint. Again, select all curves, choose Hair -> Create Constraint -> Transform. Move the constraint locator to the level about the same as the middle of the ear. Put it inside the group parented by the head joint. Adjust attributes (or apply preset) as follows:
    1. Stiffness = 0.2
    2. Glue Strength = 0.1
    3. Point Method = U Parameter
    4. U Parameter = 0.6
  12. (Simulation only) Choose Hair -> Create Cache to run simulation.

Hair Modeling Notes

  1. Hair Part
  2. Roots
  3. Tips
  4. Edge
  5. Haircut
  6. Clumps

Shave and Haircut

Convert paint effect to curves and use them to create Shave hair. Detailed steps are as follows:

  1. Select pfxHair node and choose Edit -> Convert -> Paint Effect to curves. A group containing curves will be created.
  2. Select all curves and delete history. (Leaving history behind would make rendering fail.)
  3. Select each group of curves and choose Shave -> Create New Hairs. Choose the newly created shave nodes. Open attribute editor and make sure interpolation is off, multi-strand and rand scale are zero (or apply preset). The resultiing hair shape should be exactly the same as that generated by Maya Hair.
  4. If hair is not dense enough (eg. 1000), increase hair count (eg. 2000), turn on interpolation, increase hair passes (eg. 3) if you want.

Render Shadow

To render shadow in a separate pass:

  1. In Shave Global, setup the following parameters:
  2. Hit render and the resulting image will include shadow but not hair.

FG has no effect on shadow as Shave just ignores non-spotlight lighting. If FG is to be used, it is necessary to convert hair into polygon so that shadow can be rendered correctly. But you must be able to control the polygon count so as to limit render time. Thus use the polygon objects converted from Maya Hair:

  1. Select hair system node, increase thickness of hair a few times to make sure its dense enough to cast shadow. Delete paint effect brush. If you don't delete it, polygon count to be converted will be much higher, render time will be increased significantly and the polygon hair will be very thick. (Use jcDeleteAllBrushes to delete the brushes.)
  2. Select pfxhair node, choose Modify -> Convert -> Paint Effect to Polygon with these options:
    1. Vertex Color Mode = None
    2. Quad Output = on
    3. Hide stroke = on
    4. Polygon count = (enough to include all hairs)
  3. Select the resulting polygon object, delete history (optional) and turn off Primary Visibility and Receive Shadow in its Render stat.
  4. Assign a black matt (black surface shader) to the polygon object and delete its hairtube shader. (Use jcHideMeshes to perform step 3 and 4.)

If the polygon count is too high, reduce it by reducing subSegments in the hairsystem node.

Make sure the meshes are outside the hair occlusion objects list in Shave Globals. (See note in next paragraph.) If "hairOcclusionObjects" is "all", Shave will try to cast shadow onto all the meshes and render will likely fail with message "PHEN 0.0 error: Shave: renderShadows -- shadow pass failed with status 1.".

 

Notes on Multi-Pass Rendering

Shave only obeys its hair occlusion objects list without considering render layer and visibility of objects. It ignores the object inclusion in render layer. This is intentional as Shave can render a separate hair pass even if the objects are visible. Its hair pass considers the hair occlusion objects list only so as to produce a correct alpha. With correct alpha, this hair pass can be used to overlay other render pass without doing z-depth compositing (like what Maya Hair does).

Put only those objects which would affect hair alpha and shadow into hairOcclusionObjects attribute (which does not accept selection set). To do this create a selection set called hairOcclusionObjects to include objects you want. In outliner, expand the set and highlight the objects under it. Then open script editor and you'll see the object list in the most recent select command. Copy and paste that object list into the hairOcclusionObjects attribute. Or use the following mel script:

if (`objExists hairOcclusionObjects` && `objExists shaveGlobals`)
{
    string $s[], $a, $cmd;
    select -r hairOcclusionObjects;
    $s = `pickWalk -d down`;
    $cmd = "setAttr -type \"string\" shaveGlobals.hairOcclusionObjects \"";
    for ($a in $s)
    {
        $cmd += $a + " ";
    }
    $cmd += "\"";
    eval($cmd);
};

For the same reason, make sure the visibility of the shave display object (mesh node) is off under other render layers even if it is not included in those layers. Otherwise, it'll be rendered. Alternatively, you can use render override to turn off the active attributes of the Shave nodes.