ADDING RIGGED HAIRSTYLES TO ARMATURES
AUTHOR NOTE: This tutorial uses affiliate links. I only use affiliate links for assets that are either explicitly used in the article or that I have personally tested. I do not include affiliated links for paid promotional purposes.
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.
The Problem:
Let’s say that you have a character with a few different 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. 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.
My solution:
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 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 😉
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
RULES
RULE ONE:
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.
RULE TWO:
The characters MUST be the modeled to fit the hairstyle you’re swapping. This code is intended for meshes that are already ready to fit the new 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 modeled for them separately.
So with all of that in mind, let’s get started!
The Setup
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.
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.
Getting the Code REady
Before we can do anything else, we need to write some 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 five 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
Here are the parameters I used:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HairTool : MonoBehaviour
{
public Transform finalArmature;
public Transform existingHairBones;
public Transform newHairBones;
//The name of the root bone for that character's armature.
public string rootBoneName = "Hips";
public Transform hairParent;
public GameObject currentHairMesh;
public GameObject newHairMesh;
private GameObject clonedObject = null;
public Material newHairMaterial;
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 one of those steps 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.
public void PrepCharacterStepOne()
{
//Delete the existing hair bones
if (existingHairBones == null)
{
//There are no existing hair transforms present so you can just add the new one
Debug.Log("There are no existing hair bones defined.");
PrepCharacterStepTwo();
}
else
{
//Delete the existingHairBase and its children
DestroyImmediate(existingHairBones.gameObject);
DestroyImmediate(currentHairMesh);
//Add the new bones
PrepCharacterStepTwo();
}
//Then move to the next step
}
public void PrepCharacterStepTwo()
{
//Unparent the new hair bones from their existing armature
newHairBones.SetParent(null);
//Add the new hair transforms
newHairBones.SetParent(hairParent);
BindNewHair();
UpdateExistingHairBoneReference(newHairBones);
}
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.
public void BindNewHair()
{
GameObject part = ChooseHair(newHairMesh);
DuplicateReassignedMesh(part);
if (finalArmature == null)
{
Debug.Log("No new armature assigned");
return;
}
if (finalArmature.Find(rootBoneName) == null)
{
Debug.Log("Root bone not found");
return;
}
SkinnedMeshRenderer r = clonedObject.GetComponent();
Transform[] bones = r.bones;
r.rootBone = finalArmature.Find(rootBoneName);
Transform[] children = finalArmature.GetComponentsInChildren();
for (int i = 0; i < bones.Length; i++)
for (int a = 0; a < children.Length; a++)
if (bones[i].name == children[a].name)
{
bones[i] = children[a];
break;
}
r.bones = bones;
currentHairMesh = clonedObject;
}
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.
public GameObject ChooseHair(GameObject _hairToAdd)
{
if (newHairMesh != null)
{
return newHairMesh;
}
else
{
Debug.Log("No new part has been assigned");
return null;
}
}
private void DuplicateReassignedMesh(GameObject duplicatedObject)
{
GameObject duplicate = Instantiate(duplicatedObject);
MoveMeshToNewCharacter(duplicate);
//Set up the new material
if (newHairMaterial)
{
SkinnedMeshRenderer skinMeshRend = duplicate.GetComponent();
Material oldMat = skinMeshRend.sharedMaterial;
skinMeshRend.sharedMaterial = newHairMaterial;
}
else
{
Debug.Log("No material has been defined.");
//do nothing
}
}
private void MoveMeshToNewCharacter(GameObject _duplicatedObject)
{
//Find the armature parent
Transform armatureParent = finalArmature.parent;
_duplicatedObject.transform.SetParent(armatureParent);
clonedObject = _duplicatedObject;
}
private void UpdateExistingHairBoneReference(Transform _newHairBones)
{
existingHairBones = _newHairBones;
}
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.
Adding Physics
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!
Editor Setup
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):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(HairTool))]
public class HairToolEditor : Editor
{
bool createPrefab = false;
// The path to the save location for your new prefabs
string prefabPath = "Assets/MyPrefabs/";
public override void OnInspectorGUI()
{
HairTool myTarget = (HairTool)target;
GUILayout.Space(20);
GUILayout.Label("SET UP YOUR CHARACTER", EditorStyles.miniBoldLabel);
myTarget.finalArmature = (Transform)EditorGUILayout.ObjectField("Final Armature:", myTarget.finalArmature, typeof(Transform), true);
myTarget.hairParent = (Transform)EditorGUILayout.ObjectField("Hair Parent Bone (Head):", myTarget.hairParent, typeof(Transform), true);
myTarget.existingHairBones = (Transform)EditorGUILayout.ObjectField("Existing Top Hair Bone:", myTarget.existingHairBones, typeof(Transform), true);
myTarget.rootBoneName = EditorGUILayout.TextField("Armature Root Bone Name:", myTarget.rootBoneName);
myTarget.newHairBones = (Transform)EditorGUILayout.ObjectField("New Top Hair Bone:", myTarget.newHairBones, typeof(Transform), true);
myTarget.hairParent = (Transform)EditorGUILayout.ObjectField("Hair Parent Bone (Head):", myTarget.hairParent, typeof(Transform), true);
myTarget.currentHairMesh = (GameObject)EditorGUILayout.ObjectField("Current Hair Mesh:", myTarget.currentHairMesh, typeof(GameObject), true);
myTarget.newHairMesh = (GameObject)EditorGUILayout.ObjectField("New Hair Mesh:", myTarget.newHairMesh, typeof(GameObject), true);
myTarget.newHairMaterial = (Material)EditorGUILayout.ObjectField("New Hair Material:", myTarget.newHairMaterial, typeof(Material), true);
GUILayout.Space(10);
if (GUILayout.Button("Swap Hair"))
myTarget.PrepCharacterStepOne();
GUILayout.Space(10);
createPrefab = EditorGUILayout.Toggle("Create a Prefab?", createPrefab);
if (createPrefab)
{
prefabPath = EditorGUILayout.TextField("Prefab folder path:", prefabPath);
GUILayout.Label("EX. Assets/MyPrefabs/", EditorStyles.miniBoldLabel);
if (GUILayout.Button("Create Prefab"))
CreatePrefab(myTarget.finalArmature, prefabPath);
}
}
static void CreatePrefab(Transform _finalArmature, string _savePath)
{
// Get the full character reference
GameObject fullChar = _finalArmature.parent.gameObject;
// Set the path as within the Assets folder,
// and name it as the GameObject's name with the .Prefab format
string localPath = _savePath + fullChar.name + ".prefab";
// Make sure the file name is unique, in case an existing Prefab has the same name.
localPath = AssetDatabase.GenerateUniqueAssetPath(localPath);
// Create the new Prefab.
PrefabUtility.SaveAsPrefabAssetAndConnect(fullChar, localPath, InteractionMode.UserAction);
}
}
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).
Happy Rigging!
#Unity3D #Character #CodingTutorial #Animation



