The use of Unity3D Mesh class and grid terrain generation

Generation of triangle faces

Generally speaking, we don't have much contact with the mesh class in development. The mesh class allows you to dynamically generate a mesh in unity3d, which is generally used in terrain or building generation, or in some modeling or optimization plug-ins.

Here is a brief introduction to the usage of the mesh class.
To generate a mesh that can be displayed normally requires the following steps.
1. Set all the vertex positions (local coordinates) of the grid
2. Set which triangle each vertex belongs to
3. If you need to receive light, you need to set the normal of each vertex
4. If you need to paste the material, you need to set the uv correctly

Let's take a triangle as an example.
First, create a new mesh class, then create a three-dimensional vector array, and finally assign a value.
1. Set the vertices

            Mesh mesh = new Mesh();
            var vertices = new Vector3[]
                           {
    
    
                               new Vector3(0, 0, 0),
                               new Vector3(2, 0, 0),
                               new Vector3(1, 2, 1)
                           };
            mesh.vertices = vertices;

2. Set the triangle
Set the triangle to assign an int array, and specify a triangle for every three positions. The following array is [2,1,0], which means that the three vertices of the first triangle are the second of the vertex array set above. , 1st, 0th vertex.

 var triangles = new int[] {
    
    2, 1, 0};
 mesh.triangles = triangles;

3. Set the normal line, the normal line can be calculated automatically, if you don’t need special lighting effects, you can directly use the built-in function of unity to calculate it.

 mesh.RecalculateNormals();

4. Setting uv
uv is relative to the texture. The x-axis and y-axis coordinates of a two-dimensional square texture can be scaled to [0,1]. For each vertex of the three-dimensional model, we also need to give it Associate a uv coordinate, which corresponds to the two-dimensional texture coordinate, and the intermediate value is obtained by linear interpolation. Note that this is an operation of pasting a 2D graphic on a 3D model.
How to set the uv coordinates mainly depends on what kind of effect you need. In fact, on many shapes, there is not a correct uv coordinate, and sometimes it may not be possible to paste it completely, such as pasting a square texture on a triangle.
The uv we set here can only paste half of the picture.

            var uvs = new Vector2[]
                      {
    
    
                          new Vector2(0, 0),
                          new Vector2(1, 0),
                          new Vector2(1, 1)
                      };

Of course, the grid cannot be directly displayed in the scene. In unity, everything needs components, and a grid must also mount components.
The required components are MeshFilter, which manages the grid, and mesh is an attribute of it.
MeshRenderer is also needed. This component manages the material of the grid. Here we use Shader.Find("Standard") to find the standard material.

            var mesh = createTriMesh();
            

            GameObject gameObject = new GameObject();
            gameObject.AddComponent<MeshFilter>();
            gameObject.AddComponent<MeshRenderer>();
            gameObject.GetComponent<MeshFilter>().mesh = mesh;

            Material material = new Material(Shader.Find("Standard"));
            gameObject.GetComponent<MeshRenderer>().material = material;

Finally a triangular patch is generated.
insert image description here
We randomly find a network map and paste it on it.
insert image description here

The effect is as follows

insert image description here

Note that only half of the picture is displayed here, which is related to the uv coordinates I set. You can experience the corresponding relationship here.
And it's not possible to attach a 2D texture to a triangle with three vertices. Unless it is a triangle with four vertices (that is, two of the vertices are at the same point)

Mesh Random Terrain Generation

I have written a lot of noise articles before, and here I use perlin noise plus grid to randomly generate a grid terrain.
The specific process is similar to the previous example, except that the y coordinate (ie height) of the vertex is assigned using noise, and then the x coordinate and z coordinate use the same interval.
Of course, you need to pay attention to the vertex settings corresponding to the triangular mesh. Some calculations are required here, and the specific process will not be listed.
It is probably connected like this, there are 9 vertices in the picture, and then 8 triangles need to be connected
insert image description here

