Unity 换装系统研究

最近几天研究了一下换装系统的实现 主要实现了mesh的合并,贴图的合并处理 ,meshUV信息的重新计算等

先上效果图

模型要经过预处理功能将模型的Mesh与Texture贴图从模型中分离处理,以便可以方便的进行合并

实现了一个预处理的工具类可以将资源导出与优化模型

工具用于实现模型优化将模型的那些特效挂节点暴露出来 最后制作成预制体

主要的逻辑代码如下

void ChangeRole(string[] Parts)
	{
		list.Clear();
		oldUV = new List<Vector2[]>();
		Renderer = transform.GetComponent<SkinnedMeshRenderer>();
		for (int i = 0; i < Parts.Length; i++)
		{
            //加载Mesh
			Mesh mesh = Resources.Load<Mesh>("Equipments/" + Parts[i]);
			Meshes[i] = mesh;
            //加载贴图
			Texture2D texture2D = Resources.Load<Texture2D>("Equipments/" + Parts[i]);
			list.Add(texture2D);
			CombineInstance instance = new CombineInstance();
			instance.mesh = mesh;
			CombineInstances[i] = instance;
		}
		if (Renderer.sharedMesh != null)
		{
			Renderer.sharedMesh.Clear();
		}
        //合并贴图文件减少DrawCall
		var newtexture2D = new Texture2D(1024, 1024, TextureFormat.RGBA32, true);
		Rect[] uvs = newtexture2D.PackTextures(list.ToArray(), 0);
		Vector2[] uva, uvb;
		//根据新合并的贴图文件修改Mesh的UV坐标 使之确保采样正确性
		for (int i = 0; i < CombineInstances.Length; i++)
		{
			uva = CombineInstances[i].mesh.uv;
			//   0.0   0.9      (x:0.00, y:0.50, width:0.25, height:0.50)
			uvb = new Vector2[uva.Length];
			for (int j = 0; j < uva.Length; j++)
			{
				uvb[j] =  new Vector2((uva[j].x * uvs[i].width) + uvs[i].x, (uva[j].y * uvs[i].height) + uvs[i].y);
			}
			oldUV.Add(uva);
			CombineInstances[i].mesh.uv = uvb;
		}
		var tempMesh = new Mesh();
		Renderer.enabled = false;
		tempMesh.CombineMeshes(CombineInstances,true,false);
		Renderer.sharedMesh = tempMesh;
		Renderer.enabled = true;
		
		Material material = Renderer.material;
		material.mainTexture = newtexture2D;
		//重置Mesh的UV信息
		for (int i = 0; i < CombineInstances.Length; i++)
		{
			CombineInstances[i].mesh.uv = oldUV[i];
		}
	}

部分编辑器代码 

[MenuItem("FbxTools/保存Mash&Texture2")]
	public static void SaveMesh()
	{
		Object[] fbxs = Selection.GetFiltered<Object>(SelectionMode.DeepAssets);
		if (fbxs != null)
		{
			for (int i = 0; i < fbxs.Length; i++)
			{
				GameObject fbx = fbxs[i] as GameObject;
				string path = "";
				if (fbx != null)
				{
					path = AssetDatabase.GetAssetPath(fbx);
					ModelImporter modelImporter = AssetImporter.GetAtPath(path) as ModelImporter;
					if (modelImporter != null)
					{
						string saveRootPath = "Assets/Resources/Equipments/";
						if (!Directory.Exists(saveRootPath))
						{
							Directory.CreateDirectory(saveRootPath);
						}
						modelImporter.isReadable = true;
						GameObject go = Object.Instantiate(fbx);
						SkinnedMeshRenderer[] smrs = go.GetComponentsInChildren<SkinnedMeshRenderer>();
						for (int j = 0; j < smrs.Length; j++)
						{
							//创建Mesh
							Mesh mesh = Object.Instantiate(smrs[j].sharedMesh);
							mesh.name = smrs[j].sharedMesh.name;
							SaveMeshAsset(mesh,smrs[j].sharedMaterial.mainTexture as Texture2D,saveRootPath );
						}
						modelImporter.isReadable = false;
						Object.DestroyImmediate(go);
					}
				}
			}
		}
	}
	
	public static void CleanMesh(Mesh mesh)
	{
		mesh.uv2 = null;
		mesh.uv3 = null;
		mesh.uv4 = null;
		mesh.colors = null;
		mesh.colors32 = null;
		mesh.tangents = null;
	}
	
	public static void SaveMeshAsset(Mesh mesh, Texture2D tex, string path)
	{
		CleanMesh(mesh);
		string meshPath = path + mesh.name + ".asset";
		AssetDatabase.CreateAsset(mesh,meshPath);
		if (tex != null)
		{
			string srcPath = AssetDatabase.GetAssetPath(tex);
			string desPath =  "Assets/Resources/Equipments/" + tex.name + ".tga";
			AssetDatabase.CopyAsset(srcPath, desPath);
		}
		AssetDatabase.SaveAssets();
	}
	[MenuItem("FbxTools/优化Fbx")]
	private static void OptmizeFbx()
	{
		Rect rect = new Rect(0,0,600,800);
		SelectFbxEditor window =
			(SelectFbxEditor) EditorWindow.GetWindowWithRect(typeof(SelectFbxEditor), rect, true, "Fbx面板");
		window.Init();
		window.Show();
	}

如有疑问请评论 或联系本人 邮箱tongwuwei@163.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值