Unity导出模型为Obj文件

  • 资源链接
    • 下载导入
  • 代码纪要
  • 使用方式
  • 参考链接

资源链接

原插件代码中只有MeshFilter的Obj导出代码;由于项目需求,需要将SkinnedMeshRenderer导出为Obj文件,故在原代码的基础上,扩展出了SkinnedMeshRenderer的Obj导出功能。对原代码有兴趣的可以自行进入参考链接2
下载链接:修改后MeshFilterSkinnedMeshRenderer的Obj导出功能

下载导入

将下载的插件导入项目之后,就是文件夹Editor下的3个C#脚本文件。如下图,

代码纪要

下面对代码进行简单分析纪要:

  1. 总共3个脚本分别为抽象泛型父类EditorObjExporter<T, R>MeshFilter的子类EditorObjExporter_MeshFilterSkinnedMeshRenderer的子类EditorObjExporter_SkinnedMeshRendererMeshFilterSkinnedMeshRenderer的整个过程代码都一样只有在获取Mesh网格和Material[]材质时有所不同。
  2. 由于是Unity的工具栏程序,所以大部分为static静态函数,尤其是3个触发函数:ExportSelectionToSeparateExportWholeSelectionToSingleExportEachSelectionToSingle
  3. 结合前两条,脚本之所以使用单例设计模式。是因为这个功能唯一的非静态函数string MeshToString(MeshFilter t, Dictionary<string, ObjMaterial> materialList),用于子类分别获取Mesh网格和Material[]材质,所以该函数使用泛型类继承的方式;同时父类的static void MeshToFile(T t, string folder, string filename)static void MeshesToFile(T[] ts, string folder, string filename)两个静态函数都需要调用该方法,但因为MeshToString是非静态函数,使用单例对象调用是最方便简单的。
    该功能,如果还有什么更加好的解决方案,欢迎探讨。示例代码:
sw.Write(GetInstance().MeshToString(t, materialList));//静态类中使用单例对象调用函数
  1. 3个触发函数的基本流程相同:先通过Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);函数获取当前选择的Transform对象数组;再根据泛型的每个子类不同的需求遍历该数组,并获取对应的组件;最后根据获取的组件数组保存成Obj文件。示例代码:
protected static void ExportSelectionToSeparate()
{if (!CreateTargetFolder())return;Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);if (selection.Length == 0){EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");return;}int exportedObjects = 0;for (int i = 0; i < selection.Length; i++){Component[] components = selection[i].GetComponentsInChildren(typeof(T));for (int m = 0; m < components.Length; m++){exportedObjects++;MeshToFile((T)components[m], targetFolder, selection[i].name + "_" + i + "_" + m);}}if (exportedObjects > 0)EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");elseEditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
}
  1. 先通过MeshToString函数将组件中获取的Mesh网格转换成String字符串:先顶点数据循环,再法线数据循环,然后是UV数据循环,最后材质数据循环的同时储存材质对象字典。函数代码:
protected static string MeshToString(Mesh mesh, Material[] materials, string name, Transform transform, Dictionary<string, ObjMaterial> materialList)
{StringBuilder sb = new StringBuilder();sb.Append("g ").Append(name).Append("\n");//数据起始foreach (Vector3 lv in mesh.vertices){//顶点数据循环输入Vector3 wv = transform.TransformPoint(lv);//This is sort of ugly - inverting x-component since we're in//a different coordinate system than "everyone" is "used to".sb.Append(string.Format("v {0} {1} {2}\n", -wv.x, wv.y, wv.z));}sb.Append("\n");//空格foreach (Vector3 lv in mesh.normals){//法线数据循环输入Vector3 wv = transform.TransformDirection(lv);sb.Append(string.Format("vn {0} {1} {2}\n", -wv.x, wv.y, wv.z));}sb.Append("\n");//空格foreach (Vector3 v in mesh.uv){//UV数据循环输入sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));}for (int material = 0; material < mesh.subMeshCount; material++){//材质数据循环输入sb.Append("\n");//空格sb.Append("usemtl ").Append(materials[material].name).Append("\n");sb.Append("usemap ").Append(materials[material].name).Append("\n");try{//See if this material is already in the materiallist.看看这个字典是否已经在字典中ObjMaterial objMaterial = new ObjMaterial{name = materials[material].name};if (materials[material].mainTexture)objMaterial.textureName = AssetDatabase.GetAssetPath(materials[material].mainTexture);//另一种方式EditorUtility.GetAssetPath(mats[material].mainTexture)elseobjMaterial.textureName = null;materialList.Add(objMaterial.name, objMaterial);}catch (ArgumentException){//已经在字典中//Already in the dictionary}int[] triangles = mesh.GetTriangles(material);for (int i = 0; i < triangles.Length; i += 3){//Because we inverted the x-component, we also needed to alter the triangle winding.sb.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;return sb.ToString();
}
  1. MeshToFileMeshesToFile函数是将Mesh网格转换的String字符串保存到文件中,其中的最后一步MaterialsToFile是遍历材质对象字典保存到文件中。
  2. 最后,因为工具栏的出发函数必须为静态函数,故子类都新建了静态函数用于“包装”父类的相应静态函数,并使用MenuItem修饰。示例:
[MenuItem("Custom/Export Obj/MeshFilter/导出所有选择的网格过滤器以分离的Obj形式")]//Export all MeshFilters in selection to separate Objs
protected static void ExportSelectionToSeparate_MF()
{ExportSelectionToSeparate();
}

