Unity3D简单换装系统

根据Siki学院的换装教程,有需要可以自行去学习,完整项目我上传了

在这:https://download.csdn.net/download/qq_34421469/12251517

主要代码贴在下面

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

public class AvatarSys : MonoBehaviour
{

    public static AvatarSys instance;

    //来源模型
    private Transform source;
    //目标骨架
    private Transform target;

    //存放来源模型的信息,分别为部位名字,部位编号,部位的SkinnedMeshRenderer组件
    //根据部位名字,部位编号取得想要的部位
    private Dictionary<string, Dictionary<string, SkinnedMeshRenderer>> sourceData =
        new Dictionary<string, Dictionary<string, SkinnedMeshRenderer>>();

    //存放目标骨架的信息,分别为部位名字,部位上的SkinnedMeshRenderer组件
    //没有编号是因为target上只有一套
    private Dictionary<string, SkinnedMeshRenderer> targetSmr =
        new Dictionary<string, SkinnedMeshRenderer>();

    //存放目标骨架的骨架信息,用于mesh绑定骨架
    private Transform[] hips;

    //部位信息,目标骨架初始化为模型时需要的部位,注意命名是依据来源模型上的部位命名的
    string[,] avatarStr = new string[,]{{"face","1"},{"hair","1"},
    {"pants","1"},{"shoes","1"},{"top","1"},{"eyes","1" } };

    // Use this for initialization
    void Start()
    {
        instance = this;
        InstantiateSource();//实例化来源模型
        InstantiateTarget();//实例化目标骨架
        SaveData();//存储来源模型和目标骨架的信息
        InitAvatar();//将目标骨架初始化为模型
    }
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            int i = Random.Range(1, 5);
            ChangeMesh("hair", i.ToString());
        }
    }
    /// <summary>
    /// 加载模型资源
    /// </summary>
    void InstantiateSource()
    {
        GameObject sourceObj = Instantiate(Resources.Load("FemaleModel")) as GameObject;
        source = sourceObj.transform;
        sourceObj.SetActive(false);
    }

    /// <summary>
    /// 加载目标显示物体
    /// </summary>
    void InstantiateTarget()
    {
        GameObject targetObj = Instantiate(Resources.Load("FemaleTarget")) as GameObject;
        target = targetObj.transform;
        hips = target.GetComponentsInChildren<Transform>();
    }

    /// <summary>
    /// 保存数据
    /// </summary>
    void SaveData()
    {
        if ((source == null) || (target == null))
            return;

        SkinnedMeshRenderer[] parts = source.GetComponentsInChildren<SkinnedMeshRenderer>(true);//true表示把隐藏部位的组件也获得
        foreach (SkinnedMeshRenderer part in parts)
        {
            string[] partName = part.name.Split('-');
            if (!sourceData.ContainsKey(partName[0]))//每有一种新类型的部位
            {
                //每有一种新类型的部位就在骨架下生成一个空GameObject
                GameObject partobj = new GameObject();
                partobj.name = partName[0];
                partobj.transform.parent = target;
                //部位类型只记录一次
                sourceData.Add(partName[0], new Dictionary<string, SkinnedMeshRenderer>());
                //targetSmr只记录一套部位的信息,例如裤子有两套模型,只记录一套的
                //因为target是用来展示的,各种部位只要一套即可
                targetSmr.Add(partName[0], partobj.AddComponent<SkinnedMeshRenderer>());
            }
            //sourceData记录所有部位信息
            sourceData[partName[0]].Add(partName[1], part);
        }
    }

    /// <summary>
    /// 换装(Mesh,骨骼,材质)
    /// </summary>
    /// <param name="part"></param>
    /// <param name="num"></param>
    public void ChangeMesh(string part, string num)//传入部位名字,编号
    {
        //因为sourceData记录所有部位信息,所以可以查找到所要的新的部位
        SkinnedMeshRenderer smr = sourceData[part][num];

        List<Transform> bones = new List<Transform>();
        //根据新的部位绑定的骨架信息,在target的骨架上找到相应的位置
        //例如头发mesh,在source中它绑定在脑袋上,那么我们在target上也要找到脑袋这个位置
        foreach (Transform bone in smr.bones)
        {
            foreach (Transform hip in hips)
            {
                if (hip.name == bone.name)
                {
                    bones.Add(hip);
                    break;
                }
            }
        }

        targetSmr[part].materials = smr.materials;//更换材质
        targetSmr[part].sharedMesh = smr.sharedMesh;//更换mesh
        targetSmr[part].bones = bones.ToArray();//将mesh绑定到合适的骨架中
    }

    /// <summary>
    /// 初始化模型
    /// </summary>
    void InitAvatar()
    {
        int length = avatarStr.GetLength(0);
        for (int i = 0; i < length; i++)
        {
            ChangeMesh(avatarStr[i, 0], avatarStr[i, 1]);
        }
    }

}

场景界面如下Unity3D简单换装系统

 

上一篇:嵌套画布优化 unity3d 2019.3


下一篇:开发Unity3D动画性能优化插件_GPU Animation Baker Basic