Synchronize Terrain Layer Order Between Terrains in Unity

Recently I was converting a whole open world terrain to MicroSplat, which enhances the look of the terrain and optimizes it. The terrain I was working with had more than 10 chunks and all had different orders of terrain layers. Normally, you would use a Terrain Layer Profile so that every terrain has the same order, but it was too late. Reordering the layers didn’t work, as the splat arrays only contained indices to the layers, thus effectively swapping the two textures when reordering. I searched online for solutions to this, but found nothing, which is why I’m posting this.

Here’s the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TerrainFixer : MonoBehaviour
{
    public Terrain[] terrains;

    public List<TerrainLayer> layerProfile;

    [ContextMenu("Reorder splats")]
    void ReorderSplats()
    {
        layerProfile.Clear();
        for(int i = 0; i < terrains.Length; i++)
        {
            for(int j = 0; j < terrains[i].terrainData.terrainLayers.Length; j++)
            {
                TerrainLayer layer = terrains[i].terrainData.terrainLayers[j];
                if(!layerProfile.Contains(layer))
                {
                    layerProfile.Add(layer);
                }
            }
        }

        for(int i = 0; i < terrains.Length; i++)
        {
            TerrainData d = terrains[i].terrainData;

            float[,,] oldSplats = d.GetAlphamaps(0, 0, d.alphamapWidth, d.alphamapHeight);
            float[,,] newSplats = d.GetAlphamaps(0, 0, d.alphamapWidth, d.alphamapHeight);
            
            for(int oldIndex = 0; oldIndex < d.terrainLayers.Length; oldIndex++)
            {
                int index = layerProfile.FindIndex((a) => a == d.terrainLayers[oldIndex]);
                if(index == -1)
                {
                    Debug.LogWarning($"Texture not found in custom layer profile");
                    continue;
                }
                if(index >= d.terrainLayers.Length)
                {
                    Debug.LogWarning($"{index} bigger than terrain layer length of {d.terrainLayers.Length}");
                    continue;
                }
                for(int y = 0; y < d.alphamapHeight; y++)
                {
                    for(int x = 0; x < d.alphamapWidth; x++)
                    {
                        newSplats[x, y, index] = oldSplats[x, y, oldIndex];
                    }
                }
            }

            d.SetAlphamaps(0, 0, newSplats);
        }
    }
}



To be clear, I didn’t test this code on a large set of terrain maps. All I know is that it worked perfectly for my purpose. So here’s how it’s used.

  • Attach the TerrainFixer component to any game object you like.
  • Assign all terrains you want to fix to the terrains array.
  • Right click on the component, press Reorder splats.
  • Copy the created layerProfile list and create a profile asset with it
  • Assign the profile to each terrain you have


Done! I’ve put some warning logs inside the code in case something breaks, you can contact me via email if you spot a bug and I will update this post. Goodbye!

Table of Contents
Choose a title and go to interesting part of the article

Leave Your Comment