Search Unity

Saving and Loading Terrain information at runtime

Discussion in 'World Building' started by Tempus_G, May 2, 2021.

  1. Tempus_G

    Tempus_G

    Joined:
    May 12, 2015
    Posts:
    53
    I am making a game for which I need to be able to edit my terrain and save it...... then load it again later to play on or edit again.
    To that end I am successful.
    My problem is that it takes WAY too long to save and load the terrain data. Namely the splat maps
    All works perfectly, except for the long save and load times.

    The approach that I took is this, with a similar load function.

    Code (CSharp):
    1.    
    2. private void SaveTerrainAlpha(string filename)
    3.    {
    4.        Directory.CreateDirectory(new FileInfo(Path.Combine(Application.persistentDataPath, filename)).DirectoryName);
    5.        float[,,] numArray = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
    6.        BinaryWriter writer = new BinaryWriter(new FileStream(Path.Combine(Application.persistentDataPath, filename), FileMode.Create, FileAccess.ReadWrite, FileShare.None));
    7.        int num = 0;
    8.        while (num < terrainData.alphamapWidth)
    9.        {
    10.            int num2 = 0;
    11.            while (true)
    12.            {
    13.                if (num2 >= terrainData.alphamapHeight)
    14.                {
    15.                    num++;
    16.                    break;
    17.                }
    18.                float[] numArray2 = new float[targetTerrain.terrainData.alphamapLayers];
    19.                int index = 0;
    20.                while (true)
    21.                {
    22.                    if (index >= numArray.GetLength(2))
    23.                    {
    24.                        num2++;
    25.                        break;
    26.                    }
    27.                    numArray2[index] = numArray[num, num2, index];
    28.                    writer.Write(numArray[num, num2, index]);
    29.                    index++;
    30.                }
    31.            }
    32.        }
    33.        writer.Close();
    34. }
    35.  

    What I would like to know is if there is a batter way to improve the speed.
    Now the texture sizes will probably have an impact, as well as how many textures are in use. But unless I am willing to suffer on quality quite a bit, that is not going to help much.
     
  2. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,192
    For the saving, split the save over multiple frames using a coroutine. You'll have to play around with how much to save per frame, but you can target specific smaller areas of the terrain using terrainData.GetAlphamaps.

    for loading, you might be able to do the same thing (target a smaller area), though I do not know if there is some built in overhead of SetAlphamaps that would make repeated calls non performant. You will need to test to find out, but overall I would think it would be more performant than setting the alphamap of the entire terrain at once.

    Edit: Also take a look at this thread (similar question): https://forum.unity.com/threads/fast-alternative-to-setalphamaps.1057685/
     
  3. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    568
    whats the logic behind this, I was under the impression co-routines are not multi threaded
     
  4. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,192
    No, they are not multi threaded, however coroutines are useful when you want to split some work that would normally take a long time (and thus cause a lag spike if executed in a single frame) over multiple frames. The work takes longer to finish over all, but it keeps each individual frame under your target threshold to keep gameplay smooth.

    In the OP's situation, it is unlikely that the speed of the read/write operation finished would have any noticeable effect on gameplay, thus the recommendation to split the work up using coroutines. Testing is of course needed; it may be that splitting the read operation is not necessary, or vice versa that splitting the write operation up does more harm than good.
     
    Mortalanimal likes this.