ADDING RIGGED HAIRSTYLES TO ARMATURES
Using Unity Version 2019.4
We’re going to talk about hair today!
This tutorial is a bit of a follow-up to my Adding Parts to a Rigged Character guide. Both are about moving parts from one character rig to another, but the key difference here is that in this tutorial, we're going to use parts that are weighted to unique armature bones. Namely: Hairstyles.
Let’s say that you have a character with a few hair and clothing options. In many cases, like with my assets, the hair is rigged to unique hair bones to allow for physics or animation and that means every hairstyle will use a slightly different rig, even if the main skeleton is consistent. So the character with Clothing A will have Hairstyle A and Clothing B with Hairstyle B. But if you want to move Hairstyle B over to the rig with Clothing A, you run into a problem because the hair bones are different.
You could follow my other guide and just move the hairstyle over to the new rig, ignoring the hair bones entirely. However, this could cause issues if the hair depends on those bones. Perhaps it’s only partially anchored to the Head bone and the rest of it is weighted to children of the Head bone. In that case, the unweighted vertices of the mesh would behave as though they weren’t weighted to anything at all because…well…they aren’t. And even if none of that is an issue, you lose any ability to use physics on the hair bones or animate it.
So the best solution is to move the hair and the hair bones over to the rig. This tutorial will show you how to do this.
We’ll also talk about doing this with a custom editor so you can create new character prefabs and how to add physics to the hair.
This post will use two of my character packages as an example: Scarlett Riley: Stylized Sci Fi and the Ultimate Stylized Business Women. However, they aren't required for this tutorial -- you could definitely adapt the code for your own characters too! Scarlett is a great example to work with because there are multiple rigs and hairstyles available. You can purchase the assets to follow along if you want :)
If you want to be able to add physics to the hair, you'll want an asset to do so. I prefer Dynamic Bone, which you find here:
How it Works:
This code will do three things:
Remove the existing hair bones and hairstyle from an armature
Add hair bones from a new armature to the existing armature, and
Add the corresponding hair mesh from the new rig to the existing armature
If the hairstyle is weighted to bones other than the hair bones, such as the head, spine or shoulders, the armatures (aside from the hair bones or extended bones for wings, weapons, etc.) MUST contain the same hierarchy of bone names. This is because hair that contains weights for the head, spine, shoulders, etc. will look for those bones in the rebinding code.
The characters MUST be the same. This code is intended for meshes that are already modelled to the character. For instance, my Scarlett characters will all work with other Scarlett hairstyles, but you won’t get ideal results if you try to use a Dahlia hairstyle on a Scarlett character. The heads, neck, shoulders and chest between the characters are different shapes and sizes and the hairstyles are modelled for them separately.
So with that in mind, let's get started!
When you open the Prefab folder in the Scarlett Riley package, you'll see five folders for the different clothing options. Inside each folder are three FBX files -- one for each hairstyle.
Start by choosing any of the prefab files and drag it into the Scene hierarchy. This will be the main armature (the one you are going to move the new hairstyle to).
Right click on the character in the hierarchy window and select Unpack Prefab Completely.
Now select the hairstyle you want to add. I'm going to use a long hairstyle from a Scarlett prefab in the Ultimate Stylized Business Pack. Drag a prefab (or the mesh file) containing the hairstyle you want to use to the scene. It doesn't matter which, since we're just concerned with the armature at this time.
Again, unpack the prefab completely, but this time, delete all of the meshes in the hierarchy (even the hair mesh), leaving ONLY the armature.
NOTE: Make sure the two characters are in the same spot in the scene. This will ensure the new hair bones are parented properly.
Before we can do anything else, we need to write some code.
If you don't want to go through the whole article, you can skip to the end to grab the code.
Create a new C# script. I called mine “HairTool”. This doesn't have to live on the character. You can create an empty game object in the scene for it.
Next, let’s declare our parameters. I wanted my code to do four things:
Delete the existing hair bones and hair mesh from the character
Move the new hair bones to the armature
Instantiate a clone of the new hairstyle and bind it to the new armature,
Apply a material to the new hair
Update the references in the code
So here are the parameters I used:
Let's break down what these parameters are for:
finalArmature: The new armature that we want to move parts to.
existingHairBones: The top bone of the hair hierarchy currently in the final armature referenced above (for hair, this will normally be a child of the Head bone)
newHairBones: The top bone of the hair hierarchy in the other armature (for the new hairstyle)
rootBoneName: The root bone name of the final armature that we want to move parts to. This is declared as "Hips", but can be changed if needed.
currentHairMesh: The existing hair mesh that we’ll be replacing
newHairMesh: The new hair mesh that we’ll be adding (dragged directly from the FBX file)
clonedObject: This is the clone of the hair we just added.
newHairMaterial: The material we want to apply to the cloned hair.
Populate all these fields using the bones from the unpacked prefabs you've moved to the scene view.
For the newHairMesh, you will drag the mesh directly from the original FBX file that corresponds to the mesh or prefab you unpacked in the scene view:
What this code will do:
This code works in the same way the code from Adding Parts to a Rigged Character works, but with a couple of extra steps. And since that code rebinds the new part to the new armature, we need to create the new armature first.
Again, in order to move the new part to the existing armature, the weights need to already be present on both. There can be additional bones on either armature, but the ones for the new part need to exist in the new armature.
Our first function will prepare the final armature by deleting the existing hair bones and hair mesh. First it will check if there are existing hair bones. If not, it will move on to the next step. If there are, it will destroy both the bones and the existing hair mesh.
The second function will unparent the hair bones we want from the new armature and parent them to the final armature. Then it will call another function, which clones the hair mesh we want to use and binds it to the final armature and applies the new material. Finally, it will update the references to reflect the existing hair bones and hair mesh.
The heavy lifting for this code takes place in our next function, which will bind the new hair mesh to the new armature. We don't want the script to rebind the original mesh part -- just a clone, so a function will take care of that for us. Finally, it will make sure a new armature is assigned and locate the root bone that’s referenced.
The remaining lines in the function find the Skinned Mesh Renderer of the cloned part, and which bones it is currently weighted to. We’ll then ask the script to bind the mesh instead to the bones of the new rig, but using the weights it already has. So the weights for Spine1 in the old rig will now be bound to the Spine1 bone in the new rig, and so on.
There are four functions which work in tandem to instantiate the cloned part, apply the material, physically move the mesh to the new rig, and update our references.
As is, you can add an UI button to call the "PrepArmatureStepOne()" function and run the scene. You should see the hair replaced with the new hairstyle and it should now be rigged to the new armature. Stopping the scene will clear the action and reset the hairstyle to the original.
If you want to apply physics to the bones using an asset like Dynamic Bone, you can quite easily. Simply add the script to the character, referencing the new top hair bone from the second armature before you run the code. It doesn't matter that the bones are not currently part of the character. The reference will remain intact because the bones will always exist -- we're just moving those bones over to the new armature. Here's how it looks now:
Using the code to create prefabs in edit mode.
The above code is fine to use in runtime, but what if you want to take care of this in edit mode and save your new character as a prefab? This can be done with a custom editor.
I won't get into the details on custom editors in this tutorial, but I've included the code here for your use if you'd like to use the code in edit mode. This editor should be saved in a folder called "Editor". You can read more about custom editors here and if it's something you'd like to see a tutorial on, let me know in the comments!
To set your project up properly, let's create a place for your new prefabs. I've created a folder directly under the Assets folder and called it "MyPrefabs". You can create your own folder anywhere, but make sure you note the path because it will be referenced in the editor script.
Navigate to where you've saved your HairTool code and create a new folder called "Editor". In that folder, create a new C# file called HairToolEditor. This is the code you will need (sorry the snipped gets a bit cutoff here. Scroll sideways to see it):
This is what the inspector looks like now:
The benefit here is that you can use the Hair Tool in edit mode by clicking on "Swap Hair" and if you click the "Create Prefab?" bool, it will give you the option to save the new character as a prefab at your specified save location (just make sure you've actually created the corresponding save folder first or you'll get errors).
Here are the full code files:
Used in this article: