Building Character Customization (Part 2)

Review

Welcome to the second part of my Character Customization blog post! The first part can be found here if you missed it, and it covers preparing a Blender3D file that contains a rig, several meshes weighted to that rig, and animations, as well as exporting that Blender file to multiple FBX files for Unity3D to use in a game. We ended up with this:

blender_export_fbx_rig_and_models

File Naming Convention

Before we go further into this, I need to mention a naming convention for all of these files. Keep in mind that this is only my naming convention. Your system may end up being different in the end, but the point is, in order for a system to be loaded into a game, it works best if the filenames follow a certain convention.

My convention for the input Blender file is:

<base name><rig>.blend

And specifically, my files are named like this:

  • HeroA.blend
  • HeroB.blend
  • etc.

The “A” is my rig identifier. And if I ever create new rigs for new characters, I’d have a HeroB.blend, HeroC.blend, etc.

My convention for the output FBX files is:

  • <base name><rig id>[rig]_rigify.FBX
  • <base name><rig id>[<character id>.<costume id>]_rigify.FBX
  • etc.

For example,

  • HeroA[rig]_rigify.FBX
  • HeroA[00.0]_rigify.FBX
  • HeroA[01.0]_rigify.FBX
  • etc.

The main thing to notice here is that one of those files is the rig file which may or may not include the animations (for my purposes, I have included them), and all other files are numerous custom meshes that would be attached to the rig. Each of these files corresponds to a layer in the Blender file, and the layer name is identified with the character string in between the brackets.

The Resources Folder

Unity provides a method for loading resources from disk, and this is the method I use to load my FBX models:

public static Object Resources.Load(string path);

The catch is, any resources loaded with this function must be in a subfolder named “Resources” anywhere in the Unity Assets directory. You can even have multiple folders named “Resources” in the Assets directory if you choose to, but that can sometimes be a little confusing.

Memory for a resource is not allocated until Resources.Load() is called. This is different from the prefab method, which preallocates memory for each prefab, which I’ll discuss below.

Loading the FBX assets from disk is a lot more like traditional game development, and how typical programming works. You get to choose how to load the assets, and when to load them.

Choosing Resources.Load() over the Prefab Method

I chose to use this method because loading up each FBX as a prefab set up in a scene has a number of drawbacks.

  • All model resources would have to be preloaded as prefabs, which uses precious memory that could otherwise be used by your actual game. Why load all those custom parts when you’re not even using them?
  • They’d have to be manually updated whenever new layers or blend files are created.
    • For example, if you were to save a prefab reference in a script called, say, CharacterPrefab.cs, you’d have to update that script manually whenever you add a new character or costume, head, or hair model.
    • Alternatively, in CharacterPrefab.cs, you can add an array of GameObjects to store all your prefabs. This way, you can modify the count in the Inspector, and then drag/drop the FBX model into each slot.
    • Both of these solutions require you to access a MonoBehaviour script in one way or another. If there was a way to dynamically load those prefabs without having any intervention with the Inspector, then it would cut down on some of the manual processing.
  • There is an existing bug in Unity that doesn’t update prefabs that contain an FBX asset that has been updated. There are some suggestions online that mention attaching the FBX model as a child of an empty GameObject, which serves as the actual prefab. This has been a huge pain for me, because I’d have to manually delete the old FBX model from the prefab, and re-drag/drop the FBX model onto the prefab. That’s lots of wasted time.

It’s worth mentioning that it is possible to implement an AssetPostprocessor to update these. The idea is that whenever the FBX file is updated, you can have an AssetPostprocessor target an existing prefab that’s associated with it, say by filename or something, and then modify the prefab all in script. But I decided not to go this route.

That should be it for all of my reasons to NOT use prefabs that reference the FBX files.

Loading the FBX files in Unity

