我们在开发中,可能会遇到,需要在unity中拼场景,然后到处模型给美术优化的情况,这种情况下,就需要在Unity中导出模型的操作了

思路

实际这个功能的设计思路也很简单,根据在场景中选择的对象,获取它的mesh数据,然后把数据重新生成文件就好了

实现

1.网格数据类

这个类是用来获取网格各个部分的数据信息的

保存网格名称
        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");}
保存uv数据
        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;}

2.导出文件部分功能

导出多个模型为一个文件
        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");}}}

2.编辑器菜单部分

这个模式会将父物体和子物体的模型分别导出为单独的模型文件
        [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 + " 个模型", "关闭");elseEditorUtility.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.PathSeparatorif (stripIndex >= 0)filename = filename.Substring(stripIndex + 1).Trim();ExportFile.ExportObjsToOne(mf, ExportFile.EXPORT_FOLDER, filename);EditorUtility.DisplayDialog("导出成功", "导出模型名称:" + filename, "关闭");}elseEditorUtility.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 + " 个模型", "关闭");}elseEditorUtility.DisplayDialog("导出失败", "导出模型必须含有Mesh Filter组件", "关闭");}

这个小插件在有需求的时候,还是蛮好用的,希望对大家有帮助,完整代码可以到我的工具集里找到

工具收录于我自己写的工具集,内部还有我写的几个小插件,我会慢慢更新,欢迎关注
工具集地址:https://github.com/BlueMonk1107/BlueToolkit

我会在我的公众号上推送新的博文,也可以帮大家解答问题
微信公众号 Andy and Unity 搜索名称或扫描二维码

希望我们能共同成长,共同进步

Unity场景中导出模型插件相关推荐

  1. Unity场景素材导出为 FBX文件的方法

    系列文章目录 一.Unity场景素材导出为 FBX文件的方法:http://t.csdn.cn/Xyjxe 二.Unity场景素材导出为 OBJ文件的方法:http://t.csdn.cn/08RY3 ...

  2. 从《魔兽争霸3》中导出模型到3DMax

    很多程序员写程序苦于没有素材,看到暴雪的模型都希望能导出来自己用.但是网上的教程基本上都很繁琐.我这里介绍一种软件较少的办法可以将<魔兽争霸3>中的模型导出到3DMax中,然后可以保存成其 ...

  3. Unity场景中的双相机设置,3D相机和2D相机设置

    unity场景中需要双相机,其中3D相机专摄场景物体3D显示,2D相机则专用于显示屏幕的UI元素. 3D设置: 2D设置:(别忘了给Canvas拖一下相机路径) 注意相机的Clipping Plane ...

  4. unity从场景中导出单个模型

    困扰我了一万年---- 怎么从网上购买的unity资源包中导出单个我想要的fbx模型. 基础没打好的痛苦 在assest中记得要点击select dependenices 另外 open scene ...

  5. 虚幻引擎中导出模型,并导入到Unity

    1.UE5 安装glTF 插件 在虚幻商城中添加glTF 免费插件 打开虚幻引擎插件面板,启用glTF 插件,并重启引擎 2.导出模型 选择要导出的模型资源,右键选择导出,选择格式为 gltf. 3. ...

  6. 【Unity3D插件】RuntimeTransformGizmos插件分享《Unity运行时控制模型插件》

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 一.前文   Runtime Transform Gizmos看名字顾名思义 ...

  7. 谷歌40人发表59页长文:为何真实场景中ML模型表现不好?

    文 | 白鹡鸰 编 | 夕小瑶 ~前不久,在卖萌屋NLP群里默默潜水的白鹡鸰被群友提到的一篇Google几天前放出的59页超长论文炸得飞了起来. 来,大家来感受一下气势浩大的论文首页 文章名字是Und ...

  8. 推荐场景中召回模型的演化过程

    导读:一般的推荐系统主要包括召回.排序和后续的业务机制 ( 重排序.多样性保证.用户体验保证等等 ) 这三大模块,而其中召回模块主要负责根据用户和 item 的特征,从众多待推荐的候选 item 中初 ...

  9. 在3Dmax中导出模型到Unity里,rotation发生了改变该怎么办

    别的帖子都是在3dmax里改这个那个的,给一个简单粗暴的方法,在unity里创建一个空物体,rotation为(0,0,0),把正方向调好了的模型(实际角度可能各种各样的)直接挂在空物体上,这个空物体 ...

最新文章

  1. Binutils工具集 GCC工具集介绍
  2. 使用gdb调试程序详解
  3. MySQL:给表的某个字段添加唯一性约束
  4. CAN总线的初步认识
  5. sudo: apt-get:找不到命令_Linux重复执行历史命令方法详解
  6. windows传文件到linux服务器--- secureCRT PK xftp
  7. 2019东南大学研究生课程计算机网络安全
  8. 金九银十招聘季,程序员跳槽BAT最新面经
  9. websocket.onmessage回调没反应_Java笔记:反应器模式的简单运用
  10. 2022美国大学生数学建模竞赛C题思路
  11. windows制作黑苹果双系统
  12. Oracle StorageTek磁带库产品线或将终结
  13. 【前端】基于layui写的一个高级搜索(筛选)功能
  14. 真正准确的“两个日期相差多少天”函数
  15. 盘点最近 火火火火 的 GitHub 项目
  16. BO4 SDK 检索所有使用了某个universe object的报表
  17. TP-LINK TL-WDN7200H ubuntu18.04驱动安装
  18. 谁还不是一个宝宝了~
  19. 2017年4月24号课堂笔记
  20. 线程与蓝牙:物联网连接的 VHS 与 Betamax?

热门文章

  1. 【FLink】access closed classloader classloader.check-leaked-classloader
  2. ChatGPT 大规模封号。。。
  3. Codeforces Round #782 A-D题解
  4. 80老翁谈人生(238):什么叫“不作为”?
  5. 酶切位点分析(the analysis of enzyme sites)
  6. Python计算限制性核酸内切酶切割后的核酸片段及其片段分子量
  7. PHP首期基础班郊游记:独乐乐不如众乐乐
  8. 政府机构安装什么SSL证书可以保证网站安全?
  9. Windows快捷键☞【Win+R】常用命令
  10. 微型计算机最早提出于,大学计算机基础知识理论题及解答.doc