Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Solution: Save a prefab with a generated mesh(es) without creating assets.

Discussion in 'Editor & General Support' started by mmankt, Mar 29, 2017.

  1. mmankt

    mmankt

    Joined:
    Apr 29, 2015
    Posts:
    49
    Hey guys, I've seen this topic many times and ran into this myself we I started making procedural stuff for my game. When we generate a mesh and want to bake it into a prefab (like a pre-fractured wall), Unity won't serialize the mesh.
    The most common solution is to save the mesh into assets and it's ok. But in an instance when we have generated tens/hundreds of meshes which need to be individual pieces of something , saving them all takes a lot of time and is kinda pointless. So I decided to share a simple script that will serialize and recreate your meshes once you save a prefab and drag it into the scene/instantiate. Hopefully it will help some beginners.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2. using UnityEditor;
    3. #endif
    4. using UnityEngine;
    5.  
    6. namespace TheTide.utils
    7. {
    8.     [ExecuteInEditMode]
    9.     [RequireComponent(typeof(MeshFilter))]
    10.     public class SerializeMesh : MonoBehaviour
    11.     {
    12.         [HideInInspector] [SerializeField] Vector2[] uv;
    13.         [HideInInspector] [SerializeField] Vector3[] verticies;
    14.         [HideInInspector] [SerializeField] int[] triangles;
    15.         [HideInInspector] [SerializeField]bool serialized = false;
    16.         // Use this for initialization
    17.  
    18.         void Awake()
    19.         {
    20.             if (serialized)
    21.             {
    22.                 GetComponent<MeshFilter>().mesh = Rebuild();
    23.             }
    24.         }
    25.  
    26.         void Start()
    27.         {
    28.             if (serialized) return;
    29.  
    30.             Serialize();
    31.         }
    32.  
    33.         public void Serialize()
    34.         {
    35.             var mesh = GetComponent<MeshFilter>().mesh;
    36.  
    37.             uv = mesh.uv;
    38.             verticies = mesh.vertices;
    39.             triangles = mesh.triangles;
    40.  
    41.             serialized = true;
    42.         }
    43.  
    44.         public Mesh Rebuild()
    45.         {
    46.             Mesh mesh = new Mesh();
    47.             mesh.vertices = verticies;
    48.             mesh.triangles = triangles;
    49.             mesh.uv = uv;
    50.            
    51.             mesh.RecalculateNormals();
    52.             mesh.RecalculateBounds();
    53.  
    54.             return mesh;
    55.         }
    56.     }
    57.  
    58. #if UNITY_EDITOR
    59.     [CustomEditor(typeof(SerializeMesh))]
    60.     class SerializeMeshEditor : Editor
    61.     {
    62.         SerializeMesh obj;
    63.  
    64.         void OnSceneGUI()
    65.         {
    66.             obj = (SerializeMesh)target;
    67.         }
    68.  
    69.         public override void OnInspectorGUI()
    70.         {
    71.             base.OnInspectorGUI();
    72.  
    73.             if (GUILayout.Button("Rebuild"))
    74.             {
    75.                 if (obj)
    76.                 {
    77.                     obj.gameObject.GetComponent<MeshFilter>().mesh = obj.Rebuild();
    78.                 }
    79.             }
    80.  
    81.             if (GUILayout.Button("Serialize"))
    82.             {
    83.                 if (obj)
    84.                 {
    85.                    obj.Serialize();
    86.                 }
    87.             }
    88.         }
    89.     }
    90. #endif
    91. }

    Just create a new script called SerializeMesh and paste it, add the script to a GO with a mesh u want to serialize and you're done.

    Cheers.
     
  2. lubwn

    lubwn

    Joined:
    Mar 22, 2017
    Posts:
    8
    Thank you!!! Man you are a saviour, this is what I really needed and were going to write a script. Save me a ton of work!!! Thanks again.
     
  3. jetr

    jetr

    Joined:
    Jun 2, 2017
    Posts:
    1
    Thank you , you are a genius.
     
  4. pointcache

    pointcache

    Joined:
    Sep 22, 2012
    Posts:
    576
    You can also serialize the mesh into a string and store it in a field (or array).
     
  5. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    This is wonderful! Thank you so very much!
     
  6. hptware

    hptware

    Joined:
    Dec 11, 2012
    Posts:
    107
    I think I must be missing the important step since this doesn't work how I expected. I was expecting to be able to assign a mesh at runtime to an instance of a prefab and the mesh to be retained by the prefab once I returned to the editor? I suspect I don't understand the "recreate the your meshes once you save the prefab".

    What I've done is:

    (1) Created a prefab with a meshfilter, mesh renderer and the script.
    (2) At runtime in playmode assigned the generated mesh to an instance of the prefab.
    (3) Exited playmode back to the editor. No mesh is retained in the prefab or its instance.

    Can someone give a clue on how to implement?
     
  7. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    Not sure why you're trying to save to an instance of a prefab during runtime, since during runtime a instance of a prefab is just a instantiated game object...
     
  8. hptware

    hptware

    Joined:
    Dec 11, 2012
    Posts:
    107
    I want to save a prefab with a mesh generated at runtime. This serialisation code suggests it does that. I've tried applying the mesh to a prefab in the scene and to a game object instantiated from a prefab, but neither retain the mesh once you exit playmode. How did you save a mesh using this serialisation code? I am clearly missing something important in implementing it.
     
  9. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    Did you run Serialize()?
     
  10. hptware

    hptware

    Joined:
    Dec 11, 2012
    Posts:
    107
    Unless I am missing some crucial step this code doesn't seem to work. SerializeField doesn't seem to preserve data generated at runtime once back in the editor (the code also throws an error unless you use sharedMesh instead of mesh).

    I've added debug.Log to Awake(), Start(), Serialize() to print to the console the length of the array verticies. This array is populated from the mesh in Serialize() at runtime and then used in Awake() to rebuild the mesh in the editor. Only the array is cleared on exiting playmode.

    Here's what I did: I have a prefab with the script as a component and a meshfilter. During runtime I create a mesh and apply to the prefabs meshfilter, then I call Serialize(). Then I exit playmode back to the editor. This is what it prints.

    On pressing play
    Awake: Array length 0 - this is expected no mesh has yet been added to the meshfilter
    Start: Array length 0 - this is expected no mesh has yet been added to the meshfilter
    Serialize: Array length 73 - this has added the mesh to the Vector3[] verticies within the prefab.
    Exit back to editor
    Awake: Array length 0 - data in verticies was cleared
    Start: Array length 0 - data in verticies was cleared.
     
  11. mmankt

    mmankt

    Joined:
    Apr 29, 2015
    Posts:
    49
    Lol i forgot that I even posted this, nice to see that some ppl find it useful.

    As i understand what you're trying to do, it won't be possible because Unity itself doesn't serialize fields in prefabs during runtime. They just reset to their original state after you exit playmode. You should generate your mesh in editmode. If you have a runtime mesh modifying app you need to serialize it yourself , whether its a file, an asset or a scriptable object or something else.
     
    NeatWolf likes this.
  12. captaingranit

    captaingranit

    Joined:
    Jul 24, 2019
    Posts:
    1
    Thank you, you saved my project!
     
  13. AlessioGrancini

    AlessioGrancini

    Joined:
    Aug 16, 2017
    Posts:
    8
    It's kind of late to say, but man this is gold.Thank you for sharing, I also learn something new ! For some reason in Unity 2019.4 the prefabs did not include the meshes, didn't happened in the previous version. Saved the project and deadline.
     
  14. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,851
    Hey, that's a clever trick!

    However I feel I should point out one drawback: if you have 100 instances of the same object with this script on it, this is going to result in 100 identical meshes in memory. Whereas with the standard approach of saving the modified mesh to the asset database, all instances would share just one copy of the mesh. Meshes can get pretty big, so this could really matter on memory-constrained devices (like Quest).
     
    joshcamas likes this.
  15. mmankt

    mmankt

    Joined:
    Apr 29, 2015
    Posts:
    49
    that's true, you could build only one mesh and refer instances and set their sharedmeshes to the one serialized (the mesh which is rebuilt on first awake in a prefab and other would not build a new mesh but just set a shared mesh to the one you rebuilt at first) I've used this for a destructible prebaked building and it would require serializing around 2000 small meshes per building. That's why I found it useful ;)
     
  16. Xcrypt1991

    Xcrypt1991

    Joined:
    May 20, 2020
    Posts:
    23
    Isn't it better to save the mesh? Because now we need to rebuild our mesh everytime the game/scene starts
     
  17. NANAMINER_programmer

    NANAMINER_programmer

    Joined:
    May 22, 2022
    Posts:
    2
    Hello, for some reason nothing works for me :(
    I have generated pieces of the object, and when I add your script to these pieces and click Serialize, nothing just happens, I still can't save the pieces to the prefab
    Am I doing something wrong?
     
  18. vistaero

    vistaero

    Joined:
    Mar 23, 2017
    Posts:
    7
    Did you solve it? Are you trying to use it for MeshFilter or MeshCollider? I needed it for MeshCollider, so I modified the code and replaced every mention of MeshFilter to MeshCollider and it worked. You might need to press Serialize on each collider and make sure you are not in prefab mode. You can apply changes to prefab after serializing colliders.
     
  19. masterahuck

    masterahuck

    Joined:
    Sep 10, 2015
    Posts:
    71
    Hello,
    Can you please tell me how I use your script because I added it to my prefab (added a C# script component and pasted it) but I am only getting errors:

    What I have is several prefabs using the same source mesh and I just need those prefabs to use instances or copies of that same source mesh.
     

    Attached Files:

    • a5.jpg
      a5.jpg
      File size:
      191.7 KB
      Views:
      39
  20. brilliantgenius

    brilliantgenius

    Joined:
    Aug 16, 2023
    Posts:
    1
    Thanks a lot!!