GLB 与 FBX:交给游戏引擎的到底该是哪一种
glTF/GLB 与 FBX 各自真正携带什么、各自会在哪里悄悄丢数据,以及交给 Unity、Unreal、Godot、Blender 和 Web 时该选哪一个。
两种格式都能把网格从编辑器送进引擎。真正有争议的是挂在网格上的其余部分:材质模型、纹理的引用方式、数字用的是什么单位、哪个轴朝上,以及骨骼绑定能否活着抵达。这些差异都很具体,而且大多写在文档里,所以这是一个有答案的问题,不是一件靠偏好决定的事。
这两种格式究竟是什么
glTF 2.0 与 GLB
glTF 2.0 是 Khronos Group 制定的开放、免版税规范,就是那个做 Vulkan 和 OpenGL 的组织。它被设计成运行时交付格式:文件里的数据已经接近 GPU 想要的形态,所以加载器基本上只是上传缓冲区,而不是做转换。容器有两种。.gltf 是 JSON,几何缓冲和贴图要么以独立文件躺在旁边,要么以 base64 内联进来。.glb 把同样的 JSON 和一整块二进制数据打包成单个文件。base64 会让二进制数据膨胀约三分之一,所以真正对外发布的应该是 GLB。
规范把 FBX 留作开放的地方全部钉死了。所有线性距离都是米。坐标系是右手系,+Y 朝上,+Z 朝前。角度用弧度。材质是 metallic-roughness,而且写在核心规范里,不是扩展。
FBX
FBX 起源于 Kaydara,是动作捕捉软件 Filmbox 的文件格式;Autodesk 在 2006 年收购了它。它是制作与交换格式,不是运行时格式,行为也完全对得上:它能携带 NURBS 曲面、约束、LOD 组、多段动画 take、摄像机和灯光。
它没有公开规范。参考实现是 Autodesk 的 FBX SDK,以闭源二进制形式发布,因此任何 GPL 许可的工具——Blender 也在其中——都只能从零写自己的读取器。文件分二进制和 ASCII 两种,扩展名都是 .fbx,而且格式带版本号:FBX 2020 的文件是 7.7 版,用 2014 年前后 SDK 构建的工具读取 7.7 文件时,可能会一声不响地丢掉动画和自定义属性。「导出成 FBX」并不是一件确定的事。
逐项对照
| glTF 2.0 / GLB | FBX | |
|---|---|---|
| 归属 | Khronos Group,开放免版税规范 | Autodesk,无公开规范;参考读取器是闭源 FBX SDK |
| 容器 | .gltf(JSON 加外部文件)或 .glb(单个二进制文件) | .fbx,二进制或 ASCII,带版本号 |
| 材质模型 | 核心规范里的 metallic-roughness PBR | Lambert 与 Phong;PBR 靠厂商约定传递 |
| 纹理 | 核心支持 PNG 与 JPEG,KTX2 靠扩展;内嵌在 GLB 里 | DCC 写出的任意格式;只有勾了 Embed Media 才内嵌 |
| 单位 | 米,规范强制 | 取决于文件里的 UnitScaleFactor;默认厘米 |
| 坐标轴 | +Y 朝上,+Z 朝前,右手系,强制 | 每个文件在 GlobalSettings 里自行声明;因软件而异 |
| 动画 | 烘焙好的节点轨道与变形权重轨道,step / linear / cubic spline | take、约束、blend shape、摄像机与灯光动画 |
| 自定义数据 | 几乎任何对象上都能挂 extras JSON | 自定义用户属性,Unity 和 Unreal 都有导入钩子 |
| 压缩 | 几何用 Draco 与 meshopt,纹理用 KTX2 | 格式本身没有 |
| 引擎支持 | Godot 原生、Unreal 走 Interchange、Unity 需装包、Web 的默认选择 | Unity 原生、Unreal 沿用已久、Godot 与 Blender 用 ufbx |
各自会在哪里丢数据
材质,这才是真正的分歧
glTF 的核心材质是 metallic-roughness,通道排布是定死的:粗糙度在 metallic-roughness 贴图的绿通道,金属度在蓝通道,环境光遮蔽在红通道,因此一张打包贴图可以同时服务三者。base color、法线和自发光各有自己的槽位。这里没有什么需要「映射」的:在 Blender 或 Substance 里做好的 metallic-roughness 材质,到了那边仍然是 metallic-roughness 材质。
FBX 定义的是 Lambert 和 Phong,两者都不是 PBR。任何把 PBR 写进 FBX 的导出器都是按约定行事而非按规范——最常见的是 Autodesk 的 Stingray PBS 属性命名空间——而任何导入器都必须认出导出器当时用的那一套约定。当一个 FBX 进来时粗糙度贴图被插进了 specular 槽,或者 metallic 和 roughness 干脆是空的,发生的就是这种不匹配。这是两种格式之间最大的实际差别,也是大多数「模型进来是灰的」帖子存在的原因。
内嵌纹理与引用纹理
GLB 的内嵌是结构性的:图像和几何数据待在同一块二进制缓冲里,因此一个文件就搬走了整个资产。核心 glTF 允许 PNG 和 JPEG;KHR_texture_basisu 扩展加入了装载 Basis Universal 数据的 KTX2 容器,这类纹理在显存里仍保持 GPU 压缩状态,而不是解成原始 RGBA。
FBX 默认是引用。纹理是路径,而路径一换机器就断。Maya、3ds Max 和 Blender 导出器里的 Embed Media 选项会把图像塞进 FBX,导入时它们会被解出到文件旁边一个以文件名加 .fbm 后缀命名的文件夹里。代价是体积:同一次导出,一旦 4K 贴图进去,就会从大约一兆变成几十兆。多数导出器的 Embed Media 默认是关的,这就是那么多 FBX 一进来只有一片粉色的原因。
蒙皮、动画与自定义属性
glTF 存的是烘焙结果。动画是节点上的位移、旋转、缩放和变形权重轨道,插值方式为 step、linear 或 cubic spline。蒙皮影响以四个为一组——JOINTS_0 配 WEIGHTS_0——更多组是合法的,但读取器支持参差不齐:有报告指出 Unreal 的 Interchange glTF 导入器无论文件里有什么,都会截断到每顶点四个影响。把带 IK 和约束的绑定送进 glTF,你拿回来的是运动,不是绑定。
FBX 反过来携带的是制作数据:多段 take、blend shape、约束、带动画的摄像机与灯光。到了自定义数据这一项,局面只是部分反转。glTF 有 extras,可以往节点、网格和材质上挂任意 JSON——格式会完整保留它,而多数引擎导入器会直接忽略,除非你自己写钩子。FBX 的自定义用户属性进引擎的路更成熟:Unity 通过 OnPostprocessGameObjectWithUserProperties 把它们暴露出来,Unreal 有一套 FBX 元数据管线。如果你在 DCC 里就把出生点或玩法数值标在节点上,FBX 对你的要求更少。
转了九十度,或者大了一百倍
这是同一个 bug 的两个成因,而且都不是文件损坏,都是两个程序在约定上没谈拢。
单位。FBX 文件在 GlobalSettings 块里带一个 UnitScaleFactor,而格式的基准单位是厘米——因子为 1 就意味着厘米。一扇在米制场景里做出来的 2 米门,导出时数字原样不动,就变成了一个声称单位是厘米的文件里的「2」。相信文件头的读取器给你一扇 2 厘米的门;忽略它的读取器给你 2 米。Unity 的 FBX 导入器把 Scale Factor 默认设为 0.01,正是为了这件事。glTF 没有对应的旋钮,因为米是硬性要求而不是可选设置。问题的镜像版本出现在 Unreal,它的世界单位是厘米:米制的 GLB 进来时需要在某处乘以 100,当一栋建筑进来小了一百倍,丢掉的就是这次乘法。
坐标轴。glTF 强制 +Y 朝上。FBX 在每个文件里自行声明 up 与 front 轴,而各软件的默认值并不一致:3ds Max 和 Blender 是 Z 朝上,Maya 和 Unity 是 Y 朝上。Blender 的 glTF 导出器有一个默认开启的 +Y Up 选项,会替你完成换算。它的 FBX 导出器则要你自己挑 Up 和 Forward,如果你的选择和读取器的假设不一致,资产就会仰面躺下——在 Unity 里通常表现为导入根节点上被烘死的 -90 度 X 旋转,然后跟每一段读取物体前向量的脚本较劲。
其他检查之前先做两件事:在导入物旁边放一个 2 米的参考立方体,然后看根节点的旋转值。这两条就能抓住大部分被报成「导出坏了」的情况。
分引擎该导出什么
Unity
FBX 是原生路径,Unity 不装任何东西就能读。glTF 导入走的是 Unity glTFast,也就是 com.unity.cloud.gltfast 包,它同时支持编辑器导入和运行时加载,覆盖 built-in、URP 和 HDRP——但它终究是个包,得有人把它装进项目。项目里没有 glTFast 也不打算加,就导 FBX。已经有了就导 GLB,尤其是有东西要在运行时加载模型时,一个自包含、材质原生就是 PBR 的文件省事得多。这个取舍对整片生成出来的环境同样成立,光是材质数量就能让 FBX 的约定问题变得昂贵。
Unreal Engine
Unreal 两种都收。FBX 历史更长,周边工具更深。glTF 现在通过 Interchange 框架导入,相关插件默认启用,而 Epic 已把旧的 glTF Importer 和 Datasmith glTF Importer 列入待移除——方向并不含糊。材质上 glTF 占优,因为 metallic-roughness 可以不经重新解释直接对上 Unreal 的模型。骨骼相关的活儿目前仍然偏向 FBX,部分原因就是上面那个影响数上限。记住 Unreal 是 Z 朝上的左手系,单位厘米;Epic 表示打算从 UEFN 开始逐步转向 Y 朝上的右手系,但今天的编辑器仍然是 Z 朝上。「环境和道具用 GLB,角色用 FBX」这条分法是站得住的。
Godot
文档就是白纸黑字写着 glTF 2.0,推荐。FBX 自 Godot 4.3 起通过开源的 ufbx 库原生导入;在那之前需要 FBX2glTF,一个链接了 Autodesk 专有 SDK 的外部程序,还得单独安装。Godot 是 Y 朝上的右手系、米制,和 glTF 强制的约定完全一致,所以进来时什么都不用换算。用 GLB,没有值得专门写下来的例外。
Blender
两种都能往返,但质量不对等。glTF 的导入导出是和 Khronos 一起做的,随 Blender 一同发布。FBX 出于许可原因从来无法使用 Autodesk 的 SDK;导入器已用 C++ 基于 ufbx 库重写,并在 Blender 5.0 成为默认,而导出器仍然是那个 Python 实现。用 GLB——除非文件要交给在 Maya 或 3ds Max 里工作的人,那 FBX 才是对方的母语。
Web 与 three.js
这里没有可比性。GLTFLoader 是有人维护的推荐路径;FBXLoader 存在,但并不是给它什么文件都打得开。一个 GLB 就是一次请求,不会缺依赖。几何加 Draco 或 meshopt,纹理加 KTX2,在手机上这比下载体积更要紧——而给生成场景做减法是另一件事,有它自己的一套取舍。
什么时候答案是两个都导
从同一个源再导一次只花几秒,而下面几种情况里这就是正确做法:
- 接收方的管线不由你决定。市场上架、交付客户、给另一家工作室。两个都给,让对方挑。
- 模型有两个去处。引擎构建和网页查看器或配置器,对同一份资产的要求并不相同。
- 不同部分走不同的路。环境以 GLB 进引擎,角色以 FBX 回到动画师手里。
- 你在定位导入问题。如果 GLB 进得干干净净而 FBX 不行,问题出在 FBX 的材质约定,不在你的网格上——你刚刚省下了半个下午。
Cuberta 导出 GLB 或 FBX 并带上纹理,所以在一整片生成好的场景上跑这个对照,是一次两分钟的试验,而不是一轮重做。每个项目值得在早期做一次,趁着还没有四百个物件压在某个假设上。
文件一到手就该检查什么
按这个顺序看两分钟,几乎能抓住全部问题:
- 尺度。旁边放一个 2 米的参考立方体。门和台阶最容易暴露问题。
- 朝向。导入根节点的旋转应当是零。X 上出现 -90 就说明轴向约定对不上。
- 材质数量。是和源文件一致,还是全都塌进了一个槽位。
- 纹理指派。base color 用 sRGB,法线和打包贴图用线性。灰色或洋红说明引用没解析上;到 FBX 旁边找那个
.fbm文件夹。 - 着色。该光滑的地方出现硬边,说明平滑组或切线没过来。重新导出时显式写出切线。
- 蒙皮。每顶点的最大影响数,以及绑定姿势是否和源一致。
- 命名。层级里的名字,因为脚本和预制体变体都靠它挂钩,事后改名代价很高。
从这一切里推出来的规则,比争论本身无聊得多:用 glTF 和 GLB,除非你的管线里有某件具体的事非 FBX 不可,而且你说得出那件事是什么。2019 年时诚实的回答是「FBX,带保留意见」。如今 Godot 直接推荐 glTF,Unreal 正在淘汰旧的 glTF 插件转向一等公民的导入器,Unity 自己也发布了包。FBX 不会消失——它仍是制作类软件彼此对话的语言,而且能携带 glTF 描述不了的绑定。但作为交给运行时的那份东西,它一直在失地,理由写在规范里,不在论坛的争吵里。