Have you ever wonder how to generate terrain procedurally in Unity? You are in the right place!
In this post, we are going to talk about generating mesh for the terrain.
If you don’t know how a mesh is created, I would recommend checking my last post on exactly that subject.
You will need to have an idea of how to generate a mesh, and you will need to use some math skills here. But don’t worry, we will get through it! ?
Generating more than a Quad
Generating a Quad is nothing hard at all, but how about generating a plane?
Well, a plane is nothing more than a series of quads, right?
Exactly! But I bet you don’t want to write all of the points and triangles by yourself, do you?
Let’s starts with the basics and write down base-code for our mesh generator. Oh, and let’s add an option to control the size of that mesh!
using UnityEngine; /// <summary> /// Script that generates a plane with width and depth. /// </summary> public class PlaneGenerator : MonoBehaviour { // Reference to the mesh filter. private MeshFilter meshFilter; // Width of our quad. [SerializeField] [Range(1, 10)] private int width = 2; // Depth of our plane. [SerializeField] [Range(1, 10)] private int depth = 2; /// <summary> /// Unity method called on first frame. /// </summary> void Start() { meshFilter = GetComponent<MeshFilter>(); GeneratePlane(); } /// <summary> /// Method which generates plane. /// </summary> private void GeneratePlane() { // Creating a mesh object. Mesh mesh = new Mesh(); // Defining vertices. Vector3[] vertices; // Defining triangles. int[] triangles; // Defining UV. Vector2[] uv; // Assigning vertices, triangles and UV to the mesh. mesh.vertices = vertices; mesh.triangles = triangles; mesh.uv = uv; // Assigning mesh to mesh filter to display it. meshFilter.mesh = mesh; } }
Now, I think it’s a good idea to see the structure of our mesh. We know that there is a lot of quads, but how they align with each other?
// Defining vertices. Vector3[] vertices = new Vector3[(width + 1) * (depth + 1)]; int i = 0; for (int d = 0; d <= depth; d++) { for (int w = 0; w <= width; w++) { vertices[i] = new Vector3(w, 0, d) - new Vector3(width / 2f, 0, depth / 2f); i++; } }
From the last post, we know that Vertices are not enough to draw a mesh. We also need Triangles! ??
// Defining triangles. int[] triangles = new int[width * depth * 2 * 3]; // 2 - polygon per quad, 3 - corners per polygon for (int d = 0; d < depth; d++) { for (int w = 0; w < width; w++) { // quad triangles index. int ti = (d * (width) + w) * 6; // 6 - polygons per quad * corners per polygon // First tringle triangles[ti] = (d * (width + 1)) + w; triangles[ti + 1] = ((d + 1) * (width + 1)) + w; triangles[ti + 2] = ((d + 1) * (width + 1)) + w + 1; // Second triangle triangles[ti + 3] = (d * (width + 1)) + w; triangles[ti + 4] = ((d + 1) * (width + 1)) + w + 1; triangles[ti + 5] = (d * (width + 1)) + w + 1; } }
With triangles added into the mesh, now Unity can draw it in the 3D environment!
This looks great, but we can make it better! How? With some sample texture! ??
So our last step here will be to calculate the UV map for our mesh, which at this point will be a piece of cake! ?
// Defining UV. Vector2[] uv = new Vector2[(width + 1) * (depth + 1)]; i = 0; for (int d = 0; d <= depth; d++) { for (int w = 0; w <= width; w++) { uv[i] = new Vector2(w / (float)width, d / (float)depth); i++; } }
Now it’s time to see the results!
Great! We did it! Congratulations!
What do you think about it? Have you tried generating other meshes earlier? Let me know in the comment section below!
If you want to get notified on future content, sign up for the newsletter!
As always, the whole project is available at my public repository. ?
And I hope to see you next time! ?