Unity导出模型为Obj文件

article/2025/10/25 3:51:17

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

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

参考链接

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

http://chatgpt.dhexx.cn/article/vm23uQt9.shtml

相关文章

SolidWorks2021导出带材质的OBJ文件

SolidWorks2021导出带材质的OBJ文件 注意SW中所有零件都要使用英文命名&#xff0c;装配体模式下再次新建宏按钮即可 1. 首先下载并安装工具宏 1.1 下载免费工具宏 到Github下载免费的Free-Solidworks-OBJ-Exporter&#xff0c;并解压到自己想要的保存的位置。 1.2 在Soli…

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

来源&#xff1a;《Computer Graphics Programming in OpenGL Using C 》by V Scott Gordon John L Clevenger内容&#xff1a;程序6.3 Simple (Limited) OBJ Loader 简单的obj文件读取器&#xff0c;书P152页&#xff0c;PDF171/403 结果 生成&#xff1a; 读取&#xff1a;…

unity动态加载obj文件

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

obj文件(3): 如何用matlab 打开obj文件

obj文件:如何用 matlab 打开 obj 文件 第一步&#xff1a;检查obj文本格式第二步&#xff1a;用 Blender 软件重新导出obj文件第三步&#xff1a;用excel 打开这个obj 文件第四步&#xff1a;复制excel中的数据&#xff0c;传给matlab第五步&#xff1a; 用matlab 打开3D模型 第…

三维模型obj文件解析

目录 obj文件简介文件结构顶点数据(Vertex data)&#xff1a;自由形态曲线(Free-form curve)/表面属性(surface attributes):元素(Elements):自由形态曲线(Free-form curve)/表面主体陈述(surface body statements):自由形态表面之间的连接(Connectivity between free-form sur…

linux类动态库,Linux动态库(一)

起因 博主在以Linux下做开发。在软件需求中&#xff0c;需要动态库带来的灵活性。 比如说博主主导的智能主机的开发。它需要支持很多种类的设备控制&#xff0c;如普通的开关灯、RGB灯、窗帘、百叶窗等等。我们将这些设备抽象成Device类&#xff0c;具体的设备就从这个类上派生…

OpenFlow Switch

The picture of OpenFlow Switch openflow 架构分为2层&#xff0c;一个是控制器层&#xff0c;一个是switch 层。中间是由openflow protocal进行连接的&#xff0c;负责传输指令与数据。switch分为3大块&#xff0c;第一是openflow channe&#xff0c;他是负责向控制器传输数据…

【博客450】OpenFlow学习

OpenFlow OpenFlow协议规范定义了OpenFlow交换机、流表、OpenFlow通道以及OpenFlow交换协议。 OpenFlow是第一个开放的南向接口协议&#xff0c;也是目前最流行的南向协议。它提出了控制与转发分离的架构&#xff0c;规定了SDN转发设备的基本组件和功能要求&#xff0c;以及与控…

OpenFlow交换机【ACM SIGCOMM顶会论文笔记】

目录 写在前面的话OpenFlow交换机基本思想与工作原理专用OpenFlow交换机&#xff08;Dedicated OpenFlow switches&#xff09; 启用OpenFlow的交换机&#xff08;OpenFlow-enabled switches&#xff09;其他功能&#xff08;Additional features&#xff09;控制器&#xff08…

关于ns-3中安装openflow的问题,解决openflow not found

官网 官网里面并没有明确的描述&#xff0c;这里结合自己的安装过程讲解一下 首先下载源码&#xff0c;记住这一步最好在ns-3目录下&#xff0c;就是运行waf命名的目录 $ hg clone http://code.nsnam.org/jpelkey3/openflow $ cd openflow进行编译&#xff0c;会提示缺少文件…

OpenFlow基础入门知识

本文进行讨论的是OpenFlow 1.0和OpenFlow 1.3的基本知识 Overview&#xff1a; Openflow 1.0&#xff1a; 安全通道单张流表ipv4 Openflow 1.3&#xff1a; 安全通道多级流表&#xff08;流水线pipeline&#xff09;组表测量表ipv6..... 流&#xff08;flow&#xff09; …

Openflow流表学习

Openflow流表学习 OpenFlow是一种新型的网络协议&#xff0c;它是控制器和交换机之间的标准协议。自2009年底发布1.0版本后&#xff0c;OpenFlow协议又经历了1.1、1.2、1.3及1.4版本的演进过程&#xff0c;目前使用和支持最多的是1.0和1.3版本。 OpenFlow1.3在1.0版的基础上进…

SDN与OPENFLOW 简介

本文对Openflow的发展、规范、应用和SDN的提出及相关应用做出较为客观全面的介绍。笔者希望通过本文对OpenFlow/SDN做一个初步介绍&#xff0c;以期帮助大家能够进一步深入了解和学习OpenFlow/SDN。 序言&#xff1a;从网络虚拟化说起 云计算的发展&#xff0c;是以虚拟化技术…

OpenFlow协议分析

实验环境&#xff1a;CentOS OpenDayLight-Carbon mininet WireShark 本实验通过wireshark抓包分析openflow1.3协议的各种报文与字段。 抓包 首先安装好实验所需的软件&#xff0c;这里不多赘述&#xff0c;需要的可以点击查看&#xff1a;mininet多方法安装&#xff0c;控制…

openflow简介

openflow交换机包含一些流表&#xff0c;流表负责具体包查找和转发 控制器通过of协议对流表查询和管理 一、流表 流表组成&#xff1a; 包头域、活动计数器、0个或多个执行行动 包头域&#xff1a; 计数器&#xff1a; 可以针对每张表、每个流、每个端口、每个队列来维护。…

SDN-OpenFlow1.0协议分析

目录 OpenFlow1.0代码 OpenFlow交换机流表 包头域 计数器 行动 流表匹配 OpenFlow消息 OpenFlow消息格式 对称消息 建立OpenFlow连接&#xff08;OFPT_HELLO消息&#xff09; 报告错误&#xff08;OFPT_ERROR消息&#xff09; 获取交换机特性信息&#xff08;Featu…

OpenFlow概述

OpenFlow简介 通俗的讲&#xff0c;OpenFlow是使用类似于API进程配置网络交换机的协议。OpenFlow的思路很简单&#xff0c;网络设备维护一个FlowTable并且只按照FlowTable进行转发&#xff0c;FlowTable本身的生成、维护、下发完全由外置的Controller来实现&#xff0c;注意这里…

OpenFlow了解

openflow的核心思想是将所有的协议都抽象出来&#xff0c;抽象成公共的flow概念。协议抽象&#xff1a;数据&#xff0c;函数&#xff08;对数据的处理方式&#xff09;&#xff0c;逻辑&#xff08;数据与处理的对应关系&#xff0c;函数之间的交互行为与时序&#xff09; pu…

OpenFlow交换机概述

1 交换机组成 OpenFlow交换机包括一个或多个流表和一个组表&#xff0c;执行分组查找和转发&#xff0c;和到一个外部控制器OpenFlow的信道。 控制器使用OpenFlow的协议&#xff0c;可添加、更新和删除流表中表项&#xff0c;既主动或被动响应数据包。 每个流表项包含匹配字段&…

openflow阅读感悟

一、背景 随着网络的快速发展和普及&#xff0c;设备和协议的复杂性导致了网络实验的困难。当时&#xff0c;几乎没有实际方法可以在足够现实的环境中尝试新的网络协议&#xff0c;来自网络学术、产业界的大多数新想法都未经试用和测试。因此&#xff0c;人们普遍认为网络基础设…