All that talk about Resources.Load() comes down to this section. Before we get into any code we have to get these FBX files loaded into Unity. These files simply need to be copied into the Unity project’s Assets folder tree,  remembering that they MUST be contained in, or in a subfolder of, a folder named “Resources”. You can do this by either exporting the FBX files directly into the target Assets folder manually from Blender’s UI, or automatically via a series of scripts as I’ve discussed in my blog post about a Blender-to-Unity Asset Builder. Here’s an example of a folder tree that I have for my own project:

resources_dir_example

Setup

All right, let’s do some Unity stuff.

To serve as a testing ground, open up a new scene, and place an empty GameObject in the Hierarchy. We’ll attach a script to it which will do all of our resource loading.

using UnityEngine;
using System.Collections;


public class CustomCharacterTest : MonoBehaviour
{
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}

Empty_GameObject_w_CustomCharacterTest_script

We’ll implement all of the loading code in our MonoBehaviour’s Start() function.

Loading the Rig

        GameObject rigObj = null;
        GameObject rigPrefab = Resources.Load("models/heroes/HeroA[rig]_rigify") as GameObject;
        if (rigPrefab != null)
        {
            rigObj = GameObject.Instantiate(rigPrefab);
            rigObj.transform.parent = this.transform;
        }

Note that when loading from Resources, you’re loading the asset into your project, not loading the object into the scene hierarchy. You can think of it as dynamically loading a prefab to instantiate from. Since Resources.Load() can load any type of asset, it’s not always the case that it’s a GameObject.  In this case, it is a GameObject though, so after we create the prefab, we can instantiate it.

After loading the rig, you should see something like this in the Hierarchy:

rig_hierarchy

The rig’s GameObject hierarchy should be kept intact from the Rigify armature imported from Blender, except if you have the RigifyToUnity asset installed, which you should, then the hierarchy should be somewhat stripped down to the essentials as in the screenshot.

Now, WTF is that “Plane” object you ask?

plane_object

The Dummy Object

Okay, I only glazed over this in Part 1 of this post, so I apologize for that, but here is more detail about it, because it is essential for getting the skinned mesh working later on.

The “Plane” GameObject is a very simple mesh that’s skinned to the rig, and it can actually be named anything. It’s just a “dummy” object that holds a SkinnedMeshRenderer that we need for later. If you select it and check out the Inspector, you’ll see the SkinnedMeshRenderer component assigned to it.

plane_object_skinned_mesh_renderer

This mesh can actually be any geometric shape that you create in Blender (even a stick dummy if you want to make visualizing animations easier), as long as it resides on the rig’s layer, and gets exported with the rig as a skinned mesh. I just wanted to choose the simplest object I could to reduce memory consumption, but after we’re done with it, it gets deleted anyway.

BoneDebug

At this point, if you’re not visually convinced that the rig is loaded, I found a nifty asset on the Asset Store called BoneDebug. You can drop the BoneDebug.cs script onto the rig or root GameObject, and it will visualize the armature for you!

bone_debug

Utility Functions

Before we get to loading the meshes onto the rig, I need to get some things out of the way. These are a few utility functions that I use in the below code, so know that it’s there.

public class TransformUtils
{
    // Does not support case-sensitive
    public enum StringMatch
    {
        Exact,      // Exactly
        Leading,    // Leading the string
        Partial     // Anywhere in the string
    }

    // TransformUtils
    // Recursively look for the bone with specified name
    public static Transform GetTransformWithName(Transform root, string name, StringMatch match = StringMatch.Exact)
    {
        if (match != StringMatch.Exact)
        {
            string rootname = root.name.ToLower();
            int index = rootname.IndexOf(name.ToLower());
            if (match == StringMatch.Leading && index == 0)
                return root;
            else if (match == StringMatch.Partial && index != -1)
                return root;
        }
        else
        {
            if (string.Compare(root.name, name, true) == 0)
                return root;
        }

        for (int i = 0; i < root.childCount; ++i)
        {
            Transform child = root.GetChild(i);
            Transform sub = GetTransformWithName(child, name, match);
            if (sub != null)
                return sub;
        }
        return null;
    }

