unity3d 模型换装系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jinsenianhua2012/article/details/46966193

现在公司的游戏虽然也实现了换装,但是存在一定的问题。我们项目中的换装系统的实现是这样的:一套没有蒙皮信息的人物空骨骼模型(虚拟体),头、身体、武器是独立于人物骨骼的具有蒙皮信息的模型。换装时将模型置为“T-pos”状态,删除需要身体上对应的meshpart, 然后将新的模块模型拷贝到角色骨骼下面,将蒙皮所依赖的骨骼根据名称拷贝到人物模型对应的骨骼下面。这样虽然也实现了换装,但却在人物骨骼中多添加了许多骨骼,造成资源的浪费,而且每次换装都会使模型动画置到默认状态下。

一直想完善现在项目的化妆系统,这个周末终于有时间了,于是利用周天重写了一个简单的换装系统,以此验证一下我设想的换装是否可行。如果可行,便整合到目前的项目中。

其实原理很简单,提取换装模型的蒙皮信息,在人物骨骼中按照提取出来的蒙皮信息重新实现一遍。

说了一大堆废话,还是直接上代码吧:

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

public class ActorChangeMeshPart : MonoBehaviour {

    private Transform source;
    private Transform target;

    private GameObject sourceobj;
    private GameObject targetobj;

    private Dictionary<string, Transform> _boneDic = new Dictionary<string, Transform>();
    private Dictionary<string, SkinnedMeshRenderer[]> targetSmr = new Dictionary<string, SkinnedMeshRenderer[]>();

    private Animator animator;
    private AnimationClip mClip;

    public static ActorChangeMeshPart instance;

	// Use this for initialization
	void Start () {
        instance = this;

        InstantiateSkeleton();

        InitAvatar();
	}
	
	// Update is called once per frame
	void Update () {
	
	}

    void InstantiateSkeleton()
    {
        _boneDic.Clear();

        BuildBoneMap(transform, _boneDic);
    }

    public void BuildBoneMap(Transform parent, Dictionary<string, Transform> map)
    {
        try
        {
            for(int i = 0; i< parent.childCount; i++)
            {
                Transform child = parent.GetChild(i);
                if (child == null)
                    continue;
                map.Add(child.name, child);

                BuildBoneMap(child, map);
            }
        }
        catch (System.Exception ex)
        {
            Debug.LogWarning("already has bone " + parent.name);
        }
    }

    public Transform GetBone(string name)
    {
        if (!_boneDic.ContainsKey(name))
            return null;
        return _boneDic[name];
    }

    public void ChangePart(string partName, string resPath)
    {
        if(string.IsNullOrEmpty(resPath))
        {
            RemoveMeshPart(partName);
            return;
        }

        string path = string.Format("Actor/{0}", resPath);
        GameObject objMeshPart = Resources.Load(path) as GameObject;
        if (objMeshPart == null)
            return;
        GameObject pMeshs = GameObject.Instantiate(objMeshPart, Vector3.zero, Quaternion.identity) as GameObject;

        SetMeshPart(partName, pMeshs);
        GameObject.DestroyImmediate(pMeshs);
    }

    public void SetMeshPart(string partName, GameObject pMeshs)
    {
        if (targetSmr == null)
        {
            targetSmr = new Dictionary<string, SkinnedMeshRenderer[]>();
        }

        RemoveMeshPart(partName);

        SkinnedMeshRenderer[] meshRenders = pMeshs.GetComponentsInChildren<SkinnedMeshRenderer>();
        if (meshRenders.Length == 0)
        {
            Debug.LogWarning("************** not has skinnedMeshrenders ");
            return;
        }

        SkinnedMeshRenderer[] newMeshRenders = new SkinnedMeshRenderer[meshRenders.Length];
        for (int i = 0; i < meshRenders.Length; i++)
        {
            GameObject meshObj = new GameObject();
            meshObj.name = meshRenders[i].name;
            meshObj.transform.parent = transform;
            meshObj.transform.localPosition = meshRenders[i].transform.localPosition;
            meshObj.transform.localRotation = meshRenders[i].transform.localRotation;
            meshObj.transform.localScale = meshRenders[i].transform.localScale;
            SkinnedMeshRenderer pSkine = meshObj.AddComponent<SkinnedMeshRenderer>();

            List<Transform> tempBones = new List<Transform>();
            foreach (Transform bone in meshRenders[i].bones)
            {
                if(GetBone(bone.name))
                {
                    tempBones.Add(GetBone(bone.name));
                }
            }
            pSkine.sharedMesh = meshRenders[i].sharedMesh;
            pSkine.bones = tempBones.ToArray();
            pSkine.material = meshRenders[i].material;
            if (GetBone(meshRenders[i].rootBone.name) == null)
            {
                Debug.Log("rootbone name is "+ meshRenders[i].rootBone.name);
            }
            pSkine.rootBone = GetBone(meshRenders[i].rootBone.name);
            pSkine.localBounds = meshRenders[i].localBounds;

            newMeshRenders[i] = pSkine;
        }
        targetSmr.Add(partName, newMeshRenders);
    }

