Terrain To Mesh

wingstone

2022/01/22

阅读量

目录

Unity转换Terrain为mesh的简单功能实现;

  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
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
using UnityEngine;
using UnityEditor;

public class TerrainToMeshWindow : EditorWindow
{

    [MenuItem("Window/TerrainToMeshWindow")]
    static void Init()
    {
        TerrainToMeshWindow window = (TerrainToMeshWindow)EditorWindow.GetWindow(typeof(TerrainToMeshWindow));
        window.Show();
    }
    int row = 5;
    int column = 5;
    Terrain terrain = null;

    void OnGUI()
    {
        EditorGUILayout.BeginVertical();
        terrain = EditorGUILayout.ObjectField("terrain", terrain, typeof(Terrain), true) as Terrain;
        row = EditorGUILayout.IntField("row", row);
        column = EditorGUILayout.IntField("column", column);
        if (GUILayout.Button("convert"))
        {
            if( row * column * 6 > 65535)
            {
                Debug.LogError("row or column is too big! index buffer can't use 16 bit");
                return;
            }

            TerrainData terrainData = terrain.terrainData;
            int vertexCount = (row + 1) * (column + 1);

            // vertex && uv
            Vector3[] vertices = new Vector3[vertexCount];
            Vector2[] uvs = new Vector2[vertexCount];
            for (int i = 0; i <= row; i++)
            {
                for (int j = 0; j <= column; j++)
                {
                    float width = terrainData.size.x;
                    float length = terrainData.size.z;

                    float x = (float)i / row * width;
                    float z = (float)j / column * length;
                    float y = terrain.SampleHeight(new Vector3(x, 0, z));

                    vertices[i * (column + 1) + j] = new Vector3(x, y, z);

                    uvs[i * (column + 1) + j] = new Vector2((float)i / row, (float)j / column);
                }
            }

            // index
            int indexCount = row * column * 6;
            int[] indices = new int[indexCount];
            for (int i = 0; i < row; i++)
            {
                for (int j = 0; j < column; j++)
                {
                    indices[(i * column + j) * 6] = i * (column + 1) + j;
                    indices[(i * column + j) * 6 + 1] = i * (column + 1) + j + 1;
                    indices[(i * column + j) * 6 + 2] = (i + 1) * (column + 1) + j;

                    indices[(i * column + j) * 6 + 3] = i * (column + 1) + j + 1;
                    indices[(i * column + j) * 6 + 4] = (i + 1) * (column + 1) + j + 1;
                    indices[(i * column + j) * 6 + 5] = (i + 1) * (column + 1) + j;
                }
            }

            // normal
            Vector3[] normals = new Vector3[vertexCount];
            int[] normalcounts = new int[vertexCount];
            for (int i = 0; i < vertexCount; i++)
            {
                normals[i] = Vector3.zero;
                normalcounts[i] = 0;
            }
            for (int i = 0; i < row; i++)
            {
                for (int j = 0; j < column; j++)
                {
                    int vid0 = i * (column + 1) + j;
                    int vid1 = i * (column + 1) + j + 1;
                    int vid2 = (i + 1) * (column + 1) + j;
                    int vid3 = (i + 1) * (column + 1) + j + 1;

                    Vector3 normal0 =Vector3.Cross(vertices[vid2]-vertices[vid0], vertices[vid2]-vertices[vid0]).normalized;

                    Vector3 normal1 =Vector3.Cross(vertices[vid3]-vertices[vid1], vertices[vid2]-vertices[vid1]).normalized;

                    normals[vid0] += normal0;
                    normals[vid1] += normal0;
                    normals[vid2] += normal0;
                    normalcounts[vid0]++;
                    normalcounts[vid1]++;
                    normalcounts[vid2]++;

                    normals[vid1] += normal1;
                    normals[vid2] += normal1;
                    normals[vid3] += normal1;
                    normalcounts[vid1]++;
                    normalcounts[vid2]++;
                    normalcounts[vid3]++;
                }
            }
            for (int i = 0; i < vertexCount; i++)
            {
                normals[i] /= normalcounts[i];
                normals[i].Normalize();
            }

            Mesh mesh = new Mesh();
            mesh.name = terrain.name;
            mesh.vertices = vertices;
            mesh.uv = uvs;
            mesh.triangles = indices;
            mesh.normals = normals;

            AssetDatabase.CreateAsset(mesh, "Assets/test.asset");
            AssetDatabase.Refresh();
        }
        EditorGUILayout.EndVertical();
    }
}