1
\$\begingroup\$

I'm very new to Unity. I'm messing around, just trying to get my bearings, but I'm having trouble getting a character model to animate with the clothes correctly. This is the asset that I'm using.

I've created a ThirdPersonController, and dropped my model into it. When I hit play, the base character moves and is animated, but the clothes stay in the default position.

The ReadMe for the asset says:

Attaching clothing(Classes): Add the "AttachToBody" script to the clothing, the cloths must be inside the character to work.

I believe I have done this but I could be wrong. I have an error in Unity which says

Wrong parent body

Which I can see in the code for the AttachToBody.cs

    if (bodyBones == null) 
    {
        Debug.LogError ("Wrong parent body.");
        return;
    }

Could somebody help me out and tell me where I'm going wrong please?

I've attached a screenshot for reference (you'll need to open in a new tab to see the hierarchy properly).

screenshot

Here is the full AttachToBody.cs script

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * This matches the cloth movement to a character, the clothing must be inside the character.
 **/
public class AttachToBody : MonoBehaviour
{

    void Start ()
    {
        int i = 0;
        Transform rootParent = transform.root.transform;
        GameObject target;
        Transform[] bodyBones = null;
        for (i = 0; i < rootParent.GetChildCount (); i++)
        {
            target = rootParent.GetChild (i).gameObject;
            if (target.GetComponent<SkinnedMeshRenderer> () != null)
            {
                bodyBones = target.GetComponent<SkinnedMeshRenderer> ().bones;
                break;
            }
        }

        if (bodyBones == null) 
        {
            Debug.LogError ("Wrong parent body.");
            return;
        }

        GameObject Attachment;

        for(i = 0; i < transform.GetChildCount(); i++)
        {
            Attachment = transform.GetChild(i).gameObject;
            if (Attachment.GetComponent<SkinnedMeshRenderer> () != null) 
            {
                Attachment.GetComponent<SkinnedMeshRenderer> ().bones = bodyBones;
            }
        }
    }
}

So I can determine that the following line is null, but I'm not really sure what target is or where to go from there.

target.GetComponent<SkinnedMeshRenderer> () != null

Why doesn't my character's outfit animate with the character model?

\$\endgroup\$
  • \$\begingroup\$ So bodyBones is null, but how is bodyBones populated? We'll need to see that code before we can tell you where to place the objects. \$\endgroup\$ – DMGregory Oct 16 '17 at 12:42
  • \$\begingroup\$ Okay, I'll have to update the question when I get to my PC. Thanks for the pointer; I know I should've included that. It was an oversight when writing the question! \$\endgroup\$ – Donglecow Oct 16 '17 at 12:44
  • \$\begingroup\$ I've edited the OP to include the full script now. \$\endgroup\$ – Donglecow Oct 16 '17 at 19:50
2
\$\begingroup\$

The relevant portion of the code is here:

int i;
Transform rootParent = transform.root.transform;
GameObject target;
Transform[] bodyBones = null;
for (i = 0; i < rootParent.GetChildCount (); i++)
{
    target = rootParent.GetChild (i).gameObject;
    if (target.GetComponent<SkinnedMeshRenderer> () != null)
    {
        bodyBones = target.GetComponent<SkinnedMeshRenderer> ().bones;
        break;
    }
}

This says it's expecting your transform hierarchy to look something like this:

  • Character root object (this should not be parented under any other scene object)
    • Some number of child objects (sound emitters, colliders, etc)
    • Character visual (the GameObject with the SkinnedMeshRenderer component)
    • Maybe more child objects
      • Maybe some grand children
        • Clothing object (the one running the AttachToBody script)

ie. The character's skinned mesh must be a direct child of the clothing object's most distant ancestor.

Myself, I'd usually use a different style, replacing the above code with the following:

Transform[] bodyBones = null;
var skinnedMesh = transform.parent.GetComponentInChildren<SkinnedMeshRenderer();
if(skinnedMesh != null)
    bodyBones = skinnedMesh.bones;

With this, your clothing item can be:

  • a direct child of the Skinned Mesh
  • a sibling of the Skinned Mesh under a common direct parent
  • an aunt / great aunt of the Skinned Mesh, where the direct parent of the clothing item is a grandparent or great grandparent of the Skinned Mesh

Using the clothing item's direct parent rather than its root gives you more flexibility if you want to use empty GameObjects as folders to organize your scene, or bundle together content that needs to be enabled/disabled/moved/searched as a group.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks a lot for the in depth response. I'll revisit this tonight and try out what you suggested. How does the other style you suggested make it more flexible? Or is that a bit too advanced for the scope of this question? \$\endgroup\$ – Donglecow Oct 17 '17 at 7:37
  • \$\begingroup\$ I took another look at this. I think I messed up the model while trying to get it working. I set up a new character and used the script style you recommended and it's working! It looks like the asset's original script was not behaving as intended in the first place! \$\endgroup\$ – Donglecow Oct 17 '17 at 20:03
0
\$\begingroup\$

For those interested in the steps I took to fix this, here is what I did based on DMGregory's answer.

To start with, I created an entirely new character from the same asset. The hierarchy is:

ThirdPersonController
|--  PlayerModel
|----    CharArmature
|------      CharBaseM
|----    WarriorMale
|------       CharArmature
|--------       etc...
|------      TSM_NonSym
|------      TSM_Sym
|----    Camera

I created a new script to use instead of the included AttachToBody.cs script, as DMGregory suggested and attached this to ThirdPersonController.PlayerModel.WarriorMale on the WarriorMale object. The new script is below.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * This matches the cloth movement to a character, the clothing must be inside the character.
 **/
public class AttachToMesh : MonoBehaviour
{

    void Start()
    {
        int i = 0;
        Transform rootParent = transform.root.transform;
        GameObject target;
        Transform[] bodyBones = null;
        var skinnedMesh = transform.parent.GetComponentInChildren<SkinnedMeshRenderer>();
        if (skinnedMesh != null)
        {
            bodyBones = skinnedMesh.bones;
        }

        if (bodyBones == null)
        {
            Debug.LogError("Wrong parent body.");
            return;
        }

        GameObject Attachment;

        for (i = 0; i < transform.GetChildCount(); i++)
        {
            Attachment = transform.GetChild(i).gameObject;
            if (Attachment.GetComponent<SkinnedMeshRenderer>() != null)
            {
                Attachment.GetComponent<SkinnedMeshRenderer>().bones = bodyBones;
            }

        }
    }
}

Which caused the clothes to animate with the player model. I double checked the original script in this position (and descendants) in the hierarchy and was still unable to get it to animate, but when I used the new AttachToMesh.cs script, it worked perfectly, as can be seen in the screenshot below of the idle animation of my player model, rather than the default T-Shape pose.

animated character

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.