把生成的 3D 场景导入 Unity:从 GLB 到能走进去的关卡
生成好的 GLB 或 FBX 场景几分钟就能进 Unity。让它真正可玩,靠的是导入设置、碰撞体和光照——这里是完整路径。
一个 60 MB、装着整座小镇的 GLB 落进 Assets 文件夹,Unity 却当作没看见。或者导进来了,建筑只有硬币那么大。或者尺寸对了,但满屏洋红,角色还从人行道上掉了下去。这就是拿到一份生成场景之后标准的头二十分钟,而每一步背后都有一个具体的、有名字的设置。
下面默认你手上已经有一份 GLB 或 FBX 的场景,以及一个大致空白的 Unity 工程。目标是一个能走进去的场景,不是一张截图。
先把文件弄进工程
Unity 的模型导入器开箱读取 FBX、OBJ、DAE 和 DXF。glTF 和 GLB 不在其中:引擎没有内置的导入器,所以把 .glb 拖进一个全新工程,它就只是一个躺着不动的文件。导入器要靠包来补。
这个包叫 Unity glTFast,而它在 Package Manager 的列表里按名字搜不到:Window > Package Manager,点 + 按钮,选 Add package by name,输入 com.unity.cloud.gltfast。较新的版本要求 Unity 2021.3.46f1 或更高,并覆盖 Built-in、Universal 和 High Definition 三条管线。装好之后,.gltf 和 .glb 就和别的模型一样导入——一个预制体,网格、材质和贴图作为子资源挂在下面。
如果工具让你选导出格式,决定因素与其说是格式本身,不如说是导入之后你要做什么。比如 Cuberta 导出的 GLB 或 FBX 都带着贴图,所以这只是一个下拉框,而不是一道额外的转换工序。
| 你需要什么 | 导出 | 原因 |
|---|---|---|
| 烘焙光照贴图 | FBX | Unity 自带的导入器能生成第二套 UV;glTF 导入器在这件事上并不一致 |
| 贴图跟着文件一起过来 | GLB | 贴图在二进制内部,没有需要重新链接的路径 |
| 一次性重映射上百个材质槽 | FBX | Materials 标签页有 Search and Remap |
| 迭代时最短的往返 | GLB | 一个文件出去,一个进来,不用同步贴图文件夹 |
关于两种格式本身的取舍是另一个话题。就这件事而言两者都能用;上面这张表说的是哪一个之后让你少花力气。
尺度,以及九十秒内怎么验它
差一百倍的问题
Unity 的物理把一个世界单位当作一米,所有控制器、重力值和阻力设置都建立在这个约定上。FBX 在文件里自带单位比例,而相当多的导出器往里写的是厘米。Model 标签页的 Convert Units 会读取这个声明的比例并做换算;Scale Factor 则是声明本身就不对时的手动乘数。一座大了一百倍的小镇,几乎总是卡在这两个字段上。同一个标签页里的 Bake Axis Conversion 把上轴的修正直接烘进网格数据,而不是藏在一个被旋转过的根物体里。
glTF 规定以米为单位,所以 GLB 很少出现尺度错误——但它是右手坐标系,Unity 是左手坐标系,导入器靠翻转某一个轴来解决。如果小镇看着都对、读起来却是镜像的:文字反了,本该右转的路变成了左转,你看到的就是这件事。
用角色控制器量,而不是用眼睛
在这份导入结果上动手搭任何东西之前,先往场景里放一个 CharacterController——height 2、radius 0.5、step offset 0.3、slope limit 45——给它十行移动代码,然后走一圈。四件事几乎说明一切:
- 门洞能让 2 米的胶囊体带着头顶余量通过,而不是擦着过去。
- 路缘石在 0.1~0.15 米,step offset 不用起跳就能把你带上去。
- 楼梯踏步高度低于 step offset,否则你哪儿也爬不上去。
- 一条车道 3~3.5 米,横穿大约三步。
如果为了让门合适必须把 Scale Factor 调到 0.35,而调完人行道宽得像跑道,那问题出在比例而不是单位,任何导入设置都修不了。
材质:什么能活着过来,什么要重建
着色器由你当前所在的管线决定
基础色、metallic-roughness、法线、遮蔽和自发光贴图,透明模式、双面标记和顶点色,都会完整过来。过不来的是一切与引擎绑定的东西:Shader Graph、自定义着色器、贴花投射器、地形图层、三平面映射方案。这些要么在 Unity 里重做,要么就没有。
另外,导入器按导入那一刻处于激活状态的渲染管线来挑着色器。先在 Built-in 工程里导入 GLB,再切到 URP,这个文件里的所有材质都会变成洋红。出路有两条,取决于这些着色器是谁的:
- Unity 自带的着色器——FBX 的典型情况,它会落到 Standard 或 URP/Lit 上。打开 Window > Rendering > Render Pipeline Converter,设定源管线与目标管线,运行材质转换器。它不处理自定义着色器,而且改动不可逆,所以先提交一次。
- glTF 导入器自己的着色器——转换器对它们没有映射关系。先把管线配置好,再右键资源重新导入。
手工重建材质时,盯住通道
glTF 把 roughness 放在同一张贴图的绿通道、metallic 放在蓝通道,遮蔽如果共用这张图则在红通道。Unity 的 Standard 着色器要的是红通道里的 metallic 和 alpha 通道里的 smoothness——也就是 1 减 roughness。把 glTF 的 metallic-roughness 贴图丢进 URP/Lit 的 Metallic 槽,这个表面会同时错两次:通道错,数值还反了。导入器自带的着色器是直接按 glTF 的排布来读的,这就是为什么「顺手整理一下」把它们换成 URP/Lit,会让整座小镇看起来像塑料。
还有两个贴图标记是无声失败。法线贴图必须设成 Normal Map 类型:被当成颜色数据时,它不会看起来坏掉,只是看起来是平的。任何打包的遮罩贴图都要取消勾选 sRGB,否则数值会按伽马解码,一切都比预期更亮一点。在 FBX 这边,这些都在 Materials 标签页:把 Location 设为 Use Embedded Materials,点 Extract Materials 和 Extract Textures,然后用 Search and Remap 一次性把上百个槽位指向你自己的材质库。
碰撞体:把网格碰撞体拿掉
生成几何体和 Mesh Collider 是很差的搭配,原因不是审美,而是引擎的硬限制。网格碰撞体要么是凸的,要么不是。非凸的只能用于静态物体——挂上 Rigidbody,Unity 直接拒绝。凸的上限是 255 个三角形,而一栋生成的房子有三千到三万个。也就是说,建筑的可见网格只有在它永不移动时才能当碰撞体,而即便如此,你也是在让物理系统遍历立面上的每一个三角形,只为告诉玩家他撞墙了。
导入时关掉 Generate Colliders,然后有意识地过一遍:
- 地面、道路、地形——如果是一整片大体平坦的面,在可见网格上用非凸 Mesh Collider 可以接受。单独做一张低模碰撞网格更好;平坦街区下面放一个盒子更好。
- 你不会进去的建筑——每栋一个 Box Collider,按渲染器包围盒缩放。
- 你会进去的建筑——墙、地板、天花板各用盒子,门洞就是盒子之间的空隙。搭起来慢一些,运行时便宜一个数量级。
- 树木、路灯、标识、隔离柱——在树干或杆子上放一个 Capsule Collider,树冠什么都不放。玩家理所当然地认为可以从枝叶下面走过去。
- 路缘和矮台阶——常常什么都不需要。step offset 会把控制器带过去,在那儿放碰撞体只会让玩家绊住。
- 任何带 Rigidbody 的东西——基本体,或者 255 面以内的凸网格。没有第三个选项。
碰撞体描述的是玩家能去哪里,不是物体长什么样。一座大教堂配一个盒子。
面对四百个对象,这一遍应该写脚本:遍历层级,按每个 Renderer 的包围盒加 BoxCollider,跳过你的植被名称前缀,不到一分钟就能完成绝大部分。前提是这片场景是以一个个独立对象的形式过来的,而不是一整块焊死的网格,这值得在导出前确认:在 Cuberta 这类由智能体驱动的编辑器里,每栋建筑、每件道具都保持为可选中的对象。顺便把 Player Settings 里的 Prebake Collision Meshes 保持开启:运行时烘焙网格碰撞体,会在场景加载的那一刻表现为一次掉帧。
光照:缺失的第二套 UV
几乎所有生成网格都只带一套 UV,就是贴图用的那套。光照贴图需要第二套,而且要展开到单位方块内没有任何两个三角形重叠。没有它,烘焙结果会出现黑斑、接缝,或者光从一面墙漏到另一面墙上。
FBX 只需一个勾选框:模型导入设置里的 Generate Lightmap UVs 会创建第二套 UV 通道。代价在你对三百个网格勾它之前值得心里有数。
- 导入时间。展开几百个网格要花上几分钟,而且每次重新导入都会再跑一遍。
- 纹素利用率。自动打包比手工展开松散,同样的效果要花更多光照贴图分辨率。
- 它不会修几何体。来源里重叠或退化的三角形,展开之后照样漏光。
glTF 导入器在生成光照贴图 UV 这件事上并不一致,甚至可能根本没有,这就是当你已经确定要烘焙时,把 FBX 带进 Unity 的现实理由。如果你就是要用 GLB,那就自己写编辑器脚本,对每个网格调用 Unwrapping.GenerateSecondaryUVSet。
在和展开工具较劲之前,先掂量一个替代方案。在 Unity 6 里,Adaptive Probe Volumes 让 URP 和 HDRP 拿到烘焙的间接光,既不需要光照贴图 UV,也不需要手工摆探针——Unity 按几何密度分布探针。对于一片生成的场景,反正 UV 也不在你手上,这笔交易通常更划算。你放弃的是静态表面上细腻的烘焙阴影:探针承载的是间接光,不是清晰的接触阴影。
大场景从哪里开始变痛
四百个对象就是四百个 draw call,而这还是在角色进场之前;一座生成的小镇很快就能凑到这个数。三项设置能解决大部分问题:
- Static 标记。把所有不会动的东西标为 Static。这换来静态合批——Unity 把网格合进每个最多 64000 个顶点的共享缓冲区——外加遮挡剔除和参与 GI。代价是内存:合并后的缓冲区是几何体的额外副本,一座全是独特网格的小镇可以多出几百 MB。
- GPU 实例化。如果生成器把同一根路灯复用了六十次,在它的材质上勾 Enable GPU Instancing,这六十个就会收敛成极少的绘制调用。独特的建筑得不到任何好处。注意优先级:Unity 会对已经成功进入静态合批的渲染器关闭实例化,所以相同的道具只能二选一。
- Read/Write。除非运行时要读网格数据,否则保持关闭:开着的话,每个网格都会在 CPU 内存里多留一份副本。
LOD 链、贴图图集和三角面预算是另一个题目,为游戏优化生成场景那篇讲得更完整。
真正会碰到的五种翻车
- 全是洋红。材质带的是另一条管线的着色器。在目标管线激活的状态下重新导入;如果是 Unity 自带着色器,就跑 Render Pipeline Converter。
- 小镇大了或小了一百倍。FBX 单位比例:Model 标签页的 Convert Units 和 Scale Factor,然后用 2 米胶囊体去验,别用眼睛。
- 角色从地面掉下去。根本没有碰撞体——glTF 一个都不带,而 Generate Colliders 是 FBX 的选项,你多半是故意没勾。老老实实过一遍碰撞体。
- 烘焙结果发黑或斑驳。没有第二套 UV。FBX 用 Generate Lightmap UVs,GLB 用编辑器脚本,或者换 Adaptive Probe Volumes。
- 场景里什么都没有,Play 模式只有 12 fps。绘制调用加阴影。标记静态、关掉小道具的阴影投射,在开始瞎猜之前先看 Stats 窗口。
导入本身是二十分钟。碰撞体那一遍和光照的取舍是半天——和手工搭一个关卡要花的是同样的半天,区别在于你的起点是一座门洞高度真实、车道宽度真实的小镇,而不是一堆灰盒子。认真做一次:之后每一次重新导入,都跑在你第一次选定的那些设置上。