- Home /
Scripted mesh combine with animation such as Armor, Clothing, etc.
Just to get everyone on the same page, I am not interested in an external bundle or plugin from the Asset Store to resolve this issue. I am not a fan of the 'answer your question with a purchase' mentality.
I have several skinned meshes which have a weight table, and are animated(created with 3ds Max). I have split these meshes up, so they could be re-combined through code, to create a variety of armor configurations.
Think of your typical RPG, where a user could have several options for helms, tunics, boots, pants, etc.
I've already found a solution to my issue, but I'm wanting to know if there is a BETTER solution. The way I have done this was tedious, and knowing Unity, there should be a built in way to do this without so much hassle on my end. I also wanted to post this, in case there are others out there, like myself, who wanted to do this, but couldn't find a way.
Here is a script I wrote to output the bones for the child mesh:
using UnityEngine;
public class DiscoverBones : MonoBehaviour {
// Use this for initialization
void Start () {
Debug.Log ("**** Bone discovery ****");
SkinnedMeshRenderer smr = gameObject.GetComponent<SkinnedMeshRenderer>();
for (int i = 0; i < smr.bones.Length; i++) {
Debug.Log ("Bone:"+i+"|"+smr.bones[i].name);
}
Debug.Log ("--- end ---");
}
}
This will output something like this:
**** Bone discovery ****
Bone:0|Bip01 L Clavicle
Bone:1|Bip01 Spine1
Bone:2|Bip01 Spine
Bone:3|Bip01 R Clavicle
Bone:4|Bip01 Pelvis
Bone:5|Bip01 L UpperArm
Bone:6|Bip01 R UpperArm
--- end ---
Once I record the bones, I remove the DiscoverBones script, then I can remove the mesh from the skeleton, add it as a prefab, and reference it with this script:
using UnityEngine;
public enum MeshSlot
{
Head = 1,
Chest = 2,
Arms = 4,
Skirt = 8,
SleeveCuff = 16,
Hands = 32,
GloveCuff = 64,
Legs = 128,
Shins = 256,
Boots = 512,
BootCuff = 1024
};
public class ArmorPiece : MonoBehaviour {
public MeshSlot slotMask;
public GameObject Prefab; // reference to the Child Mesh from above...
public string[] Bones;
public int RootBone;
public Texture Texture;
}
In this script, I take the bones listed in the DiscoverBones output, and put it in the Bones array. I also put in the RootBone.
So now I can call this function on the original parent object with the skeleton, passing in the prefab with the ArmorPiece attached to it:
// root mesh GameObject of the original imported mesh (the one with the Animator)
public Transform MyMesh;
public Transform Biped; // the biped GameObject imported
private void CreateNewArmorMesh( ArmorPiece armorPiece){
SkinnedMeshRenderer armorRef = armorPiece.Prefab.GetComponent<SkinnedMeshRenderer> ();
var NewObj = new GameObject( armorRef.gameObject.name );
NewObj.transform.parent = MyMesh.transform;
var NewRenderer = NewObj.AddComponent<SkinnedMeshRenderer>();
Transform[] boneMap = new Transform[armorRef.bones.Length];
for( int i = 0; i < armorPiece.Bones.Length; i++){
boneMap[i] = FindChildByName(armorPiece.Bones[i], Biped);
}
NewRenderer.bones = boneMap;
NewRenderer.sharedMesh = armorRef.sharedMesh;
NewRenderer.sharedMaterials = armorRef.sharedMaterials;
NewRenderer.material.SetTexture ("_MainTex", armorPiece.Texture);
NewRenderer.rootBone = boneMap[armorPiece.RootBone];
}
private Transform FindChildByName( string ThisName, Transform ThisGObj ){
Transform ReturnObj = null;
if (ThisGObj.name == ThisName) {
return ThisGObj.transform;
}
foreach ( Transform child in ThisGObj )
{
ReturnObj = FindChildByName( ThisName, child );
if( ReturnObj ){
return ReturnObj;
}
}
return null;
}
As you can see, this is a real hassle, and not something easy to understand how to do if you're new to Unity. I figured there might be some setting or a way to reference the original mesh for the prefab. I just don't know enough about Unities animation and render system to know where to look.