    // TransformUtils
    public static void ResetTransform(Transform transform)
    {
        transform.localPosition = Vector3.zero;
        transform.localRotation = Quaternion.identity;
        transform.localScale = Vector3.one;
    }

    public static void ResetChildTransforms(Transform parent)
    {
        for (int j = 0; j < parent.childCount; ++j)
        {
            Transform child = parent.GetChild(j);
            TransformUtils.ResetTransform(child);
        }
    }
}

Loading the Model

GameObject modelPrefab = Resources.Load("models/characters/heroA[01.0]_rigify") as GameObject;

This time, instead of instantiating the model prefab wholesale, we’ll “pick at” the prefab in a piecemeal manner. Essentially, we just want to load the head and hair mesh objects, and also the body mesh object. We don’t want to instantiate the rig that they are attached to in the model prefab.

Loading the Head and Hair

The head and hair are relatively simple to load compared to the body, so we’ll start there. The head and hair objects are not skinned to the armature. They are simply parented to a bone on that armature.

        GameObject modelPrefab = Resources.Load("models/heroes/HeroA[01.0]_rigify") as GameObject;
        if (modelPrefab != null)
        {
            Transform headXfrm = TransformUtils.GetTransformWithName(modelPrefab.transform, "head", TransformUtils.StringMatch.Leading);

            Transform parentBoneXfrm = headXfrm.parent;

            Transform rigHeadBoneXfrm = TransformUtils.GetTransformWithName(rigObj.transform, parentBoneXfrm.name, TransformUtils.StringMatch.Exact);

            GameObject headObj = GameObject.Instantiate(headXfrm.gameObject) as GameObject;

            headObj.transform.parent = rigHeadBoneXfrm;

            GameUtils.ResetTransform(headObj.transform);
            GameUtils.ResetChildTransforms(headObj.transform);
        }

If it’s not clear as to what the script is doing, here’s what’s going on in semi-plain English. GetTransformWithName() gets the head transform in the prefab. We also want to remember the head transform’s parent too. With the parent transform’s name, we look for the bone with that same name in the rig object hierarchy (because the rig object is what’s actually instantiated in the scene). We then instantiate the head object from the prefab, and set its parent to the bone that we spent the last few lines trying to get. After all that’s done, we reset the transforms of the newly created objects, namely the head and hair objects.

With this, you can load up the scene, and see that the head and hair objects are loaded, especially with the BoneDebug component applied to the rig.

head_and_hair_attached

I want to mention that the calls to ResetTransform() and ResetChildTransforms() are here because I couldn’t get the head and hair to look right after instantiation. I don’t think they’re necessary if you apply your transforms properly in Blender, but for some reason, they still looked wacky to me. Go figure.

Loading the Body

And now for the main event! The body mesh is skinned to the rig with a SkinnedMeshRenderer. However, in terms of the model prefab that we loaded above, this means that the body mesh of the prefab is skinned to the prefab rig with the prefab SkinnedMeshRenderer. This does us no good, because we don’t want a SkinnedMeshRenderer referring to a rig in the prefab. We want to use the rig that’s already loaded in the scene.

But how do we go about doing that?

Let’s forget about the rig in the scene for a second, and focus on getting the mesh from the prefab’s SkinnedMeshRenderer.

            Transform bodyPrefabXfrm = TransformUtils.GetTransformWithName(modelPrefab.transform, "body", TransformUtils.StringMatch.Leading);
            SkinnedMeshRenderer prefabSkinnedMeshRenderer = bodyPrefabXfrm.GetComponent< SkinnedMeshRenderer >();
            Mesh mesh = prefabSkinnedMeshRenderer.sharedMesh;
            Material mat = prefabSkinnedMeshRenderer.sharedMaterial;

We’ll hold on to the Mesh and Material here.

Static Mesh Test

