Unity SkinnedMesh 换装
2016-10-20 17:49
567 查看
Unity SkinnedMesh :
游戏中常见的换装做法 :
一、直接更换贴图
二、更换静态Mesh
三、更换SkinnedMesh
前两者简单,今天需要mark下SkinnedMesh。
1.首先可以了解下SkinnedMesh的基础概念 : http://blog.csdn.net/gamemonkey/article/details/44058291 这篇文章对于入门的同学很不错。
2.Untiy中合并Mesh主要使用到了CombineMeshes接口,接下来就是可以参考Unity文档 :
https://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html
3.再来就是实例,可以在AssetsStore中搜索Skinned Mesh官方示例 :
Character Customization
注意:
a.Unity5版本以后,代码和AseetBundle有不兼容的的地方,这个我有做修改。
b.AssetBundle需要重新生成。
运行:
打开Scene:CharacterCustomization / DressingroomExample.scene
AssetBundle生成方式:
①.选中Project视图->Assets->CharacterCustomization文件夹。
②.工具栏->Character Generator->CreateAssetbundles。
4..这个工程是采用assetbundle为基础写的。所以对于部分基友们可能会造成困扰,我们需要的其实紧紧是了解SkinnedMesh实现方式,所以我写了一个直接只用Prefab的小用例在里面,这样就只使用到了下面两个C#文件和它的资源,其余无关的逻辑和框架统统可以摒弃。
运行:
打开Scene:CharacterCustomization / SkinMesh.scene
Prefab生成方式:
①.选中Project视图->Assets->CharacterCustomization文件夹。
②.工具栏->Character Generator->CreatePrefabs。
修改后的Unity工程可以去这里下载:http://download.csdn.net/detail/zhousanxi123/9659635
以下是Prefab使用SkinnedMesh的两个主要文件 :
游戏中常见的换装做法 :
一、直接更换贴图
二、更换静态Mesh
三、更换SkinnedMesh
前两者简单,今天需要mark下SkinnedMesh。
1.首先可以了解下SkinnedMesh的基础概念 : http://blog.csdn.net/gamemonkey/article/details/44058291 这篇文章对于入门的同学很不错。
2.Untiy中合并Mesh主要使用到了CombineMeshes接口,接下来就是可以参考Unity文档 :
https://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html
3.再来就是实例,可以在AssetsStore中搜索Skinned Mesh官方示例 :
Character Customization
注意:
a.Unity5版本以后,代码和AseetBundle有不兼容的的地方,这个我有做修改。
b.AssetBundle需要重新生成。
运行:
打开Scene:CharacterCustomization / DressingroomExample.scene
AssetBundle生成方式:
①.选中Project视图->Assets->CharacterCustomization文件夹。
②.工具栏->Character Generator->CreateAssetbundles。
4..这个工程是采用assetbundle为基础写的。所以对于部分基友们可能会造成困扰,我们需要的其实紧紧是了解SkinnedMesh实现方式,所以我写了一个直接只用Prefab的小用例在里面,这样就只使用到了下面两个C#文件和它的资源,其余无关的逻辑和框架统统可以摒弃。
运行:
打开Scene:CharacterCustomization / SkinMesh.scene
Prefab生成方式:
①.选中Project视图->Assets->CharacterCustomization文件夹。
②.工具栏->Character Generator->CreatePrefabs。
修改后的Unity工程可以去这里下载:http://download.csdn.net/detail/zhousanxi123/9659635
以下是Prefab使用SkinnedMesh的两个主要文件 :
using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine; using System.Xml; class CreatePrefabs { //创建Prefab [MenuItem("Character Generator/Create Prefabs")] static void Execute() { bool createdPrefabs = false; foreach (Object o in Selection.GetFiltered(typeof (Object), SelectionMode.DeepAssets)) { //1.搜索CharacterCustomization文件下的非动画模型文件 if (!(o is GameObject)) continue; if (o.name.Contains("@")) continue; if (!AssetDatabase.GetAssetPath(o).Contains("/characters/")) continue; //2.从资源创建对应的非动画模型实例 GameObject characterFBX = (GameObject)o; string name = characterFBX.name.ToLower(); Debug.Log("******* Creating prefab for: " + name + " *******"); // Create a directory to store the generated prefabs. if (!Directory.Exists(PrefabsPath)) Directory.CreateDirectory(PrefabsPath); // Delete existing prefabs for current character. string[] existingPrefabs = Directory.GetFiles(PrefabsPath); foreach (string prefab in existingPrefabs) { if (prefab.EndsWith(".prefab") && prefab.Contains("/Prefabs/" + name)) File.Delete(prefab); } GameObject characterClone = Object.Instantiate(characterFBX); // postprocess animations: we need them animating even offscreen foreach (Animation anim in characterClone.GetComponentsInChildren()) anim.cullingType = AnimationCullingType.AlwaysAnimate; //删除克隆对象中的skinnedmesh对象 foreach (SkinnedMeshRenderer smr in characterClone.GetComponentsInChildren()) Object.DestroyImmediate(smr.gameObject); //给克隆对象添加SkinnedMesh组件 characterClone.AddComponent(); //创建克隆对象的Prefab Object characterBasePrefab = GetPrefab(characterClone, name); //3.为每个SkinnedMesh创建Prefab foreach (SkinnedMeshRenderer smr in characterFBX.GetComponentsInChildren(true)) { //SkinnedMesh创建Prefab GameObject rendererClone = (GameObject)PrefabUtility.InstantiatePrefab(smr.gameObject); GameObject rendererParent = rendererClone.transform.parent.gameObject; rendererClone.transform.parent = null; Object.DestroyImmediate(rendererParent); Object rendererPrefab = GetPrefab(rendererClone, name + "_" + smr.gameObject.name); //获取骨骼信息存到xml XmlDocument xml = new XmlDocument(); var root = xml.CreateElement("root"); xml.AppendChild(root); List bonesList = new List(); foreach (Transform t in smr.bones) root.AppendChild(xml.CreateElement(t.name)); xml.Save("Assets/Resources/" + name + "_" + smr.gameObject.name + ".xml"); createdPrefabs = true; } } if (createdPrefabs) Debug.Log("Success"); else EditorUtility.DisplayDialog("Character Generator", "No Prefabs created. Select the characters folder in the Project pane to process all characters. Select subfolders to process specific characters.", "Ok"); } static Object GetPrefab(GameObject go, string name) { Object tempPrefab = PrefabUtility.CreateEmptyPrefab("Assets/Resources/Prefabs/" + name + ".prefab"); tempPrefab = PrefabUtility.ReplacePrefab(go, tempPrefab); Object.DestroyImmediate(go); return tempPrefab; } public static string PrefabsPath { get { return "Assets" + Path.DirectorySeparatorChar + "Resources" + Path.DirectorySeparatorChar + "Prefabs" + Path.DirectorySeparatorChar; } } }using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Xml; using System.IO; using UnityEngine.UI; //合并skinnedMesh步骤 //1.从Prefab创一个无子mesh模型 //2.创建 CombineInstances集合(融合实例) | Materials集合(材质) | 创建一个Bone_Transforms结合(骨骼矩阵)用于融合准备 //3.从Prefab创建各个SkinnedMesh模型 //4.给对应的SkinnedMesh赋予Material,并将Material加入Materials集合 //5.根据SkinnedMesh创建CombineInstance,并将CombineInstance加入CombineInstances集合 //6.从无子mesh的模型获取整体Transform,再根据各个SkinnedMesh和骨骼信息,将对应的Transform加入Bone_Transforms集合 //7.在无子mesh下调用CombineMeshes接口,将三个集合信息设置好开始合并。 public class Main_SkinMesh : MonoBehaviour { public Button Btn_Change; GameObject Root; string []change_string = new string[6]; // Use this for initialization void Start () { Generate(); Btn_Change.onClick.AddListener(OnClick_Change); } // Update is called once per frame void Update () { } //切换模型组件并创建. public void OnClick_Change() { change_ 4000 string[0] = change_string[0] == "female_eyes" ? "female_eyes" : "female_eyes"; change_string[1] = change_string[1] == "female_face-1" ? "female_face-2" : "female_face-1"; change_string[2] = change_string[2] == "female_hair-1" ? "female_hair-2" : "female_hair-1"; change_string[3] = change_string[3] == "female_pants-1" ? "female_pants-2" : "female_pants-1"; change_string[4] = change_string[4] == "female_shoes-1" ? "female_shoes-2" : "female_shoes-1"; change_string[5] = change_string[5] == "female_top-1" ? "female_top-2" : "female_top-1"; List constant = new List(); constant.AddRange(change_string); Generate(Root, constant); } public void Generate() { //合并skinnedMesh步骤1 Root = Resources.Load("Prefabs/female"); Root = Instantiate(Root) as GameObject; OnClick_Change(); } public GameObject Generate(GameObject root, List constant) { float startTime = Time.realtimeSinceStartup; // The SkinnedMeshRenderers that will make up a character will be // combined into one SkinnedMeshRenderers using multiple materials. // This will speed up rendering the resulting character. //合并skinnedMesh步骤2 List combineInstances = new List(); List materials = new List(); List bones = new List(); Transform[] transforms = root.GetComponentsInChildren(); foreach (var res in constant) { //合并skinnedMesh步骤3 GameObject element = Resources.Load("Prefabs/" + res); element = Instantiate(element) as GameObject; SkinnedMeshRenderer smr = element.GetComponent() as SkinnedMeshRenderer; //合并skinnedMesh步骤4 string mat_res = "Per Texture Materials/"; string[] existingMaterials = Directory.GetFiles("Assets/Resources/Per Texture Materials/"); foreach (string matfile in existingMaterials) { if (matfile.EndsWith(".mat") && matfile.Contains(res)) { mat_res += matfile.Substring(matfile.LastIndexOf('/') + 1); break; } } mat_res = mat_res.Substring(0, mat_res.LastIndexOf('.')); smr.material = Resources.Load(mat_res); materials.AddRange(smr.materials); //合并skinnedMesh步骤5 for (int sub = 0; sub < smr.sharedMesh.subMeshCount; sub++) { CombineInstance ci = new CombineInstance(); ci.mesh = smr.sharedMesh; ci.subMeshIndex = sub; combineInstances.Add(ci); } //合并skinnedMesh步骤6 XmlDocument xml = new XmlDocument(); xml.Load("Assets/Resources/" + res + ".xml"); var Root = xml.FirstChild; var bonelist = Root.ChildNodes; foreach (XmlNode bone in bonelist) { foreach (Transform transform in transforms) { if (transform.name == bone.Name) { bones.Add(transform); break; } } } Object.Destroy(smr.gameObject); } // Obtain and configure the SkinnedMeshRenderer attached to // the character base. //合并skinnedMesh步骤7 SkinnedMeshRenderer r = root.GetComponent(); r.sharedMesh = new Mesh(); r.sharedMesh.CombineMeshes(combineInstances.ToArray(), false, false); r.bones = bones.ToArray(); r.materials = materials.ToArray(); Debug.Log("Generating character took: " + (Time.realtimeSinceStartup - startTime) * 1000 + " ms"); return root; } }
相关文章推荐
- unity换装,SkinnedMeshRender
- Unity 3D Avatar换装系统 SkinnedMeshRenderer皮肤渲染
- 在Unity 5中优化SkinnedMeshRenderer
- unity, SkinnedMeshRenderer.updateWhenOffscreen
- 【Unity 优化】Skinned-Mesh 能动态合并嘛?
- unity, SkinnedMeshRenderer.bones[i]不能直接赋值
- 关于Unity中Skinned Mesh Renderer中Quality中的坑
- unity 合并skinnedMeshRenderer中遇到的一个大坑
- 关于Unity中Mesh网格的详解
- unity, editable mesh
- Unity 3D换装系统教程/Demo
- Unity 5.x BuildAssetBundles 角色换装 基础使用
- [Unity实战]详解换装系统(四)
- skinned mesh render
- unity中利用mesh动态创建墙体
- Unity开发优化----删除多余的MeshCollider和Animation组件
- 关于Unity 获得和使用GetComponent<MeshFilter>().mesh时的心得
- 【Unity3d基础】Unity换装系统(1)
- Unity里的Mesh属性
- Unity Mesh(五) Mesh 立方体Cube贴图以及六个面分别贴不同的图片