unity人物模型换装系统浅析

 *****最近研究了一下unity中人物模型的换装系统感觉挺有意思的!特意来分享给大家。*****
 首先给大家介绍一下3D人物模型的相关知识:模型一般分为静态模型和动态模型嘛!静态模型简单的来说就是不会动的模型。那么要给一个静态模型换装是不是很简单了!只需要替换它的网格和材质就行了呗!很容易的完成一个换装。但是要是一个动态模型呢?就稍微有点复杂了哦!
 我们继续来谈谈一个动态模型它的换装复杂在哪里啊!既然是动态的模型嘛!那么它首先肯定是会动的,动很容易的嘛!添加个动画就ok了啊!但是对于换装而言这一动可就容易出问题了哦!大家想啊!一个模型要它动起来,是不是需要骨骼才能让它动起来啊!有了骨骼才会有各种人物复杂的动作对吧!而这个骨骼其实就是我们在Unity3D空间中各个点的位置信息。即Transform组件。我们通过控制这些骨骼的位置信息来操作人物的各种动作。好了,模型就介绍到这里了吧!我们进入我们的主题---动态模型的换装系统。
 大家先试想一下啊!我们也像替换静态模型一样,直接给模型替换材质和网格行吗?(PS:思考一分钟)原因很简单的呢!你想啊!人物模型是动态的,是通过骨骼来动的吧!如果没有骨骼了的话,可能你换了装饰,导致的结果就是动作与装饰不匹配。这样的话就会太假了!比如当你抬起一个刀剑时,准备攻击时,结果发现刀还在后面呢!这就不好了啊!
 现在大概讲一下动态模型换装的思路吧!**对于一个动态模型的换装,首先我们得要有几套衣服吧!这些衣服按照部位来区分,比如:头发,头部,手,身体,脚等等。那么我们就需要一个原模型了,可以理解为一个拥有多套衣服的模型。然后我们就要对原模型进行Copy一份了。复制什么呢?当然是赋值它的皮肤骨骼和材质啦!最后给一个新的模型换上一套衣服即可!**
 那么下面我们通过代码来具体实现一下:
using UnityEngine;
using System.Collections.Generic;

public class AvatarSystem : MonoBehaviour
{

    //原模型,所有的可以替换的部件存储在这里
    //原模型只是提供资源的作用
    private Transform source;
    //目标骨架(骨架其实就是一系列可以运动的点的位置信息)我们在这个目标上进行换装的操作
    private Transform target;

    //临时的源模型(中间的变量)
    //作为交换值使用的,没有其他的作用
    private GameObject tempsource;
    //临时的目标骨架
    private GameObject temptarget;
    //建立一个模型资源字典,存储对应上面的source资源
    //参数 Dictionary<部位,<皮肤编号,个部位的位置信息>>
    private Dictionary<string, Dictionary<string, Transform>> data = new Dictionary<string, Dictionary<string, Transform>>();
    //用来存储骨架上的资源信息数组
    private Transform[] hips;
    //目标皮肤字典,替换这里面的内容就行
    private Dictionary<string, SkinnedMeshRenderer> targetSmr = new Dictionary<string, SkinnedMeshRenderer>();

    private Animation mAnim;
    //表示穿的衣服的编号
    private int count = 0;

    // Use this for initialization
    void Start()
    {
        InstantiateAvatar();
        LoadAvatarData(source);
        LoadSkeleton();
        //获取到骨架上面的位置信息
        hips = target.GetComponentsInChildren<Transform>();
        //得到所有的动作
        mAnim = target.GetComponentInChildren<Animation>();

        InitAvatar();
    }

    /// <summary>
    /// 实例化原模型赋值给临时的模型方法
    /// </summary>
    void InstantiateAvatar()
    {
        //临时原模型接收加载源资源 
        tempsource = Instantiate(Resources.Load("FemaleAvatar")) as GameObject;
        //再对原资源赋值
        source = tempsource.transform;
        //实例化出原模型并将其隐藏
        tempsource.SetActive(false);
    }


