I had some old .asset files of Mesh data that I wanted to make accessible for external editing as FBX files. I was able to use the SDK provided in FBX Exporter | Essentials | Unity Asset Store to write my own context menu option for Mesh .asset files. The SDK enabled a large amount of control, such as saving as ascii or binary format , changing the scale and axis orientation, etc.
You can use the ExtractToFBX function in the code below to save any dynamically generated mesh (you must provide a filepath) or serialized Mesh asset file to an FBX:
using System.IO;
using UnityEngine;
using UnityEditor;
using Unity.FbxSdk;
using FbxExporters.Editor;
// Place in 'Editor' folder
public static class ExtractMeshToFBX
{
// true: fbx file is easy-to-debug ascii, false: fbx file is binary.
static bool saveFbxAsAscii = false;
// The preferred axis system for the exported fbx file
static FbxAxisSystem fbxAxisSystem = FbxAxisSystem.Max;
// The preferred units of the exported fbx file
static FbxSystemUnit fbxUnit = FbxSystemUnit.m;
static string fbxFileTitle = "TITLE HERE";
static string fbxFileSubject = "SUBJECT HERE";
static string fbxFileComment = "COMMENT HERE";
static string fbxFileKeywords = "KEYWORDS HERE";
static string fbxFileAuthor = "AUTHOR HERE";
static string fbxFileRevision = "1.0";
static string fbxFileApplication = "Unity FBX SDK";
[MenuItem("Assets/Extract to FBX", validate = true)]
public static bool MenuExtractToFBXValidate()
{
if (Selection.activeObject == null)
return false;
return Selection.activeObject.GetType() == typeof(Mesh);
}
[MenuItem("Assets/Extract to FBX")]
public static void MenuExtractToFBX()
{
// We assume validation worked and this is always defined.
Mesh mesh = Selection.activeObject as Mesh;
// Set up paths
string meshFilePath = AssetDatabase.GetAssetPath(mesh);
string meshDirectory = Path.GetDirectoryName(meshFilePath);
string filename = Path.GetFileNameWithoutExtension(meshFilePath) + ".fbx";
string filePath = Path.Combine(meshDirectory, filename);
ExtractToFBX(mesh, filePath);
}
public static void ExtractToFBX(Mesh mesh, string filePath)
{
// Make a temporary copy of the mesh to modify it
Mesh tempMesh = Object.Instantiate(mesh);
tempMesh.name = mesh.name;
// If meters, divide by 100 since default is cm. Assume centered at origin.
if (fbxUnit == FbxSystemUnit.m)
{
Vector3[] vertices = tempMesh.vertices;
for (int i = 0; i < vertices.Length; ++i)
vertices */= 100.0f;*
tempMesh.vertices = vertices;
}
// You could handle other SystemUnits here
// FBX Manager
FbxManager manager = FbxManager.Create();
manager.SetIOSettings(FbxIOSettings.Create(manager, Globals.IOSROOT));
// FBX Exporter
FbxExporter fbxExporter = FbxExporter.Create(manager, “Exporter”);
// Binary
int fileFormat = -1;
// Ascii
if (saveFbxAsAscii)
fileFormat = manager.GetIOPluginRegistry().FindWriterIDByDescription(“FBX ascii (*.fbx)”);
fbxExporter.Initialize(filePath, fileFormat, manager.GetIOSettings());
fbxExporter.SetFileExportVersion(“FBX201400”);
// FBX Scene
FbxScene fbxScene = FbxScene.Create(manager, “Scene”);
FbxDocumentInfo sceneInfo = FbxDocumentInfo.Create(manager, “SceneInfo”);
// Set up scene info
sceneInfo.mTitle = fbxFileTitle;
sceneInfo.mSubject = fbxFileSubject;
sceneInfo.mComment = fbxFileComment;
sceneInfo.mAuthor = fbxFileAuthor;
sceneInfo.mRevision = fbxFileRevision;
sceneInfo.mKeywords = fbxFileKeywords;
sceneInfo.Original_ApplicationName.Set(fbxFileApplication);
sceneInfo.LastSaved_ApplicationName.Set(fbxFileApplication);
fbxScene.SetSceneInfo(sceneInfo);
// Set up Global settings
FbxGlobalSettings globalSettings = fbxScene.GetGlobalSettings();
globalSettings.SetSystemUnit(fbxUnit);
globalSettings.SetAxisSystem(fbxAxisSystem);
FbxNode modelNode = FbxNode.Create(fbxScene, tempMesh.name);
// Add mesh to a node in the scene
using (ModelExporter modelExporter = new ModelExporter())
{
if (!modelExporter.ExportMesh(tempMesh, modelNode))
Debug.LogError(“Problem Exporting Mesh”);
}
// add the model to the scene
fbxScene.GetRootNode().AddChild(modelNode);
// Finally actually save the scene
bool sceneSuccess = fbxExporter.Export(fbxScene);
AssetDatabase.Refresh();
// clean up temporary model
if (Application.isPlaying)
Object.Destroy(tempMesh);
else
Object.DestroyImmediate(tempMesh);
}
}
The code worked even on 2017.1 despite the above package requiring 2017.3, after first downloading the package in a later version and then manually moving the DLLs. The dependency on 2017.3 is only due to their custom UI, which this code does not use.
----------
If you want to include materials in the fbx you can easily modify the function to pass in materials which can be passed in as an argument to modelExporter.ExportMesh.
much appreciated
– malkereThank you for this!
– helix_1Wow, this was perfect! We learn something new everyday! Thanks for putting this together!
– CJ-ClarkThank you.
– bhunterdgreat addition.
– elenzil