使用方式

  1. 在场景中选择模型对象。
  2. 在工具栏选择Custom—>Export Obj,再根据所选择的模型对象所使用的Mesh组件选择对应的选项:MeshFilterSkinnedMeshRenderer
  3. 再根据自己的需求选择导出的模式:
  • 所有网格分别输出到一个Obj文件;
  • 输出选择的网格合体到一个Obj文件;
  • 输出每个选择的模型到单一Obj文件。
  1. 之后弹出对话框,即为成功。
  2. 项目文件夹下会出现一个名为ExportedObj的文件夹,其中便是保存下来的Obj文件以及对应的png图片。可以双击查看是否正确。

参考链接

  1. Unity2019导出地形terrain为obj
  2. Unity 导出FBX和OBJ的方法(原代码出处)

Unity导出模型为Obj文件相关推荐

  1. unity动态加载obj文件

    unity2018.4.2f1 vs2017 最近项目需求,需要实现动态读物外部obj模型,并加载到场景中,研究了好几天,终于实现了,在此做个记录. 1.首先随便找个.obj模型,带贴图,我的资源截图 ...

  2. unity动态加载.obj文件相关

    .obj文件加载相关 QA: 要点 .obj文件结构 .mtl文件结构 材质匹配问题 动态加载obj文件 unity资源商城插件:Runtime Obj Importer QA: q: 如何动态加载o ...

  3. unity 导出模型为fbx 格式

    记录一下 原文链接 unity 给大家分享一个可以直接将unity中的物体导出成fbx存在项目中的方法(实测pc可用,移动端不可以~其他待测) 如题,会给大家分享一个超实用的动态库,是关于将unity ...

  4. Unity导出模型透明底图片,用于UI制作

    最近在制作一个钓鱼的游戏需要对钓到的不同种类的鱼进行统计,但是没有找到合适的2D图片素材,找了蛮久下载了一个3D模型素材包,只有模型和材质没有对应的贴图,当场裂开!尝试过使用快捷键截图来截取模型图片但 ...

  5. Unity场景中导出模型插件

    我们在开发中,可能会遇到,需要在unity中拼场景,然后到处模型给美术优化的情况,这种情况下,就需要在Unity中导出模型的操作了 思路 实际这个功能的设计思路也很简单,根据在场景中选择的对象,获取它 ...

  6. Unity 录制模型动画并导出至Maya编辑的方法

    本案例实现功能为在Unity编辑器中逐帧记录模型的动画,并可以将记录的动画片段保存下来,和模型一并导出为FBX,导入到Maya中,进行对模型和动画的调节. 意义:Unity可以结合动作捕捉软件,使复杂 ...

  7. unity下载模型到本地并加载

    目录 1.目的 2.参考 2.1 Unity3D 动态加载本地/网络GLB模型 2.2 unity下载模型到本地并加载 2.3 插件:TriLib2.0 3.注意 4.操作 4.1 3dmax简单的制 ...

  8. C++/OpenGL 入门(18):读取obj文件并贴图

    来源:<Computer Graphics Programming in OpenGL Using C++ >by V Scott Gordon John L Clevenger 内容:程 ...

  9. java3d载入obj_Threejs大型obj文件的秒加载实现

    项目需求:要将3d模型显示在网页上 并实现时时旋转和鼠标悬停功能.给我的3d模型是60M的obj文件 threejs加载obj模型比较简单但加载时间很长 毕竟60m的文件网络传输需要很长时间 obj模 ...

最新文章

  1. javascript中对象在OOP方面的一些知识(主要是prototype和__proto__相关)
  2. python散点图拟合曲线-使用python通过点拟合曲线
  3. Android GIS开发系列-- 入门季(11) Callout气泡的显示
  4. 老赖凭本事骗钱,你有本事不被骗吗?
  5. UNIX再学习 -- 函数 fork 和 vfork
  6. Linux进程 管理,Linux进程查看与管理以及作业控制
  7. RabbitMQ发布/订阅模式(Publish/Subscribe)
  8. Flutter应用进行自动化测试
  9. 207.课程表(力扣leetcode) 博主可答疑该问题
  10. opengl超级宝典(第5版)的环境搭建
  11. Android Toast的几种使用方式
  12. 【《Real-Time Rendering 3rd》 提炼总结】(十) 第十一章 · 非真实感渲染(NPR)相关技术总结
  13. python系统函数详解
  14. 来soul,遇见你的奇妙缘分
  15. linux硬盘损坏无法启动,CentOS 硬盘损坏导致无法启动
  16. 创业要素:如何推广自己的产品
  17. 用速腾RS16跑LeGO-LOAM
  18. 某电商用户行为分析-提升GMV
  19. 1.4 面试问题整理: ATM机取款
  20. SQL实现筛选出连续3天登录用户与窗口函数

热门文章

  1. git----如何撤销上次提交
  2. 【20221220】Windows通过网线共享网络及小猫咪局域网共享
  3. PRML:Pattern Recognition And Machine Learning 相关资料整理与下载
  4. python基本输入输出函数有_python基本输入输出函数与变量类型
  5. Linux基础(三):多重引导
  6. shapenet数据集_三维形状数据的深度特征表示
  7. android 手写签批_Android自定义实现手写签名功能
  8. 软科计算机科学与工程专业,2019上海软科世界一流学科排名计算机科学与工程专业排名德蒙福特大学排名第201-300...
  9. 使用cookiecutter创建pyramid项目
  10. 可以参考的前端网站(提高审美和创新)