Programmatically change Unity TerrainData with C#

Programmatically change Unity TerrainData with C# (用C#代码来动态改变地形数据)

Unity terrain data could be changed by c# code. You could change the height data and atlas alpha texture, remove or add grass or tree at runtime dynamically.

  • Change Terrain Height
public void ModifyTerrainDataHeight(TerrainData terrainData)
{
    int width = terrainData.heightmapWidth;
    int height = terrainData.heightmapHeight;
    float[,] array = new float[width, height];
    print("width:" + width + " height:" + height);
    for (int i = 0; i < width; i++)
        for (int j = 0; j < height; j++)
        {
            float f1 = i;
            float f2 = width;
            float f3 = j;
            float f4 = height;
            float baseV = (f1 / f2 + f3 / f4) / 2 * 1;
            array[i, j] = baseV * baseV;
        }
    // restore the old heights as need
    heightsBackups = terrainData.GetHeights(0, 0, width, height);
    
    // set up new heights
    terrainData.SetHeights(0, 0, array);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  • Change Terrain Alphamap with a new one
void SetAtlasAlpha(TerrainData terrainData, Texture2D splatAlpha)
{
    float[,,] maps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);

    for (int y = 0; y < terrainData.alphamapHeight; y++)
    {
        for (int x = 0; x < terrainData.alphamapWidth; x++)
        {
            Color col = splatAlpha.GetPixel(x, y);

            maps[x, y, 0] = col.r;
            maps[x, y, 1] = col.g;
            maps[x, y, 2] = col.b;
            maps[x, y, 3] = col.a;
        }
    }

    terrainData.SetAlphamaps(0, 0, maps);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • Clean some trees / or remove some trees on the roads
void RemoveTreesOnRoad(Terrain terrain)
{
    if ( terrain.GetComponent<TerrainCollider>() != null && terrain.GetComponent<TerrainCollider>().enabled )
    {
        UnityEngine.Debug.LogWarning("Please disable TerrainCollider before remove ");
        return;
    }

    TerrainData terrainData = terrain.terrainData;

    Vector3 size = terrainData.size;
    Debug.Log("size: " + size);

    Vector3 pos = terrain.GetPosition();

    TreeInstance[] treeInstances = terrainData.treeInstances;

    List<TreeInstance> list = new List<TreeInstance>();

    float distance = size.y;

    foreach(TreeInstance ti in treeInstances)
    {
        Vector3 treePos = new Vector3( ti.position.x * size.x ,  ti.position.y * size.y, ti.position.z * size.z ) + pos;

        RaycastHit hit;
        if ( Physics.Raycast(treePos + Vector3.up * distance, Vector3.down, out hit, distance * 2f) )
        {   
            // this tree spawned on the road
        } 
        else 
        {
            list.Add(ti);
        }
    }

    terrainData.treeInstances = list.ToArray();
}  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  • Clean all details or grass
int detailResolution = terrainData.detailResolution;

for (int layer = 0; layer < terrainData.detailPrototypes.Length; layer++)
{   
    int[,] detailLayer = terrainData.GetDetailLayer(0, 0, detailResolution, detailResolution, layer);
    for (int j = 0; j < detailResolution; j++)
    {
        for (int k = 0; k < detailResolution; k++)
        {
            detailLayer[j, k] = 0;
        }
    }
    terrainData.SetDetailLayer(0, 0, layer, detailLayer);
} 
1
2
3
4
5
6
7
8
9
10
11
12
13
14

评论