- Home /
Is it possible to save a generated mesh instance along with a scene without creating an asset for it?
I'm generating some small meshes (in edit mode) and would like to save them as part of the MeshFilter in my scene. I want to avoid having to create any prefabs or mesh assets because those meshes are used only once for each instance.
I've noticed that my meshes don't get saved with the scene. I've recorded undo for the MeshFilter component, set the new mesh instance dirty and set the scene dirty. The changes persist through play mode, but not when I reload the scene.
Is this a fixed limitation or am I forgetting something? Again, I know, I can save the mesh instance as an asset and everything will work, but I want to avoid that because there are many of them and they can't be reused.
Solution
Here's some working example code to show how to use Undo.RegisterCreatedObjectUndo as was indicated by @Bunny83:
[ContextMenu("Generate Mesh")]
public void GenerateMesh()
{
Mesh mesh = new Mesh();
UnityEditor.Undo.RegisterCreatedObjectUndo(mesh, "Generate Mesh");
MeshFilter filter = GetComponentInChildren<MeshFilter>();
UnityEditor.Undo.RecordObject(filter, "Generate Mesh");
filter.sharedMesh = mesh;
mesh.name = "My Mesh";
mesh.vertices = new Vector3[]
{
new Vector3 (-0.5f, 0, -0.5f),
new Vector3 (0.5f, 0, -0.5f),
new Vector3 (0.5f, 0, 0.5f),
new Vector3 (-0.5f, 0, 0.5f),
};
mesh.triangles = new int[]
{
0, 2, 1,
0, 3, 2
};
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
You can always save the mesh data (at least vertices and triangles arrays) to file via JSON, BinaryFormatter etc. and load it again to re-create a mesh.
That's not a bad suggestion, but I think in my case it would be overkill to serialize the meshes myself. I also want the meshes to be visible in edit mode, so I would have to add logic to recreate them there as well. If there's no way to let Unity save them with the scene, I'll store them as regular assets. I was just wondering because its possible to save e.g. a ScriptableObject instance as part of another $$anonymous$$onoBehaviour in the scene without having to create an asset for it, but maybe that's a special case and not applicable to other resources.
Answer by Bunny83 · Feb 20, 2018 at 05:32 AM
Yes it's possible to save a Mesh object inside the scene. Did you forget to register your object to the undo system? Though even that wouldn't be necessary. Just marking the scene as dirty should be enough. Any action you take manually though the inspector on scene objects usually marks the scene as dirty so it need to be saved again. However if you just create objects / add components without registrating them to the undo system Unity won't realise that the scene need to be saved again.
You may want to have a look at the Undo class. You have to use Undo.RegisterCreatedObjectUndo after you created your mesh object.The Undo class is your main tool when you do editor scripting. It should be used to create scene objects, adding components and when modifying any values on serialized objects in the scene you have to register the object right before the change. When using SerializedObject / SerializedProperty in inspector code it takes care of the necessary undo steps for the changes your inspector does to the object.
Besides the Undo class it's also worth mentioning the PerfabUtility class. When an editor script wants to create an instance of a prefab you should use PrefabUtility.InstantiatePrefab instead of the usual Instantiate. Only InstantiatePrefab actually preserves the prefab link in the editor. The usual Instantiate just creates a clone that is not related to the prefab.
However
if you need a way to serialize a Mesh to a byte array manually you're lucky. I just created general purpose Mesh serializer. It should support all possible meshes including bone weights, bindposes, submeshes, different mesh topologies and even blendshapes. Unity's default sphere mesh serializes to "33482 bytes", the cube mesh to "1412 bytes". The cube has 24 vertices. It has normals, tangents, uv0 and uv1. That's a total of 14 float values per vertex. So the raw vertex data is 24*14*4 bytes (==1344). It has 36 indices and since the vertex count is smaller than 256 my serializer stores each index as 1 byte. The mesh name is "Cube" so another 5 bytes(1 byte length and 4 characters). So the rough overhead is about 27 bytes.
Why do you know so much, Bunny83?! :D Thanks for pointing out Undo.RegisterCreatedObjectUndo. I've been using the Undo system or setting things dirty, but somehow I forgot about newly created objects. And thanks for the mesh serializer, will come in handy one day, I'm sure!
Answer by Thomas-Hawk · Feb 19, 2018 at 02:19 AM
Are your meshes being created on the fly, or will they be in the resources anyway?
If the latter, couldn't you use script to re-assign the meshes from the resources as part of your load process?
The meshes are generated by an editor script directly affecting the $$anonymous$$eshFilter components in the scene. I do not want to save the meshes to the project folder, because they are unique to a scene, don't require anything special, but there are a lot of instances. They just conceptually "belong" into the scene, but if there is no way to serialize them as part of the scene file, I will store them as assets.