Unity实现换装功能

换装的核心思想:更换对象SkinnerMeshRenderer组件中骨骼(Bones),网格(sharedMesh),材质(materials)。麻烦的是要找到对应的部位,对应的SkinnerMeshRenderer组件,对应的位置。以下,介绍一种比较简单的换装过程。

通常要实现换装需要有一个带有“所有需要更换部件”的模型,如下:(图1)中FemaleModel为模型,其中Female_Hips为骨骼信息。(图2)为场景用的样子,可以看出它是很多重复部件的叠加物。


Unity实现换装功能_第1张图片
Unity实现换装功能_第2张图片

接下来说说具体的思路;

1.先制作骨骼模型

2.将原模型和骨骼模型实例化出来

3.建立字典存储所有SkinnerMeshRenderer信息

4.建立字典存储所有骨骼信息

5.将相应的信息存储在字典中

6.以名字进行一一对应,更换相应SkinnerMeshRenderer中三大件


接下来是每步详细步骤:

1.先制作骨骼模型

其实这部很简单,只需要将原模型中所有部件删除,只留下骨骼部分,如图:其中FemaleTarget就是骨骼模型


Unity实现换装功能_第3张图片

2.将原模型和骨骼模型实例化出来

    //原模型

    GameObject avatarModel;

    //骨骼模型

    GameObject avatarTarget;

    //所有骨骼信息

    Transform[] Hips;

void InitSys() {

 //实例化对应的模型并将其隐藏 

 avatarModel = Instantiate(Resources.Load("FemaleModel") as GameObject); avatarModel.SetActive(false); 

 //实例化要显示的对象并将其所有(骨骼)Transform信息收集 

 avatarTarget = Instantiate(Resources.Load("FemaleTarget") as GameObject); 

 Hips = avatarTarget.GetComponentsInChildren();

    }

3.建立字典存储所有SkinnerMeshRenderer信息

//存储模型的所有信息 //建立字典存储模型的SkinnerMeshRenderer信息

Dictionary> avaStr = new Dictionary>();

4.建立字典存储所有骨骼信息

//建立字典存储要显示对象的skinnerMeshRenderer信息

Dictionary avaSmr = new Dictionary();

5.将相应的信息存储在字典中

void SaveAvatarData() {

    SkinnedMeshRenderer[] skis = avatarModel.GetComponentsInChildren();

    foreach (SkinnedMeshRenderer ski in skis) {

    string[] names = ski.name.Split('-');

    //如果字典中没有存储这个部位

    if (!avaStr.ContainsKey(names[0])) {

    //那么就新建一个对象当做这个对象

    GameObject part = new GameObject();

    part.name = names[0];

    //set父级为要显示的任务骨骼

    part.transform.parent = avatarTarget.transform;

    //并且给它添加ski组件并加入字典中

    avaSmr.Add(names[0], part.AddComponent());

    //存入模型字典并实例化相应子字典

    avaStr.Add(names[0], new Dictionary());

    }

    //将序号和SkinnerMeshRenderer信息存入模型字典

    avaStr[names[0]].Add(names[1], ski); } }

6.以名字进行一一对应,更换相应SkinnerMeshRenderer中三大件

 //换装 

 //参数:换装部位名称,序号 

 void ChangeMesh(string name,string num) { 

 //从模型字典中拿到相应的SkinnerMeshRenderer 

 SkinnedMeshRenderer skm = avaStr[name][num]; 

 //创建集合来存储(骨骼)Transform信息

List bones = new List();

        foreach (var trans in skm.bones)

        {

            foreach (var bone in Hips)

            {

                if (bone.name == trans.name)

                {

                    bones.Add(trans);

                    break;

                }

            }

        }

        avaSmr[name].bones = bones.ToArray();

        avaSmr[name].materials = skm.materials;

        avaSmr[name].sharedMesh = skm.sharedMesh;

    }

至此,基本的换装的过程就此基本完成,接下来就是让要显示的模型有一个初始状态

7.先建立字典存储模型最初的状态:

//显示初始状态

    //建立数组

    string[,] avatar = new string[,] { {"face","1" }, { "top", "1" }, { "pants", "1" }, { "hair", "1" },

        { "eyes", "1" }, { "shoes", "1" } };

8.依次调用换装方法(注意此处遍历的是数组的行数而不是数组长度)

void InitAvatar()

    {

        for (int i = 0; i < avatar.GetLength(0); i++)

        {

            ChangeMesh(avatar[i, 0], avatar[i, 1]);

        }

    }

好了,现在试下调用如上方法就可以让模型显示出来啦。

void Start () {

        InitSys();

        SaveAvatarData();

        InitAvatar();

    }


进行换装就是调用ChangeMesh方法就好。如下举个小栗子~

void Update () {

        print(ani.isPlaying);

        if (Input.GetKeyDown(KeyCode.Space))

        {

            ChangeMesh("top", "2");

        }

}


Ps:这里还有一个问题就是模型的动画没有播放出来(虽然ani.isPlaying结果是true)。我怀疑是我中途换了Unity版本导致。就不深究啦~~

如上如果有任何不严谨或是错误的地方,欢迎各位指正~~嘻嘻~~

                                                                                                                                                                                                不忘初心的Tiny

                

你可能感兴趣的:(Unity实现换装功能)