Search Unity

Dynamic Meshes and memory management

Discussion in 'Scripting' started by SteamPunkPro2, Aug 21, 2014.

  1. SteamPunkPro2

    SteamPunkPro2

    Joined:
    Jun 8, 2013
    Posts:
    29
    I've been working on a 2d sandbox game for awhile now and after trying just about everything I could I still haven't found a good way to manage the meshes of the world in a manner that doesn't either hurt FPS or cause massive GC ticks. I'll quickly go over what I have tried, what I think would help in the hopes that someone might have a suggestion to help me out!

    So in our world we have tiles that make up the world, these tiles are editable by the player, there is a pretty good amount of them (about 3000 of them).

    So far I have tried:

    Creating a mesh that I update with changes and reassign the verts (The problem with this was massive GC ticks due to the fact you cant SET the length of verts used by a mesh, you must clear the now unused verts from the stack, which basically just means copying the array, which is horrible).

    Same as above, but instead of reassigning the verts, setting all the unused verts to vector3.zero (this cost far far to much in the loop and basically grounded the FPS)

    Using GL calls to directly render the scene (This works 'okay' but it results in far far more processing power due to having the loop inside of c# instead of allowing unitys rendery to handle it).

    Creating one quad (a mesh that just has one quad) and redrawing it to the screen wherever I need it, with pre-calculated colors and UVs (This worked the best over all but its still very performance heavy and not really a real solution).


    What would be great to have:

    A version of Graphics.DrawMeshNow that takes parameters like so, Graphics.DrawMeshNow(verts, uvs, colors, length) where the length is the amount of the arrays I wish it to actually use so the values in the arrays I wish to use, so I never need to thrown away the array I can just pre-calculate the max amount ever needed and stick with it.


    Any suggestions would be great!
     
  2. ardizzle

    ardizzle

    Joined:
    Mar 28, 2013
    Posts:
    86
    I have not messed with meshes much but I did have some memory management problems in a game I made a while back. I had tons of projectiles and gui numbers popping up when damage was done and more enemys spawing. It took a toll on fps. So I wrote a script that I have been using since. Like I said I have not ran into the exact issue with the meshes but Ill post the script here and an example script so you can see it in action.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Recycling : MonoBehaviour
    6. {
    7.     private static Recycling instance;
    8.     private int count  = 0; // Counter for CreateObject;
    9.     private int count2 = 0; // Counter for Recyle
    10.     private int count3 = 0; // Counter for CleanUp
    11.     private List<ObjectsInfo> objectList = new List<ObjectsInfo>();
    12.  
    13.     public GameObject CreateObject(GameObject item, Vector3 startPos, Quaternion rotation)
    14.     {
    15.         // This function when called will take the GameObject that you passed
    16.         // and see if it has already been made. If not it will make a new one
    17.         // if so it will return the object it alreay created.
    18.         count = 0;
    19.         while(objectList.Count > count)
    20.         {
    21.             if(objectList[count].gObject.name== item.name + "(Clone)")
    22.             {
    23.                 if(objectList[count].inUse == false)
    24.                 {              
    25.                     // Sets the inUse to be true
    26.                     objectList[count].inUse = true;
    27.                     // Places the object where it is suppose to start
    28.                     objectList[count].gObject.transform.position = startPos;
    29.                     objectList[count].gObject.transform.rotation = rotation;
    30.                     // Reenables the object
    31.                     objectList[count].gObject.SetActive(true);
    32.                     // Returns the old object
    33.                     return objectList[count].gObject;
    34.                 }
    35.             }
    36.             count++; // Goes to the next object in the list to check if it exsists
    37.         }
    38.         if(objectList.Count <= count)
    39.         {
    40.             // Creates a new object and adds it to the array
    41.             objectList.Add(new ObjectsInfo(Instantiate(item, startPos, rotation)as GameObject));      
    42.             // Returns the new object
    43.             return objectList[objectList.Count - 1].gObject;
    44.         }
    45.         return null; // This will never happen
    46.     }
    47.  
    48.     public void Recycle(GameObject item)
    49.     {
    50.         count2 = 0;
    51.         while(objectList.Count > count2)
    52.         {
    53.             if(objectList[count2].gObject == item && objectList[count2].gObject != null)
    54.             {
    55.                 // Disables the object
    56.                 objectList[count2].gObject.SetActive(false);
    57.                 // Sets the inUse to be true
    58.                 objectList[count2].inUse = false;
    59.                 // Breaks the while
    60.                 break;
    61.             }
    62.             count2++; // Goes to the next object in the list to check if it exsists
    63.         }
    64.     }
    65.  
    66.     public void CleanUp()
    67.     {
    68.         // Emptys the array
    69.         count3 = 0;
    70.         while(objectList.Count > count3)
    71.         {
    72.             Destroy(objectList[count3].gObject);
    73.             count3++;
    74.         }
    75.         objectList.Clear();
    76.         // Calls the garbage collector
    77.         System.GC.Collect();
    78.     }
    79.  
    80.     public void Awake()
    81.     {
    82.         instance = this; // Sets instance to this script to allow easy access
    83.     }
    84.    
    85.     public static Recycling Do()
    86.     {
    87.         return instance; // Returns this script for easy access
    88.     }
    89. }
    90.  
    91.  
    92.  
    93. public class ObjectsInfo
    94. {
    95.     public GameObject gObject     = null; // The game object that will be recycled
    96.     public bool       inUse     = true; // Makes sure you don't pull an object that would affect the game
    97.  
    98.     public ObjectsInfo(GameObject go)
    99.     {
    100.         gObject = go;
    101.     }
    102. }
    To sum up what that code does, it gives you a new way to spawn prefabs rather than instinating them. By using this instead you check to see if the object has been created before and if its still in use. If it is it makes a new object. If it isn't in use then it returns an old object. Below is a guide that shows you how to use it.

    " Recycling Resource Guide
    Setup: Drop the Recycling file in with the rest of your code. Attach it to a game object that will always be in the scene, I use the main camera. Setup is done.
    Functions:
    Recycling.Do().CreateObject(GameObject, Vector3, Quaternion);
    Call this function when you need to spawn a game object that is used over and over. Treat if just like the Instantiate function. But rather than creating a new object this checks to see if you have already made the object and pulls it back out for use.
    Recycling.Do().Recycle(GameObject);
    Call this when you need to get rid of the object you created above. This throws the object into an invisible pool so that you can't see it but keeps it in memory so it doesn't uselessly call the Garbage Collector which can slow down your game.
    Recycling.Do().CleanUp();
    Call this when you want to clean everything created above out of memory. A good time to use this is at the end of a level or during a pause screen. This helps make sure you don't have objects just lingering and not being recycled."

    If this is useful and you have any question feel free to ask
     
  3. SteamPunkPro2

    SteamPunkPro2

    Joined:
    Jun 8, 2013
    Posts:
    29
    yea, I'm recycling memory as much as I can (infact all of the above methods excluding the first one dont cause GC issues), that method will not work for my specific problem, which has to do with how immutable mesh data is.
     
  4. SteamPunkPro2

    SteamPunkPro2

    Joined:
    Jun 8, 2013
    Posts:
    29
    After talking to a friend he gave me a pretty good solution but I'm still implmenting it.

    He suggested writing a shader that has a vertex limit built into it, so I can continue to pass and update the same vertex/uv/color arrays and just pass in the limit to keep from using vertexes I dont want.

    now I just need to figure out how to write a vertex shader to do that.