在 Unity 中,将游戏对象或场景在运行时导出为 FBX 文件,对于程序化内容生成(Procedural Content Generation)、用户自定义内容(UGC)或资产备份非常有用。本教程将指导你如何使用 Autodesk FBX SDK for Unity 实现这一功能。
重要前提:此功能不能在 WebGL 或 iOS 等受沙盒限制的平台使用,因为它需要访问文件系统。
获取 FBX SDK for Unity 从 Autodesk 官方或 Unity Asset Store 获取 FBX Exporter或 Autodesk FBX SDK for Unity包。 注意:不同 Unity 版本(如 2019, 2020, 2021+)需要对应版本的 SDK 包,请仔细核对。 安装与导入 将下载的 .unitypackage文件拖入 Unity 编辑器,完成导入。 导入后,在 Assets文件夹下会出现 Autodesk或 FBXExporter等相关目录。 项目设置 API Compatibility Level:在 Player Settings中,将 Api Compatibility Level设置为 .NET 4.x 或 .NET Standard 2.1,因为 FBX SDK 依赖较新的 .NET 功能。 平台:确保目标平台是 Standalone (Windows, macOS, Linux) 或 Android (有存储权限)。 确保它们的 Transform是你期望的最终世界坐标。 创建一个 C# 脚本,例如 RuntimeFBXExporter.cs,并挂载到一个空物体上。
using UnityEngine;
using System.Collections.Generic;
// 引入 FBX SDK 命名空间
using Autodesk.Fbx;
public class RuntimeFBXExporter : MonoBehaviour
{
// 导出的文件名
public string fileName = "MyExportedModel";
// 导出路径
public string exportPath = "C:/Exports/";
void Update()
{
// 按键盘 E 键触发导出
if (Input.GetKeyDown(KeyCode.E))
{
ExportGameObject(gameObject, exportPath + fileName + ".fbx");
}
}
public void ExportGameObject(GameObject go, string path)
{
// 1. 创建 FBX Manager
FbxManager fbxManager = FbxManager.Create();
FbxIOSettings fbxIOSettings = FbxIOSettings.Create(fbxManager, Globals.IOSROOT);
fbxManager.SetIOSettings(fbxIOSettings);
// 2. 创建 FBX Scene
FbxScene fbxScene = FbxScene.Create(fbxManager, "MyScene");
// 3. 将 Unity GameObject 转换为 FBX Node
// 这是最核心的一步
FbxNode fbxNode = ConvertGameObjectToFbxNode(go, fbxManager, fbxScene);
if (fbxNode != null)
{
fbxScene.GetRootNode().AddChild(fbxNode);
}
else
{
Debug.LogError("转换失败,无法导出。");
return;
}
// 4. 创建 Exporter 并导出
FbxExporter fbxExporter = FbxExporter.Create(fbxManager, "MyExporter");
int fileFormat = fbxManager.GetIOPluginRegistry().FindWriterIDByDescription("FBX ascii (*.fbx)");
bool status = fbxExporter.Initialize(path, fileFormat, fbxIOSettings);
if (!status)
{
Debug.LogError("初始化 FBX Exporter 失败: " + fbxExporter.GetStatus().GetErrorString());
return;
}
status = fbxExporter.Export(fbxScene);
if (status)
{
Debug.Log("成功导出 FBX 到: " + path);
}
else
{
Debug.LogError("导出 FBX 失败: " + fbxExporter.GetStatus().GetErrorString());
}
// 5. 清理
fbxExporter.Destroy();
fbxScene.Destroy();
fbxManager.Destroy();
}
private FbxNode ConvertGameObjectToFbxNode(GameObject go, FbxManager manager, FbxScene scene)
{
// 创建 FBX 节点
FbxNode fbxNode = FbxNode.Create(manager, go.name);
// 设置 Transform
fbxNode.LclTranslation.Set(new FbxDouble3(go.transform.position.x, go.transform.position.y, go.transform.position.z));
fbxNode.LclRotation.Set(new FbxDouble3(go.transform.eulerAngles.x, go.transform.eulerAngles.y, go.transform.eulerAngles.z));
fbxNode.LclScaling.Set(new FbxDouble3(go.transform.localScale.x, go.transform.localScale.y, go.transform.localScale.z));
// 处理 MeshFilter
MeshFilter meshFilter = go.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
{
FbxMesh fbxMesh = CreateFBXMesh(meshFilter.sharedMesh, manager, scene);
fbxNode.SetNodeAttribute(fbxMesh);
}
// 递归处理子对象
foreach (Transform child in go.transform)
{
FbxNode childFbxNode = ConvertGameObjectToFbxNode(child.gameObject, manager, scene);
if (childFbxNode != null)
{
fbxNode.AddChild(childFbxNode);
}
}
return fbxNode;
}
private FbxMesh CreateFBXMesh(Mesh unityMesh, FbxManager manager, FbxScene scene)
{
FbxMesh fbxMesh = FbxMesh.Create(manager, "MyMesh");
// 顶点
Vector3[] vertices = unityMesh.vertices;
fbxMesh.InitControlPoints(vertices.Length);
for (int i = 0; i < vertices.Length; i++)
{
fbxMesh.SetControlPointAt(new FbxVector4(vertices[i].x, vertices[i].y, vertices[i].z), i);
}
// 三角面
int[] triangles = unityMesh.triangles;
for (int i = 0; i < triangles.Length; i += 3)
{
fbxMesh.BeginPolygon();
fbxMesh.AddPolygon(triangles[i]);
fbxMesh.AddPolygon(triangles[i + 1]);
fbxMesh.AddPolygon(triangles[i + 2]);
fbxMesh.EndPolygon();
}
return fbxMesh;
}
}在 Inspector 面板中,可以修改 fileName和 exportPath。 如果一切顺利,你会在指定的 exportPath下找到导出的 .fbx文件。 材质与纹理 (Materials & Textures) 本教程中的基础代码不包含材质导出。 要导出材质,你需要遍历 MeshRenderer的 sharedMaterials,解析 Albedo, Metallic, Normal等贴图,并在 FBX 中创建对应的 FbxSurfaceMaterial和 FbxTexture。 这是一个相对复杂的过程,建议参考 Autodesk 提供的官方示例代码。 骨骼动画 (Skinned Meshes) 导出带蒙皮的网格 (Skinned Mesh) 需要额外处理 SkinnedMeshRenderer和 Bone权重,将 FbxCluster与 FbxMesh关联起来。 坐标系转换 (Coordinate System) Unity 使用左手坐标系 (Y-Up),而 FBX SDK 默认是右手坐标系 (Y-Up 或 Z-Up)。 重要:在 ConvertGameObjectToFbxNode函数中,你可能需要添加一个转换矩阵,将顶点的 X 或 Z 坐标取反,以确保导出的模型在 Maya/3ds Max 中方向正确。 例如:new FbxVector4(go.transform.position.x, go.transform.position.y, -go.transform.position.z) 使用 Autodesk FBX SDK for Unity 进行运行时导出,核心在于理解 FBX 场景、节点、网格的创建流程,并处理好 Unity 与 FBX 坐标系 的差异。