    /// <summary>
    /// 这么多的工作只是从原模型中取出部位,然后将部位重新作为一个新的模型,之后往里面添加东西
    /// </summary>
    /// <param name="source"></param>
    void LoadAvatarData(Transform source)
    {
        //安全校验一下
        if ( source== null)
            return;
        //获取资源的所有皮肤存到数组中去
        SkinnedMeshRenderer[] parts = source.GetComponentsInChildren<SkinnedMeshRenderer>(true);
        //初始化data,将资源添加到data字典中
        foreach (SkinnedMeshRenderer part in parts)
        {
            string[] partName = part.name.Split('-');
            //如果当前字典中没有这个对象,
            if (!data.ContainsKey(partName[0]))
            {
                //往字典中添加部位
                data.Add(partName[0], new Dictionary<string, Transform>());
                //创建一个部位
                GameObject partObj = new GameObject();
                //部位的名字
                partObj.name = partName[0];
                //设置创建的部位的父物体
                partObj.transform.parent = target;
                //添加皮肤组件
                targetSmr.Add(partName[0], partObj.AddComponent<SkinnedMeshRenderer>());
            }
            //添加具体的部位中的皮肤编号的具体皮肤
            //这样一个data中的数据才算赋值完成
            data[partName[0]].Add(partName[1], part.transform);

        }
    }


    /// <summary>
    /// 加载骨骼模型方法
    /// </summary>
    void LoadSkeleton()
    {
        temptarget = Instantiate(Resources.Load("targetmodel")) as GameObject;
        target = temptarget.transform;
    }



    /// <summary>
    /// 换装具体方法(部位,衣服)
    /// </summary>
    /// <param name="part"></param>
    /// <param name="item"></param>
    void ChangeMesh(string part, string item)
    {
        //取出衣服 获取当前需要替换的皮肤
        SkinnedMeshRenderer smr = data[part][item].GetComponent<SkinnedMeshRenderer>();
        //获取target上与source对应的骨骼 这里不能直接把骨骼直接赋值过去
        //存放将要替换的骨骼的位置信息
        List<Transform> bones = new List<Transform>();
        //遍历smr中的骨骼然后和我们要替换的目标骨骼进行对比
        foreach (Transform bone in smr.bones)
        {
            foreach (Transform hip in hips)
            {
                //没有找到
                if (hip.name != bone.name)
                    continue;
                //找到添加上去
                bones.Add(hip);
                break;
            }
        }
        //进行替换皮肤,骨骼,材质

        targetSmr[part].sharedMesh = smr.sharedMesh;//替换皮肤
        targetSmr[part].bones = bones.ToArray();//替换骨骼
        targetSmr[part].materials = smr.materials;//替换材质

    }

    //init avatar resource
    //初始化换装系统的衣服数据
    void InitAvatar()
    {
        //大衣
        ChangeMesh("coat", "003");
        //头部
        ChangeMesh("head", "003");
        //头发
        ChangeMesh("hair", "003");
        //裤子
        ChangeMesh("pant", "003");
        //脚
        ChangeMesh("foot", "003");
        //手
        ChangeMesh("hand", "003");

    }

    /// <summary>
    /// 绘制GUI按钮方法进行点击换装
    /// </summary>
    void OnGUI()
    {
        if (GUILayout.Button("Head"))
        {
            if (count == 1)
            {
                ChangeMesh("head", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("head", "003");
                count = 1;
            }

        }

        if (GUILayout.Button("Pant"))
        {
            if (count == 1)
            {
                ChangeMesh("pant", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("pant", "003");
                count = 1;
            }
        }

        if (GUILayout.Button("Hair"))
        {
            if (count == 1)
            {
                ChangeMesh("hair", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("hair", "003");
                count = 1;
            }
        }

        if (GUILayout.Button("Hand"))
        {
            if (count == 1)
            {
                ChangeMesh("hand", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("hand", "003");
                count = 1;
            }
        }

        if (GUILayout.Button("Foot"))
        {
            if (count == 1)
            {
                ChangeMesh("foot", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("foot", "003");
                count = 1;
            }
        }
        if (GUILayout.Button("Coat"))
        {
            if (count == 1)
            {
                ChangeMesh("coat", "001");
                count = 0;
            }
            else
            {
                ChangeMesh("coat", "003");
                count = 1;
            }
        }

    }

}

效果图:
模型效果图
主要名称注释

这就是一个动态换装的代码思路了,大家学会了吗?不是很难的哦!只要明白思路就很简单的啦!

小结:动态人物换装:
1.加载原模型;
2.将原模型上的皮肤存入Data中;
3.加载骨骼;
4.将Data中的皮肤取出,放入骨骼中;
5.给不同的部位实施换装。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值