- Home /
[Editor scripting] How to save a script generated mesh as an asset/FBX?
Hello,
I've got an editor script that will generate some meshes, and I would like to be able to save these meshes as assets (FBX files)
This:
AssetDatabase.CreateAsset( [mesh object here], [path to asset] );
doesn't work.
Trying to add a ModelImporter object doesn't either, and besides, if I use an FBX extension to save the asset, it will be automatically processed as a model asset, but still won't work.
Thanks.
Answer by Mike 3 · Dec 22, 2010 at 01:24 PM
Use SaveAssets to commit the changes. Also - make sure that path to asset is relative to the project (not relative to Assets), and the extension is .asset
AssetDatabase.CreateAsset( [mesh object here], [path to asset] );
AssetDatabase.SaveAssets();
Or, as the comments say - save your meshes as obj files so that they get imported as model assets :D
Yeah I did that actually, but I still end up with some random data the FBX importer doesn't seem to recognize.
Ah, right, that's not going to work no, you're just saving the unity serialized data that way. What you could try is the obj exporter using the $$anonymous$$esh you already have: http://www.unifycommunity.com/wiki/index.php?title=ObjExporter
Thanks $$anonymous$$ike, but, again, that's not my ultimate goal :) The only reason I want my generated mesh to be a FBX is to invoke the 'Generate Lightmap UVs' feature on it, so that I can lightmap a scene populated with the models I have generated. Devious, I know. But I tried to copy UV2s from the original models I construct my new models from, alas to no avail.
Correction: I got the meshes to be saved as such (they are pure 'mesh' objects), but of course, not being considered as models from Unity, I can't do to them things I can on models, such as generating lightmap uvs.
Try this one ins$$anonymous$$d: http://www.unifycommunity.com/wiki/index.php?title=ObjExporterColorUvs then convert to fbx with an external program?
Answer by Pharan · Apr 20, 2015 at 03:13 AM
I wrote a small editor script that adds a context menu item to the MeshFilter component. It will allow you to save the mesh in the MeshFilter as a .asset file, which you can drag into any GameObject with a MeshRenderer and MeshFilter and it will work.
https://github.com/pharan/Unity-MeshSaver/blob/master/MeshSaver/Editor/MeshSaverEditor.cs
You can also check the code to see how it was done.
Wow, this was perfect! We learn something new everyday! Thanks for putting this together!
Answer by femi · Jan 02, 2011 at 10:55 PM
There is a method not involving generation of intermediate files: have a prefab template that looks almost ready and only misses a mesh. You can then either save your mesh into this prefab and assign it to MeshFilter
's sharedMesh
or (useful if you want to generate multiple meshes into identical prefab) go something like:
// All generated models will be structured after this template string modelTemplate = "Assets/Templates/Model.prefab";
void Generate(string prefabPath) { // clone the model template Object templatePrefab = AssetDatabase.LoadAssetAtPath(modelTemplate, typeof(GameObject)); GameObject template = (GameObject)EditorUtility.InstantiatePrefab(templatePrefab);
// this way links will persist when we regenerate the mesh
Object prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
if (!prefab) {
prefab = EditorUtility.CreateEmptyPrefab( prefabPath );
}
// sort of the same...
Mesh mesh = (Mesh)AssetDatabase.LoadAssetAtPath(prefabPath, typeof(Mesh));
if (!mesh) {
mesh = new Mesh();
mesh.name = name;
AssetDatabase.AddObjectToAsset (mesh, prefabPath);
} else {
mesh.Clear();
}
// generate your mesh in place
BlaBlaBla(mesh);
// assume that MeshFilter is already there. could check and AddComponent
template.GetComponent<MeshFilter>().sharedMesh = mesh;
// make sure
EditorUtility.ReplacePrefab(template, prefab, ReplacePrefabOptions.ReplaceNameBased);
// get rid of the temporary object (otherwise it stays over in scene)
Object.DestroyImmediate(template);
}
This is not generalized enough yet (contains a call to BlaBlaBla :-) - mesh generation function), you really should pass some sort of generator object to this function or something like that. It's because I adapted this snippet from my working code that does something slightly different. Now that I realize that it's generalizable I'll probably refactor it next time I have some time to kill.
This code makes sure that if you've instantiated your models already and decide to regenerate the mesh prefab link will stay intact. On the other hand, model is not linked to the template, if you change the template you will have to regenerate all models you have (and their instances will get updated then).
Thanks atm. However I don't see how this will save the mesh as a $$anonymous$$odel. It will create a prefab asset where you'll put you mesh in, but that won't allow you to invoke on the mesh things you can do to $$anonymous$$odels, such as recalculate normals or tangents or generate secondary UVs for lightmapping (my ultimate goal). Of course, please correct me if I'm wrong! ^^
Ah, do you mean you want to somehow pass it to $$anonymous$$odelImporter? Sorry then, I misunderstood: I gues I see my own problems in other people's questions :-) But: in my script, after the meshes are saved in the prefab I see unity's own ProgressBar dialog appearing saying "importing blablabla.prefab". I wonder if model importers are called with it... Let me test.
Holy shit xD I love you femi, it took me a long while of messing around to get your solution to work for my case, but in the end I managed to do it!
Thank you so much for making a key part of my game possible!! :)
Answer by JohannesMP · Jul 26, 2018 at 07:31 AM
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 https://assetstore.unity.com/packages/essentials/101408 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[i] /= 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
.
Your answer
![](https://koobas.hobune.stream/wayback/20220613092107im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Converting all MA files to FBX without changing GUIDs 2 Answers
How to make plane as tree leaf (2 side plane) like in GTA Vice City? 3 Answers
Different standing positions between drag/drop from Blender and import FBX 1 Answer
[Model] Imported Model - Resets to random rotation upon Play Mode 0 Answers