Unity场景导出OBJ全攻略:模型与地形的跨软件交付实践

📅 发布时间:2026/9/8 17:46:03
Unity场景导出OBJ全攻略:模型与地形的跨软件交付实践
简介这是一款面向Unity开发者的场景导出工具用于将当前场景中的GameObject与Terrain地形以及外部.fbx模型统一导出为通用的.obj文件适用于需要将Unity场景资源迁移到其他DCC工具或做二次开发的场景。资源共10个文件大小约540KB以jpg截图、md文档、cs脚本和json配置为主其中cs脚本为核心导出逻辑md文档提供使用说明与更新日志json为包配置信息。已有1617人学习下载。通过下载源码或unitypackage即可导入项目也支持在2018.3及以上版本通过Package Manager的Git方式安装。功能上支持自定义裁剪区域、自动裁剪、非正式选择导出等能够灵活控制导出范围同时覆盖.fbx模型的导出便于美术或程序在管线中快速转换资源。压缩包内附带多张效果截图、README与CHANGELOG可帮助使用者快速上手并了解版本演进。 干Unity开发这些年我隔三差五就会撞上一个看起来特别基础、实际上官方一直没做利索的需求把当前场景里的一堆模型连同地形整体导出一个通用格式的文件。客户那边用Blender看模型、用Rhino复核尺寸、用GIS平台做叠加分析都不认Unity场景文件。最后我在编辑器里接入了ExportSceneToObj这类场景导出工具把Unity场景里的对象和terrain、以及外部导入的FBX资产统一导出成.obj文件才算把这条数据链路彻底打通。这篇东西就把这套工具的选型逻辑、实际操作流程和踩过的坑一次说清楚。1. 为什么场景导出不能靠Unity自带功能硬扛1.1 官方导出能力的两条腿都有点短很多人的第一反应是Unity不是有FBX Exporter吗确实Unity官方维护的com.unity.formats.fbx包能导出FBX但它解决的是把预制体或单个模型变成FBX的问题而且FBX导出在场景级批量处理上并不顺手它更偏向资产导出而非整场景导出。至于OBJ官方导出链路里压根没有这个选项最多只能自己写脚本遍历MeshFilter手动拼。另一个容易被忽略的点是FBX这种二进制/ASCII混合格式带节点层级、动画、约束、自定义属性信息量大没错但很多下游工具尤其是老牌CAD、GIS、数值仿真软件对FBX的版本和嵌入数据非常挑剔版本一不对就拒绝打开。而OBJ是从上世纪90年代用到现在的最朴素网格格式几乎所有三维软件都会处理它连很多文本编辑器都能直接打开看内容。做跨软件交付时越笨的格式反而越不容易出问题。1.2 OBJ的笨反而成了它被选中的理由OBJ格式说穿了就是几行顶点、法线、UV和面索引。它没有场景树没有骨骼权重没有动画轨道材质信息全部放在同名的.mtl文件里。这种极简结构带来的好处是解析极简单、文件体积可控、坐标信息一目了然。我做数字孪生项目时经常需要把Unity里的建筑白模交给规划院做分析对方明确要求只要OBJ。原因很实在他们的软件读FBX老是崩读OBJ反而稳定而且OBJ可以直接用文本程序批量改单位、改坐标系、替换材质路径。所以ExportSceneToObj的核心定位不是全能交换格式而是几何与纹理的干净中间人——如果你在乎的是形状、位置、UV和基础贴图OBJ足够如果你在乎动画和PBR材质参数那你一开始就不该选OBJ该用FBX或glTF。1.3 谁真正需要场景级OBJ导出回顾我自己的使用场景这类工具主要集中在四个方向把Unity场景里的建筑、道路、设备模型导出给Blender/Maya/C4D做二次加工或动画数字孪生项目中把Unity场景导出到GIS平台或CAD系统做坐标叠加游戏研发里的关卡白盒评审策划想放在Blender里快速画批注OBJ比截图直观得多3D打印、渲染农场这类只需要壳的下游流程OBJ提交最稳妥。顺带提醒一个容易踩的认知误区Unity本身并不能原生导入.obj文件所以导出OBJ是为了再导回Unity这个说法在原生能力下不成立。如果确实要把OBJ重新弄回Unity要么走Blender中转成FBX要么借助资源商店里的OBJ导入插件。ExportSceneToObj的产出绝大多数时候是给Unity之外的软件消费的。2. ExportSceneToObj在编辑器里到底做了什么2.1 场景遍历哪些GameObject会被装进OBJ这套工具挂在Unity编辑器菜单下执行时第一步是沿场景根节点往下遍历。默认情况下它会收集挂有MeshFilter MeshRenderer的节点、SkinnedMeshRenderer节点、以及带Terrain组件的对象。有几点需要提前了解隐藏或被禁用的对象默认不导出避免把编辑器里临时隐藏的辅助物体带出去SkinnedMeshRenderer会自动做一次骨骼蒙皮烘焙输出的是当前姿态下的顶点位置而不是骨骼层级所以导出的模型是静止姿势LODGroup只取最高精度的LOD0这正是大多数手工导出期望的行为自带碰撞体但没有任何渲染组件的对象比如纯Collider的触发器区域通常会被忽略因为OBJ里没有碰撞体概念。我刚开始用的时候以为它会把所有东西一股脑导出来后来发现它很聪明地绕开了空节点和仅逻辑节点。但这也意味着如果你的场景里有大量用ProBuilder建的临时白模或者用SpriteRenderer铺的广告牌这些默认不会被导出除非你提前把它们转成带MeshFilter的网格。2.2 坐标变换左手系与右手系之间那点事Unity采用左手坐标系OBJ约定是右手坐标系。虽然很多工具不在乎这点但如果你把Unity导出OBJ直接丢进Maya或Rhino会明显看到X轴方向反转模型看起来像照过镜子。ExportSceneToObj这类工具内部通常会提供一个坐标转换开关。选Unity坐标原样输出时模型位置和Unity场景里完全一致方便在同样坐标系的工具里对齐选右手系转换时会做Z轴取反或X轴取反处理得到的是符合OBJ惯例、在多数DCC软件里显示正常的模型。我的建议是如果你只是给Blender/3ds Max这类现代DCC看原始坐标即可它们都能正确识别如果给老牌CAD、GIS平台务必打开右手系转换否则后续对坐标会出大麻烦。实际做项目时这个坑我在甲方那里遇到不止一次。2.3 材质输出OBJ不是纹理容器但MTL可以搭桥OBJ本身不内置纹理但配套的.mtl文件支持map_Kd指令来引用漫反射贴图。工具遍历每个Renderer时会读材质的_MainTex属性URP里通常是_BaseMap和颜色值写进MTL文件。这里有个先天限制PBR材质里的金属度、粗糙度、法线贴图在标准MTL规范里没有完整对应字段工具顶多把主贴图导出来其余全部丢弃。如果你的对接方要求保留完整材质效果OBJ这条路走不通得走glTF。但反过来对于白模评审、尺寸复核、GIS叠加这类需求漫反射贴图已经够用文件还小了一大截。另一个实操细节是贴图路径。工具默认会在OBJ同目录生成MTL并在MTL里使用相对路径指向纹理这样整个文件夹拷给谁都完整。但有些旧版本工具写的是绝对路径换个电脑就丢贴图。拿到导出结果后我习惯用文本编辑器搜一下map_Kd后面的路径确认是相对路径再往外发。2.4 合并导出与分组命名规则OBJ里用o标记对象名用g标记组名。ExportSceneToObj在输出时默认每个MeshFilter生成一个o节点名称直接沿用GameObject的层级路径比如o Building_3F_Wall这样下游工具里能一眼找到对应物体。同时它通常会提供合并所有网格选项。合并的好处是顶点有唯一索引、文件更小、部分不支持多物体的软件能直接打开坏处是丢了对象区分后期不方便按部件调整。这个选项适合确定我只要一个整体模型的时候比如3D打印前的STL预处理。3. 实操从选中对象到落盘OBJ的完整导出流程3.1 安装与菜单入口把工具包导入Unity工程后重启编辑器在顶部菜单栏会多出ExportSceneToObj相关入口常见位置是Window ExportSceneToObj也有些版本放在Assets Export下。不同分支的命名可能略有差别但逻辑一致点开后是一个带参数面板的导出窗口。如果你只是想导出某个子树最简单的方式是先选中目标根节点再打开导出面板工具会默认把选中节点当作导出范围如果不选中任何节点导出范围就是整个活动场景。这个交互符合我习惯因为大场景里经常只想把某个地块、某栋楼单独交出去。3.2 关键参数逐个过一遍不同版本参数名会不一样但核心选项就那么几项按我常用的配置说明参数作用我的推荐导出路径OBJ文件输出目录工程外单独文件夹避免混入Assets单位系数顶点坐标整体缩放倍数Unity单位与米1:1时填1要厘米单位填100坐标转换左手系/右手系切换对接CAD/GIS开转换只给Blender可关合并网格全场景合成一个Mesh不需要区分物体时开保留层级名是否用物体路径命名o节点建议开方便下游关联导出隐藏物体是否包含Inactive节点默认关特殊需求再开地形分辨率Terrain采样网格大小1025或513别盲目拉高单位系数是我最常改的选项。之前有个项目统一用毫米单位建模Unity里数值本身也是毫米含义但甲方CAD平台要求厘米我在导出时填0.1所有顶点坐标直接缩放比下游工具里再统一缩放省事得多。3.3 导出的OBJ文件长什么样以我最近导出的一个设备间小场景为例OBJ开头长这样mtllib ExportSceneToObj.mtl o Device_Router v -0.5000 0.2000 1.3000 v -0.5000 0.2000 1.7000 v 0.5000 0.2000 1.7000 v 0.5000 0.2000 1.3000 vt 0.0000 0.0000 vt 1.0000 0.0000 vt 1.0000 1.0000 vt 0.0000 1.0000 vn 0.0000 1.0000 0.0000 f 1/1/1 2/2/1 3/3/1 f 1/1/1 3/3/1 4/4/1MTL文件里的关键行是newmtl Device_Router_mat Kd 0.8000 0.8000 0.8000 map_Kd textures/Device_Router_Albedo.png导出完成后我基本不看Unity界面里的日志直接拖到Blender里看一眼材质、量一下尺寸确认无误再发给对方。这是最快也是最稳的验证方式。4. Terrain导出是另一套逻辑高度图如何变成一张网格4.1 TerrainData的解析方式Unity地形组件在场景里看起来是一整块可刷的地面但它的底层不是普通Mesh而是一张高度图Heightmap加若干细节层。ExportSceneToObj处理Terrain时会读取TerrainData里的高度数据按固定间距采样把每个采样点变成一个顶点再连接成三角形网格。具体做法是调用TerrainData.GetHeights得到一张二维浮点数组每个值代表对应格点的高度工具把它当作顶点的Y坐标X和Z则根据地形的尺寸和采样分辨率等距生成。简单理解就是高度图变成了地形网格的骨架采样越密地形细节越接近Unity里看到的样子同时三角面数也成倍上升。4.2 采样分辨率怎么选才不会爆内存Unity地块最大支持4097x4097的高度图分辨率。如果工具不限制、直接全量导出那就是约1680万个顶点、3300多万个三角形导出的OBJ文本文件动辄几个GB编辑器大概率直接卡死。实际使用中我把分辨率控制在1025x1025以内也就是约105万个顶点、200万三角形对大多数项目的地形起伏表现已经足够做远景地块时降到513x513文件小很多下游软件操作也更流畅。有一点要明白地形采样的分辨率不等于地形高度图原始精度。高度图是连续插值的你按513采样得到的是513个取样点的近似曲面远看完全够近看才有轻微棱角。采样过程中还要注意内存峰值。GetHeights接口一次性返回整个二维数组如果你的地形是4097分辨率光这个数组就占约6700万个float的内存约268MB加上后续生成的顶点数组编辑器内存会顶到很高。遇到这种情况我会建议把地形拆成多个小块分别导出或者先用工具自带的地形降采样功能。4.3 树和细节为什么导不出去不少第一次用的人会问为什么树、草、石头没导出来原因很简单TerrainData里的树和细节是独立的实例化系统不在高度图数据里。高度图只描述地表起伏树木是库里另外记录坐标和Prefab引用的。如果你确实需要这些植被随地形一起进入OBJ有两条路。一条是把Terrain转成Mesh后再手动把树和草的模型按原始坐标批量合并进同一个OBJ这种做法适合树木数量少的情况另一条是干脆分开交付地形一个OBJ、植被另列清单下游在引擎或DCC里按坐标重新放置。我做数字孪生时绝大多数情况选后者因为几十万棵草灌进OBJ文件体积和面数都失控完全得不偿失。5. FBX进Unity再导出OBJ的转换路径5.1 为什么有人绕这一大圈初始收到FBX最终却要OBJ最直接的办法是用Maya或FBX SDK工具直接转。但现实是很多团队手里只有Unity模型已经导进了Unity场景、调好了位置或者FBX里包含了很多Unity里才能看到的运行时效果。这时候直接在Unity里跑ExportSceneToObj等于把Unity当作一个转换器和场景整理器先把FBX资产在场景里摆好再一次性导出OBJ。这条路径的典型用途把外部建模师发来的FBX建筑模型加上Unity里的地块和周边设施导出一个完整区域OBJ交给GIS平台。FBX在这里是源资产OBJ是交付物Unity反而是中间那个整理台。5.2 变换与负缩放对导出结果的影响FBX导入Unity时Unity会自动处理Z轴转向、单位换算和枢轴点偏移。这意味着你在Unity场景里看到的局部坐标跟FBX原始文件里的坐标已经不一样了。导出OBJ时如果按世界坐标烘焙结果通常没问题但如果你选择按局部坐标导出就会发现模型位置、旋转甚至缩放都和预期不符。更隐蔽的是负缩放问题。Maya里做镜像的时候经常会留下-1的缩放值Unity导入后虽然显示正常但部分顶点法线会因此翻转。工具导出时计算normal如果直接用Unity烘焙后的法线数据问题不大但如果它用三角形叉积重算法线这些翻转的面就会在OBJ里暴露出来出现一整片黑面。遇到这种情况我建议在DCC里先清除历史、烘焙变换重新导出FBX再进Unity。5.3 导入时就要做对的三个设置如果你明确知道这个FBX将来要经过Unity导出OBJ导入设置里就要提前做三件事打开Read/Write Enabled否则网格数据无法被脚本读取导出时直接报Mesh is not readable把Scale Factor跟Unity单位对齐避免导出的OBJ在所有软件里都被放大100倍关掉Optimize Game Objects如果只是纯导出开着问题不大但你要用脚本读取层级结构时它会造成困扰。顺便说FBX里的动画、骨骼、BlendShape在OBJ阶段会被全部丢弃。如果你要交付的模型还需要动画别走OBJ老老实实给FBX原文件。6. 我踩过的坑和对应的排查方法6.1 Mesh is not readable最常见也最好修第一次批量导出时跑到一半报错提示某个Mesh不可读。原因是Unity为了节省内存默认不给导入模型开读写权限脚本只能拿到渲染用的GPU侧数据无法访问CPU侧顶点数组。修复方式在Project窗口选中对应FBX或模型资产打开Inspector里的Model选项卡勾选Read/Write Enabled点Apply。导出工具自身解决不了这个权限问题因为这是Unity资源层的限制。为了避免每次都被打断我现在凡是准备用于导出的资产导入时就顺手把Read/Write打开。6.2 导出后模型全部堆在原点有一次导出场景打开OBJ发现所有物体全部挤在原点位置信息全丢了。排查下来是导出设置里误开了类似仅烘焙网格数据、忽略Transform的选项顶点只用了Mesh本身的本地坐标没有叠加GameObject的world matrix。对比起来正确处理是每个o节点下方的v坐标都要通过transform.localToWorldMatrix把本地顶点变换到世界空间。如果你遇到所有物体堆在原点先检查是不是某个烘焙变换开关没打开再看脚本有没有乘以localToWorldMatrix。这个坑最容易被忽略因为编辑器里看着没报错。6.3 地形洞、UV拉伸和法线翻转Unity新版地形支持Holes功能可以刷出洞。但OBJ导出的网格本质是规则采样网格洞的位置如果没有特殊处理导出来还是一个完整平面只是高度按原始高度图插值洞就变成了一块凹陷或者直接被封死。目前这些工具对Holes的支持普遍不完善我的处理办法是在导出前把洞区域用其他工具预先修平或者接受这个细节损失。另一个常见问题是UV拉伸。地形网格的UV通常是把世界坐标的XZ映射到0-1范围如果工具采样时对UV的原点偏移或缩放算错贴图会呈条状拉伸。检查办法很简单把OBJ拖进Blender开材质预览地面贴图花成一团就说明UV出问题了。6.4 大批量导出的内存与崩溃问题几千个物体的场景如果工具默认全部合并成一个Mesh再写入文件编辑器内存很容易在合并阶段暴涨。我的做法是先做场景裁剪只选中交付范围对应的根节点其次是分批导出比如按地块分批输出多个OBJ文件下游软件再按坐标摆放。这里再推荐一个习惯导出前先File Save保存场景再清理掉场景里用来辅助显示的Debug对象和Gizmo。曾经有一次我把调试用的几千个Debug.DrawLine对应的临时小球全留在场景里导出文件5秒内涨到800MB教训相当深刻。整体用下来ExportSceneToObj这套流程现在已经是我Unity工作流里的固定一环模型摆进场景地形刷好FBX资产检查过导入设置一次导出Blender里复核交付。你如果也要频繁跟外部软件交换模型数据建议把这套链路固定下来能省掉非常多的沟通成本。本文还有配套的精品资源点击获取