public static Mesh GenerateTerrainMesh(float[,] heightMap, float heightScale, AnimationCurve heightCurve, int LOD) { int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); // The x and y position for the top left vertex on the mesh. In 3D, the represent the x and // z values. This is used so we can make sure the center vertex of the heightMap will be // at the center of the 3D world. float topLeftX = (width - 1) / -2f; float topLeftY = (height - 1) / 2f; // Based on the LOD, the increment in which vertices are chosen. int vertexSkip = 1; if (LOD > 0) { vertexSkip = LOD * 2; } int verticesPerLine = (width - 1) / vertexSkip + 1; // Log some info about vertex decrease // int totalVertices = verticesPerLine * verticesPerLine; // float vertexDecrease = (1f / ((width * height) / totalVertices)) * 100; // Debug.Log("Vertices per line: " + verticesPerLine + "; Total: " + totalVertices + // "; Vertex Decrease: " + vertexDecrease + "%"); // We need a TerrainData variable to store vertices and triangles for our terrain mesh. TerrainData terrainData = new TerrainData(verticesPerLine, verticesPerLine); // Loop through heights. int vertexIndex = 0; for (int y = 0; y < height; y += vertexSkip) { for (int x = 0; x < width; x += vertexSkip) { // Push a vertex to the end of the array, with the height pulled from the heightmap. terrainData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x, y]) * heightScale, topLeftY - y); // Push a uv mapping to the end of the array. terrainData.uvData[vertexIndex] = new Vector2(x / (float)width, y / (float)height); // Squares originate from the top left corners, so we ignore the vertices lining the // right side and bottom of the vertex map. if (x < width - 1 && y < height - 1) { // Add the bottom left triangle of the square to the mesh. terrainData.AddTriangle(vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine); // Add the top right triangle of the square to the mesh. terrainData.AddTriangle(vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1); } vertexIndex++; } } // Instead of directly creating and returning a mesh, we only return the mesh data. The // reason for this is because Unity does not allow for creating meshes within a thread. // Therefore, we must calculate the mesh data on the thread and create the mesh itself // outside of it. return(terrainData.ConstructMesh()); // this currently DOES return the mesh. }