code show as below

        private Mesh createNoiseMesh(int size)
        {
    
    
            Mesh mesh = new Mesh();
            Vector3[] vertexs = new Vector3[size * size];
            for (int y = 0; y < size; y++)
            {
    
    
                for (int x = 0; x < size; x++)
                {
    
    
                    var height = PerlinNoise.fbmNoise(x/32f, y/32f,4) * 50;
                    vertexs[y * size + x] = new Vector3(x, height, y);
                }
            }

            mesh.vertices = vertexs;
            var triangles = new int[(size - 1) * 2 * (size - 1) * 3];
            int index = -1;
            for (int i = 0; i < triangles.Length/2; i += 3)
            {
    
    
                index++;
                triangles[i] = index;
                triangles[i + 1] = index + size;
                triangles[i + 2] = index + 1;
                if ((index % size) + 1 == size - 1)
                {
    
    
                    index++;
                }
              
            }

            index = 0;
            for (int i = triangles.Length/2; i <triangles.Length ; i += 3)
            {
    
    
                index++;
                triangles[i] = index;
                triangles[i + 1] = index + size-1;
                triangles[i + 2] = index + size;
                if ((index % size) ==size-1)
                {
    
    
                    index++;
                }
              
            }
      
             mesh.triangles = triangles;
             mesh.RecalculateNormals();

            return mesh;
        }

The effect is as follows.
The terrain generation in the complete game is naturally impossible to be so simple, but the core must be realized by using the grid class plus some noise functions.

insert image description here

For uv, you can set it as needed, so I won’t set it here, because the vertex spacing is the same, and the simplest uv setting method is of course that the uv spacing of each vertex is the same.

full code

The code about noise can be found in previous blogs.
perlin noise

using UnityEngine;

namespace Algorithm
{
    
    
    public class CreateMesh : MonoBehaviour
    {
    
    
        private void Start()
        {
    
    
            //var mesh = createTriMesh();
            var mesh = createNoiseMesh(256);

            GameObject gameObject = new GameObject();
            gameObject.AddComponent<MeshFilter>();
            gameObject.AddComponent<MeshRenderer>();
            gameObject.GetComponent<MeshFilter>().mesh = mesh;

            Material material = new Material(Shader.Find("Standard"));
            gameObject.GetComponent<MeshRenderer>().material = material;
        }

        private Mesh createNoiseMesh(int size)
        {
    
    
            Mesh mesh = new Mesh();
            Vector3[] vertexs = new Vector3[size * size];
            for (int y = 0; y < size; y++)
            {
    
    
                for (int x = 0; x < size; x++)
                {
    
    
                    var height = PerlinNoise.fbmNoise(x/32f, y/32f,4) * 50;
                    vertexs[y * size + x] = new Vector3(x, height, y);
                }
            }

            mesh.vertices = vertexs;
            var triangles = new int[(size - 1) * 2 * (size - 1) * 3];
            int index = -1;
            for (int i = 0; i < triangles.Length/2; i += 3)
            {
    
    
                index++;
                triangles[i] = index;
                triangles[i + 1] = index + size;
                triangles[i + 2] = index + 1;
                if ((index % size) + 1 == size - 1)
                {
    
    
                    index++;
                }
              
            }

            index = 0;
            for (int i = triangles.Length/2; i <triangles.Length ; i += 3)
            {
    
    
                index++;
                triangles[i] = index;
                triangles[i + 1] = index + size-1;
                triangles[i + 2] = index + size;
                if ((index % size) ==size-1)
                {
    
    
                    index++;
                }
              
            }

            // StringBuilder builder = new StringBuilder();
            // for (int i = 0; i < triangles.Length; i++)
            // {
    
    
            //     builder.Append(triangles[i] + " ");
            // }
            // Debug.Log(builder.ToString());
            
            
             mesh.triangles = triangles;
             mesh.RecalculateNormals();

            return mesh;
        }

        private Mesh createTriMesh()
        {
    
    
            Mesh mesh = new Mesh();
            var vertices = new Vector3[]
                           {
    
    
                               new Vector3(0, 0, 0),
                               new Vector3(2, 0, 0),
                               new Vector3(1, 2, 1)
                           };
            mesh.vertices = vertices;

            var triangles = new int[] {
    
    0, 1, 2};
            mesh.triangles = triangles;

            var uvs = new Vector2[]
                      {
    
    
                          new Vector2(0, 0),
                          new Vector2(1, 0),
                          new Vector2(1, 1)
                      };
            mesh.uv = uvs;
            mesh.RecalculateNormals();
            return mesh;
        }
    }
}

For more usage, please refer to the official documentation. ( Although there is nothing there )
In addition, the code has also been uploaded to the github warehouse, you can also pay attention to it~
my github

Guess you like

Origin blog.csdn.net/o83290102o5/article/details/117426888