本文向大家介绍Unity换装原理及其简单实现
首先附上效果图:
本文的源码我将上传提供大家下载点击打开链接
实现原理:控制角色SkinMeshRenderer组件的mesh、materials、bones属性来实现角色换装
在该Demo素材中,主角是由多个网格拼接完成
其中网格对象上添加了SkinMeshRenderer组件,并指定了material、mesh、root bone
我们不采用这种方式来渲染角色
我们把角色的全部materials、mesh、bones绑定到一个SkinMeshRenderer上,其中这种做法需要注意的是materials和bones需要一一对应起来,否则渲染紊乱
好的,接下来我将写一个实例实现换装(下载参考源码方便理解)
我们Ctrl+D复制Female对象除了Female_Hips子节点保留(骨骼节点),其他都Delete
在Female节点上添加SkinMeshRenderer组件
首先随机获取到子网格
GameObject go = list[Random.Range(0, list.Count)]; SkinnedMeshRenderer goSMR = go.GetComponent<SkinnedMeshRenderer>(); if (goSMR) { CombineInstance ci = new CombineInstance(); ci.mesh = goSMR.sharedMesh; ciList.Add(ci); materialList.AddRange(goSMR.materials); //遍历角色所有的骨骼节点来找到相对应得骨骼 GetBone(goSMR.bones); }
其中遍历节点方式是通过节点名字来获取,将获得骨骼节点,通过遍历获得
foreach (Transform x in t) { foreach (Transform y in allBones) { if (y.name.Equals(x.name)) { boneList.Add(y); break; } } }
最后生成角色蒙皮
mesh = new Mesh(); mesh.CombineMeshes(ciList.ToArray(),false,false); smr.sharedMesh = mesh; smr.materials = materialList.ToArray(); smr.bones = boneList.ToArray();
最终脚本
using UnityEngine; using System.Collections; using System.Collections.Generic; [RequireComponent(typeof(SkinnedMeshRenderer))] public class GeneraterAvatar : MonoBehaviour { private enum GeneraterType { ALL, EYE, FACE, HAIR, PANT, SHOES, BODY } //可以供选择的对象列表 public List<GameObject> eyeList = new List<GameObject>(); public List<GameObject> faceList = new List<GameObject>(); public List<GameObject> hairList = new List<GameObject>(); public List<GameObject> pantList = new List<GameObject>(); public List<GameObject> shoesList = new List<GameObject>(); public List<GameObject> bodyList = new List<GameObject>(); //角色的SkinMeshRenderer组件上的材质列表 private List<Material> materialList = new List<Material>(); //角色的SkinMeshRenderer组件上的骨骼列表 private List<Transform> boneList = new List<Transform>(); //角色的子网格,对这些子网格进行拼接后形成角色的完整网格 private List<CombineInstance> ciList = new List<CombineInstance>(); //角色的网格 private Mesh mesh; //角色的骨骼节点 private Transform[] allBones; //组件 private SkinnedMeshRenderer smr; // Use this for initialization void Start () { //获取蒙皮组件 smr = this.GetComponent<SkinnedMeshRenderer>(); //随机种子 Random.seed = (int)Time.time; //获取各个骨骼节点 allBones = this.GetComponentsInChildren<Transform>(); //生成 GeneraterSkin(GeneraterType.ALL); } // Update is called once per frame void Update () { if (Input.GetKeyDown(KeyCode.Space)) { GeneraterSkin(GeneraterType.ALL); } } private void Reset() { ciList.Clear(); materialList.Clear(); boneList.Clear(); } /// <summary> /// 生成蒙皮 /// </summary> private void GeneraterSkin(GeneraterType type) { Reset(); GetNextSkin(eyeList); GetNextSkin(faceList); GetNextSkin(hairList); GetNextSkin(pantList); GetNextSkin(shoesList); GetNextSkin(bodyList); mesh = new Mesh(); mesh.CombineMeshes(ciList.ToArray(),false,false); smr.sharedMesh = mesh; smr.materials = materialList.ToArray(); smr.bones = boneList.ToArray(); } /// <summary> /// 随机获得蒙皮 /// </summary> private void GetNextSkin(List<GameObject> list) { if (list.Count > 0) { GameObject go = list[Random.Range(0, list.Count)]; SkinnedMeshRenderer goSMR = go.GetComponent<SkinnedMeshRenderer>(); if (goSMR) { CombineInstance ci = new CombineInstance(); ci.mesh = goSMR.sharedMesh; ciList.Add(ci); materialList.AddRange(goSMR.materials); //遍历角色所有的骨骼节点来找到相对应得骨骼 GetBone(goSMR.bones); } } } /// <summary> /// 遍历角色所有的骨骼节点来找到相对应得骨骼 /// </summary> /// <returns></returns> private void GetBone(Transform[] t) { foreach (Transform x in t) { foreach (Transform y in allBones) { if (y.name.Equals(x.name)) { boneList.Add(y); break; } } } } }
将其挂载到Female节点上
并为其制定相对应的对象(含SkinMeshRenderer组件)
在这个重点需要提出的是:
CombineInstance ci = new CombineInstance(); ci.mesh = goSMR.sharedMesh; ciList.Add(ci); mesh = new Mesh(); mesh.CombineMeshes(ciList.ToArray(),false,false); smr.sharedMesh = mesh;
该函数作用是将多个子网格进行拼接结合
==================== 即步 CSDN博客专栏=================
博客地址:http://blog.liujunliang.com.cn
个人网站:http://www.liujunliang.com.cn
==================== battle for programming =============
作者:qq_33747722 发表于2017/5/13 17:53:52 原文链接
阅读:70 评论:0 查看评论