    public SkinnedMeshRenderer[] GetMeshPart(string partName)
    {
        try
        {
            return targetSmr[partName];
        }
        catch (System.Exception ex)
        {
        	return null;
        }        
    }

    public void RemoveMeshPart(string partName)
    {
        SkinnedMeshRenderer[] parts = GetMeshPart(partName);
        if(parts == null)
            return;
        for(int i = 0;i <parts.Length; i++)
        {
            GameObject.DestroyImmediate(parts[i].gameObject);
        }

        targetSmr.Remove(partName);
    }   

    void InitAvatar()
    {
        ChangePart("head", "X_JianNan/SkinnedMesh/T_01");
        ChangePart("body", "X_JianNan/SkinnedMesh/Y_01");
        ChangePart("weapon", "X_JianNan/SkinnedMesh/W_01");
    }

    void OnGUI()
    {
        // 文本显示
        GUI.Label(new Rect(50, 20, 200, 50), "换装系统");

        // 头换模型
        GUI.color = Color.yellow;  
        GUI.backgroundColor = Color.red; 
        if (GUI.Button(new Rect(50, 50, 200, 30), "ChangeHead1"))
        {
            ChangePart("head", "X_JianNan/SkinnedMesh/T_01");
        }
        GUI.color = Color.yellow;  
        GUI.backgroundColor = Color.red; 
        if (GUI.Button(new Rect(50, 80, 200, 30), "ChangeHead2"))
        {
            ChangePart("head", "X_JianNan/SkinnedMesh/T_02");
        }
        GUI.color = Color.yellow;  
        GUI.backgroundColor = Color.red; 
        if (GUI.Button(new Rect(50, 110, 200, 30), "ChangeHead3"))
        {
            ChangePart("head", "X_JianNan/SkinnedMesh/T_03");
        }

        // 身体换模型
        GUI.color = Color.yellow; 
        GUI.backgroundColor = Color.red; 
        if (GUI.Button(new Rect(50, 140, 200, 30), "ChangeBody1"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_01");
        }
        GUI.color = Color.yellow;  
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 170, 200, 30), "ChangeBody2"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_02");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 200, 200, 30), "ChangeBody3"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_03");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 230, 200, 30), "ChangeBody4"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_04");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 260, 200, 30), "ChangeBody5"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_05");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 290, 200, 30), "ChangeBody6"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_06");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 320, 200, 30), "ChangeBody7"))
        {
            ChangePart("body", "X_JianNan/SkinnedMesh/Y_07");
        }

        // 武器模型
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 350, 200, 30), "ChangeWeapon1"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_01");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 380, 200, 30), "ChangeWeapon2"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_02");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 410, 200, 30), "ChangeWeapon3"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_03");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 440, 200, 30), "ChangeWeapon4"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_04");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 470, 200, 30), "ChangeWeapon5"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_05");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 500, 200, 30), "ChangeWeapon5"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_06");
        }
        GUI.color = Color.yellow;
        GUI.backgroundColor = Color.red;
        if (GUI.Button(new Rect(50, 530, 200, 30), "ChangeWeapon7"))
        {
            ChangePart("weapon", "X_JianNan/SkinnedMesh/W_07");
        }
        
    }
}


我的模型都放在Resources下的Actor文件夹,大家可以根据自己的文件路径重写文件路径即可,呵呵。这只是一个小小的验证demo。

猜你喜欢

转载自blog.csdn.net/jinsenianhua2012/article/details/46966193