To really understand what’s going on here, let’s load up the body mesh onto a standard, static MeshRenderer. Here’s the function that does the work.

    private void CreateStaticModel(Transform parent, Mesh mesh, Material mat)
    {
        GameObject bodyObj = new GameObject("body_static");
        bodyObj.transform.parent = parent;

        MeshFilter filter = bodyObj.AddComponent< MeshFilter >();
        filter.sharedMesh = mesh;

        MeshRenderer renderer = bodyObj.AddComponent< MeshRenderer >();
        renderer.sharedMaterial = mat;
    }

And then here’s the function being called, with the Mesh and Material from above.

CreateStaticModel(rigObj.transform, mesh, mat);

What we did here is essentially take the Mesh and Material references  that were assigned to the prefab SkinnedMeshRenderer, and attached them to a newly created MeshFilter and MeshRenderer components.

body_static

That’s fantastic for making scarecrows. Yes, I know. But what we can take away from this is that if we cache references to the Mesh and Material from the SkinnedMeshRenderer, we can easily apply it back onto a new SkinnedMeshRenderer that’s attached to the rig in our scene.

Swapping the SkinnedMeshRenderer

So for the real deal, we’ll take our rig object that’s in the scene and add a new SkinnedMeshRenderer component to it. The difference between the static MeshRenderer and the SkinnedMeshRenderer is that we need to provide the bones used to skin the mesh. Remember our “Plane” object from a few sections back? That object has a valid SkinnedMeshRenderer, which contains the proper bone mappings from the rig in the scene to the mesh. Also notice that after we’re done with the “Plane” object, we destroy it, because we don’t need it any more. The Mesh and Material assignment is essentially the same as before. Here’s the function.

    private void CreateSkinnedModel(Transform parent, Mesh mesh, Material mat)
    {
        Transform planeXfrm = TransformUtils.GetTransformWithName(parent, "Plane", TransformUtils.StringMatch.Exact);
        SkinnedMeshRenderer rigSkinnedRenderer = planeXfrm.GetComponent< SkinnedMeshRenderer >();
        if (rigSkinnedRenderer != null)
        {
            GameObject obj = new GameObject("body_skinned");
            obj.transform.parent = parent;
            SkinnedMeshRenderer skin = obj.AddComponent< SkinnedMeshRenderer >();
            skin.sharedMaterial = mat;
            skin.sharedMesh = mesh;
            skin.bones = rigSkinnedRenderer.bones;

            GameObject.Destroy(planeXfrm.gameObject);
        }
    }

And the call.

CreateSkinnedModel(rigObj.transform, mesh, mat);

And finally, we have our fully skinned character model!

body_skinned

Conclusion

With this dynamic model loading process, you can probably see how we can easily load up any FBX resource that we want, dig into the prefab hierarchy, and pull out a mesh or object, skinned or not, and that having a uniform naming convention would help with this. You’d be able to call character “01” with costume “3” by using the string “[01.3]” in the filename to apply to rig “A”, and mix and match accordingly, while loading only the FBX files that you absolutely need to at any given time. It’s probably pretty obvious that this is just the bare bones for getting a custom character system working, but I think this is the core of the work that needs to be done. Another thing we can do is attach an Animator and apply different animation clips, which requires loading an AnimationController, but that’s beyond the scope of this subject. We can also play around with assigning different materials or textures, which is also out of scope of this blog entry. Anyway, I hope this helps some Unity developers who are interested in introducing character customization into their game, or even helps shed some light to non-developers into the work that’s involved in getting such a system working.

Make it fun!

  • Unity 5.1.1f1
  • Blender 2.74
This entry was posted in Dev, Programming. Bookmark the permalink.

2 Responses to Building Character Customization (Part 2)

  1. Casper says:

    Dear a_a,

    I love the tutorial because I was strugeling with this for days now.
    Is it possible that you make a video tutorial about it too?
    Because English isn’t my native language so reading english makes me not understand is as well as a video.

    Casper

    • a_a says:

      Hello Casper, I’m glad you enjoyed the Character Creation article. I plan on eventually preparing video on the subject, but not for about another month or so. If you have any specific questions, feel free to send me an email and maybe I can help out.

Leave a Reply

Your email address will not be published. Required fields are marked *