您的位置:首页 > 移动开发 > Unity3D

unity人物模型换装系统浅析

2017-11-23 15:52 951 查看
*****最近研究了一下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.给不同的部位实施换装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: