赞
踩
我们在开发中,可能会遇到,需要在unity中拼场景,然后到处模型给美术优化的情况,这种情况下,就需要在Unity中导出模型的操作了
实际这个功能的设计思路也很简单,根据在场景中选择的对象,获取它的mesh数据,然后把数据重新生成文件就好了
这个类是用来获取网格各个部分的数据信息的
private void SaveMeshName(MeshFilter meshFilter, StringBuilder data)
{
data.Append("g ").Append(meshFilter.name).Append("\n");
}
private static void SaveVertices(MeshFilter meshFilter, StringBuilder data)
{
foreach (Vector3 ver in meshFilter.sharedMesh.vertices)
{
Vector3 worldPos = meshFilter.transform.TransformPoint(ver);
//因为坐标系的区别,x分量需要反转
data.Append(string.Format("v {0} {1} {2}\n", -worldPos.x, worldPos.y, worldPos.z));
}
data.Append("\n");
}
private void SaveNormals(MeshFilter meshFilter, StringBuilder data)
{
foreach (Vector3 normal in meshFilter.sharedMesh.normals)
{
Vector3 directionWorld = meshFilter.transform.TransformDirection(normal);
data.Append(string.Format("vn {0} {1} {2}\n", -directionWorld.x, directionWorld.y, directionWorld.z));
}
data.Append("\n");
}
private void SaveUVs(MeshFilter meshFilter, StringBuilder data)
{
foreach (Vector3 uv in meshFilter.sharedMesh.uv)
{
data.Append(string.Format("vt {0} {1}\n", uv.x, uv.y));
}
}
private void SaveMaterails(MeshFilter meshFilter, StringBuilder data, Dictionary<string, MaterialData> materialDic) { Mesh mesh = meshFilter.sharedMesh; Material[] materialArray = meshFilter.GetComponent<Renderer>().sharedMaterials; string materialName = ""; for (int materialIndex = 0; materialIndex < mesh.subMeshCount; materialIndex++) { materialName = materialArray[materialIndex].name; data.Append("\n"); data.Append("usemtl ") .Append(materialName) .Append("\n"); data.Append("usemap ") .Append(materialName) .Append("\n"); //筛选同名材质,不重复添加 if (!materialDic.ContainsKey(materialName)) { MaterialData materialData = new MaterialData(); materialData.Name = materialName; materialData.TextureName = materialArray[materialIndex].mainTexture ? AssetDatabase.GetAssetPath(materialArray[materialIndex].mainTexture) : null; materialDic[materialData.Name] = materialData; } //保存三角形数据 int[] triangles = mesh.GetTriangles(materialIndex); for (int i = 0; i < triangles.Length; i += 3) { data.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n", triangles[i] + 1 + _vertexOffset, triangles[i + 1] + 1 + _normalOffset, triangles[i + 2] + 1 + _uvOffset)); } } _vertexOffset += mesh.vertices.Length; _normalOffset += mesh.normals.Length; _uvOffset += mesh.uv.Length; }
public static void ExportObjsToOne(MeshFilter[] mf, string folder, string filename) { MeshData data = new MeshData(); using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".obj")) { sw.Write("mtllib ./" + filename + ".mtl\n"); foreach (MeshFilter mesh in mf) { data.SaveData(mesh); sw.Write(data.ToString()); } } ExportMaterials(data.GetMaterialDic(), folder, filename); }
public static void ExportObjToOne(MeshFilter mf, string folder, string filename)
{
MeshData data = new MeshData();
data.SaveData(mf);
using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".obj"))
{
sw.Write("mtllib ./" + filename + ".mtl\n");
sw.Write(data.ToString());
}
ExportMaterials(data.GetMaterialDic(), folder, filename);
}
private static void ExportMaterials(Dictionary<string, MaterialData> materialList, string folder, string filename) { using (StreamWriter sw = new StreamWriter(folder + "/" + filename + ".mtl")) { foreach (KeyValuePair<string, MaterialData> kvp in materialList) { sw.Write("\n"); sw.Write("newmtl {0}\n", kvp.Key); sw.Write("Ka 0.6 0.6 0.6\n"); sw.Write("Kd 0.6 0.6 0.6\n"); sw.Write("Ks 0.9 0.9 0.9\n"); sw.Write("d 1.0\n"); sw.Write("Ns 0.0\n"); sw.Write("illum 2\n"); if (kvp.Value.TextureName != null) { string destinationFile = kvp.Value.TextureName; int stripIndex = destinationFile.LastIndexOf('/'); if (stripIndex >= 0) destinationFile = destinationFile.Substring(stripIndex + 1).Trim(); string relativeFile = destinationFile; destinationFile = folder + "/" + destinationFile; try { File.Copy(kvp.Value.TextureName, destinationFile); } catch { } sw.Write("map_Kd {0}", relativeFile); } sw.Write("\n\n\n"); } } }
[MenuItem("BlueToolKit/导出模型/将选中模型分别导出(子物体会拆分导出)")] private static void ExportAllChild() { if (!ExportFile.CreateExportFolder()) return; Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab); if (selection.Length == 0) { EditorUtility.DisplayDialog("未选中模型", "请选中一个或多个模型", "关闭"); return; } int exportCount = 0; for (int i = 0; i < selection.Length; i++) { Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter)); for (int m = 0; m < meshfilter.Length; m++) { exportCount++; ExportFile.ExportObjToOne((MeshFilter)meshfilter[m], ExportFile.EXPORT_FOLDER, selection[i].name + "_" + i + "_" + m); } } if (exportCount > 0) EditorUtility.DisplayDialog("导出成功", "成功导出 " + exportCount + " 个模型", "关闭"); else EditorUtility.DisplayDialog("导出失败", "导出模型必须含有Mesh Filter组件", "关闭"); }
[MenuItem("BlueToolKit/导出模型/将选中模型导出成一个obj文件")] private static void ExportToSingleObj() { if (!ExportFile.CreateExportFolder()) return; Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab); if (selection.Length == 0) { EditorUtility.DisplayDialog("未选中模型", "请选中一个或多个模型", "关闭"); return; } int exportCount = 0; ArrayList mfList = new ArrayList(); for (int i = 0; i < selection.Length; i++) { Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter)); for (int m = 0; m < meshfilter.Length; m++) { exportCount++; mfList.Add(meshfilter[m]); } } if (exportCount > 0) { MeshFilter[] mf = new MeshFilter[mfList.Count]; for (int i = 0; i < mfList.Count; i++) { mf[i] = (MeshFilter)mfList[i]; } string filename = SceneManager.GetActiveScene().name + "_" + exportCount; int stripIndex = filename.LastIndexOf('/'); //FIXME: Should be Path.PathSeparator if (stripIndex >= 0) filename = filename.Substring(stripIndex + 1).Trim(); ExportFile.ExportObjsToOne(mf, ExportFile.EXPORT_FOLDER, filename); EditorUtility.DisplayDialog("导出成功", "导出模型名称:" + filename, "关闭"); } else EditorUtility.DisplayDialog("导出失败", "导出模型必须含有Mesh Filter组件", "关闭"); }
[MenuItem("BlueToolKit/导出模型/将选中模型分别导出(子物体不拆分导出)")] private static void ExportParent() { if (!ExportFile.CreateExportFolder()) return; Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab); if (selection.Length == 0) { EditorUtility.DisplayDialog("未选中模型", "请选中一个或多个模型", "关闭"); return; } int exportCount = 0; for (int i = 0; i < selection.Length; i++) { Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter)); MeshFilter[] mf = new MeshFilter[meshfilter.Length]; for (int m = 0; m < meshfilter.Length; m++) { mf[m] = (MeshFilter)meshfilter[m]; } exportCount++; ExportFile.ExportObjsToOne(mf, ExportFile.EXPORT_FOLDER, selection[i].name + "_" + i); } if (exportCount > 0) { EditorUtility.DisplayDialog("导出成功", "成功导出 " + exportCount + " 个模型", "关闭"); } else EditorUtility.DisplayDialog("导出失败", "导出模型必须含有Mesh Filter组件", "关闭"); }
这个小插件在有需求的时候,还是蛮好用的,希望对大家有帮助,完整代码可以到我的工具集里找到
工具收录于我自己写的工具集,内部还有我写的几个小插件,我会慢慢更新,欢迎关注
工具集地址:https://github.com/BlueMonk1107/BlueToolkit
我会在我的公众号上推送新的博文,也可以帮大家解答问题
微信公众号 Andy and Unity 搜索名称或扫描二维码
希望我们能共同成长,共同进步
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。