【unity 5学习记录】 可编辑地形 网格 原理讲解 17.8.8

 

【unity 5学习记录】 可编辑地形 网格 原理讲解 17.8.8

这是效果

附上源码 我的****博客是http://blog.****.net/zhong1213/article/details/76904263

 

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TerrainManager : MonoBehaviour
{
    Mesh mesh;

    //材质
    public Material diffuseMap;

    //顶点、uv、索引信息
    private Vector3[] vertives;
    private Vector2[] uvs;
    private int[] triangles;
    private ushort[] blockData;

    //生成信息
    private Vector3 chunkSize;//长宽高
    private int groundHeight;//地面高度

    //区块主体
    private GameObject terrain;

    void Start()
    {
        SetTerrain(10, 10, 10, 5);
    }

    // 通过参数生成地形

    public void SetTerrain(float width, float height, float length, int groundH)
    {
        Init(width, height, length, groundH);//初始化数据
        GetVertives();
        DrawMesh();
        terrain.AddComponent<MeshCollider>();
    }

    /// 初始化计算某些值
    private void Init(float width, float height, float length, int groundH)
    {
        chunkSize = new Vector3(width, height, length);//初始化区块尺寸并赋值
        groundHeight = groundH;//给地面高度赋值
        if (terrain != null)
        {
            Destroy(terrain);
        }
        terrain = new GameObject();//初始化区间
        terrain.name = "plane";//设置chunk名字
        terrain.layer = 8;//设置区间所在层数。只有这一层内的碰撞体才会被射线检测到
        blockData = new ushort[(int)(chunkSize.x * chunkSize.y * chunkSize.z)];//初始化方块数据,方括号内是该区间内所容纳方块数,该数组的容量
        //该循环遍历0,0,0 到 (chunksize-1,chunksize-1,chunksize-1)的方块位置。并根据地面高度。分配方块对应的数字。0是空,1是有方块
        for (int x = 0; x < chunkSize.x; x++)
        {
            for (int y = 0; y < chunkSize.y; y++)
            {
                for (int z = 0; z < chunkSize.z; z++)
                {
                    if (y <= groundH)
                    {
                        blockData[getBlockIndex(x, y, z)] = 1;
                    }
                    else
                    {
                        blockData[getBlockIndex(x, y, z)] = 0;
                    }


                }

            }

        }
        //用于测试
        blockData[getBlockIndex(5, 1, 5)] = 0;
        blockData[getBlockIndex(5, 2, 5)] = 0;
        blockData[getBlockIndex(5, 3, 5)] = 0;
        blockData[getBlockIndex(5, 4, 5)] = 0;
        blockData[getBlockIndex(5, 5, 5)] = 0;
        blockData[getBlockIndex(5, 5, 6)] = 0;
        blockData[getBlockIndex(5, 5, 7)] = 0;
        blockData[getBlockIndex(6, 5, 5)] = 0;
        blockData[getBlockIndex(7, 5, 5)] = 0;
    }
    public void BuildBlock(float px, float py, float pz, int blockID)
    {
        //获取对应的方块并且赋值blockID
        blockData[(int)((pz + py * ((int)chunkSize.z) + (px * (int)(chunkSize.y) * (int)(chunkSize.z))))] = (ushort)blockID;

        //这里开始重绘网格
        GetVertives();
        //给mesh 赋值
        mesh.Clear();
        mesh.vertices = vertives;//,pos);
        mesh.uv = uvs;
        mesh.triangles = triangles;
        //重置法线
        mesh.RecalculateNormals();
        //重置范围
        mesh.RecalculateBounds();
        //更新网格碰撞体
        terrain.GetComponent<MeshCollider>().sharedMesh = mesh;
    }
    /// <summary>
    /// 绘制网格
    /// </summary>
    private void DrawMesh()
    {
        mesh = terrain.AddComponent<MeshFilter>().mesh;//添加网格组件,并且添加到本地mesh变量里
        terrain.AddComponent<MeshRenderer>();//添加网格渲染
        if (diffuseMap == null)
        {
            Debug.LogWarning("No material,Create diffuse!!");
            diffuseMap = new Material(Shader.Find("Diffuse"));
        }

        terrain.GetComponent<Renderer>().material = diffuseMap;

        mesh.Clear();

        //给mesh 赋值
        mesh.vertices = vertives;//,pos);
        mesh.uv = uvs;
        mesh.triangles = triangles;
        //重置法线
        mesh.RecalculateNormals();
        //重置范围
        mesh.RecalculateBounds();
    }

    /// <summary>
    /// 生成顶点信息
    /// </summary>
    /// <returns></returns>
    private Vector3[] GetVertives()
    {
        int index = 0;//顶点初始序号
        //GetUV();

        vertives = new Vector3[(int)((chunkSize.x + 1) * (chunkSize.y + 1) * (chunkSize.z + 1))];//初始化顶点序号
        for (int x = 0; x < chunkSize.x + 1; x++)
        {
            for (int y = 0; y < chunkSize.y + 1; y++)
            {
                for (int z = 0; z < chunkSize.z + 1; z++)
                {

                    if (y == 0)//底面一定绘制
                    {
                        vertives[index] = new Vector3(x, y, z);

                    }
                    else
                    {
                        if (!ifIsSide(x, y, z, 0))
                        {
                            if (ifDifFromAround(x, y, z))
                            {
                                vertives[index] = new Vector3(x, y, z);
                            }
                        }
                    }
                    index++;//即将进行下一个遍历,顶点序号加一,这样是为了每一个坐标都有唯一对应的顶点序号。便于后面绘制三角形通过坐标计算顶点序号

                }
            }
        }
        GetTriangles();//生成三角形信息
        return vertives;
    }
    //这个包含方块序号和坐标的对应规则,可以直接通过方块坐标获得方块序号
    private int getBlockIndex(int x, int y, int z)
    {
        return (z + y * ((int)chunkSize.z) + (x * (int)(chunkSize.y) * (int)(chunkSize.z)));
    }

    //这部分是为了接下来多区块准备的,就是避开绘制周围一圈方块,因为周围一圈方块的绘制需要根据相邻chunk里的方块来绘制
    private bool ifIsSide(int x, int y, int z, int VorT) //v =0 t=1
    {
        if (VorT == 0)//0是给顶点遍历用的
        {
            if (x == 0 || y == 0 || z == 0 || x >= (int)chunkSize.x || y >= (int)chunkSize.y || z >= (int)chunkSize.z)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else//1是给三角形遍历用的
        {
            if (x == 0 || y == 0 || z == 0 || x >= (int)chunkSize.x - 1 || y >= (int)chunkSize.y - 1 || z >= (int)chunkSize.z - 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

    }

    //这部分是顶点遍历的时候。判断顶点周围八个方块是不是一样。只有不一样的情况。这个顶点才会被加载
    private bool ifDifFromAround(int x, int y, int z)
    {
        if (blockData[getBlockIndex(x, y, z)] == 0)
        {

            if (blockData[getBlockIndex(x - 1, y, z)] > 0 ||
                    blockData[getBlockIndex(x, y - 1, z)] > 0 ||
                    blockData[getBlockIndex(x, y, z - 1)] > 0 ||
                    blockData[getBlockIndex(x - 1, y - 1, z)] > 0 ||
                    blockData[getBlockIndex(x, y - 1, z - 1)] > 0 ||
                    blockData[getBlockIndex(x - 1, y, z - 1)] > 0 ||
                    blockData[getBlockIndex(x - 1, y - 1, z - 1)] > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        else
        {

            if (blockData[getBlockIndex(x - 1, y, z)] == 0 ||
                    blockData[getBlockIndex(x, y - 1, z)] == 0 ||
                    blockData[getBlockIndex(x, y, z - 1)] == 0 ||
                    blockData[getBlockIndex(x - 1, y - 1, z)] == 0 ||
                    blockData[getBlockIndex(x, y - 1, z - 1)] == 0 ||
                    blockData[getBlockIndex(x - 1, y, z - 1)] == 0 ||
                    blockData[getBlockIndex(x - 1, y - 1, z - 1)] == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;

    }
    /// <summary>
    /// 生成UV信息
    /// </summary>
    /// <returns></returns>
    /*private Vector2[] GetUV()
    {
        int sum = Mathf.FloorToInt((segment.x + 1) * (segment.y + 1));
        uvs = new Vector2[sum];
        float u = 1.0F / segment.x;
        float v = 1.0F / segment.y;
        uint index = 0;
        for (int i = 0; i < segment.y + 1; i++)
        {
            for (int j = 0; j < segment.x + 1; j++)
            {
                uvs[index] = new Vector2(j * u, i * v);
                index++;
            }
        }

        return uvs;
    }*/

    /// <summary>
    /// 生成三角形信息
    /// </summary>
    /// <returns></returns>
    private int[] GetTriangles()
    {
        int sum = Mathf.FloorToInt(chunkSize.x * chunkSize.y * chunkSize.z * 6);
        triangles = new int[sum];//初始化三角形数组
        uint index = 0;//初始三角形序号

        for (int x = 0; x < chunkSize.x; x++)
        {
            for (int y = 0; y < chunkSize.y; y++)
            {
                for (int z = 0; z < chunkSize.z; z++)
                {
                    /*if (blockData[z + (y * (int)chunkSize.z) + (x * (int)chunkSize.y * (int)chunkSize.z)] != 0){
                        if (y == 0){
                            int self = z + y * ((int)chunkSize.z+1)+ (x * (int)(chunkSize.y+1) * (int)(chunkSize.z+1));
                            int next = z + (y * (int)(chunkSize.z + 1) + ((x+1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));

                            triangles[index] = self;
                            triangles[index + 1] = self + 1;
                            triangles[index + 2] = next + 1;
                            triangles[index + 3] = self;
                            triangles[index + 4] = next + 1;
                            triangles[index + 5] = next;
                            index += 6;
                        }
                    }*/
                    if (y == 0)
                    {
                        int self = z + y * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                        int next = z + (y * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));

                        triangles[index] = self;
                        triangles[index + 1] = self + 1;
                        triangles[index + 2] = next + 1;
                        triangles[index + 3] = self;
                        triangles[index + 4] = next + 1;
                        triangles[index + 5] = next;
                        index += 6;
                    }
                    else
                    {

                        if (!ifIsSide(x, y, z, 1))
                        {
                            if (blockData[getBlockIndex(x, y, z)] == 0)
                            {

                                //下面是判断当前坐标方块上下左右前后的方块是不是实心的
                                //如果是实心的就把面绘制出来。而且要注意三角形面的绘制是一侧的。取决于你取点的顺序。顺时针就是正面,逆时针就是反面

                                //check up and draw triangle

                                if (blockData[getBlockIndex(x, y + 1, z)] != 0)
                                {
                                    int self = z + (y + 1) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + ((y + 1) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));

                                    triangles[index] = self;
                                    triangles[index + 1] = next + 1;
                                    triangles[index + 2] = self + 1;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = next;
                                    triangles[index + 5] = next + 1;
                                    index += 6;
                                }
                                //check doawn and draw triangle
                                if (blockData[getBlockIndex(x, y - 1, z)] != 0)
                                {
                                    int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));

                                    triangles[index] = self;
                                    triangles[index + 1] = self + 1;
                                    triangles[index + 2] = next + 1;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = next + 1;
                                    triangles[index + 5] = next;
                                    index += 6;
                                }
                                //side
                                if (blockData[getBlockIndex(x, y, z - 1)] != 0)
                                {
                                    int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));
                                    int sup = self + (int)chunkSize.z + 1;
                                    int nup = next + (int)chunkSize.z + 1;
                                    triangles[index] = self;
                                    triangles[index + 1] = nup;
                                    triangles[index + 2] = sup;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = next;
                                    triangles[index + 5] = nup;
                                    index += 6;
                                }
                                if (blockData[getBlockIndex(x, y, z + 1)] != 0)
                                {
                                    int self = z + 1 + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + 1 + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));
                                    int sup = self + (int)chunkSize.z + 1;
                                    int nup = next + (int)chunkSize.z + 1;
                                    triangles[index] = self;
                                    triangles[index + 1] = sup;
                                    triangles[index + 2] = nup;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = nup;
                                    triangles[index + 5] = next;
                                    index += 6;
                                }
                                if (blockData[getBlockIndex(x - 1, y, z)] != 0)
                                {
                                    int self = z + (y) * ((int)chunkSize.z + 1) + (x * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 1) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));
                                    int sup = self + (int)chunkSize.z + 1;
                                    int nup = next + (int)chunkSize.z + 1;
                                    triangles[index] = self;
                                    triangles[index + 1] = sup;
                                    triangles[index + 2] = sup + 1;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = sup + 1;
                                    triangles[index + 5] = self + 1;
                                    index += 6;
                                }
                                if (blockData[getBlockIndex(x + 1, y, z)] != 0)
                                {
                                    int self = z + (y) * ((int)chunkSize.z + 1) + ((x + 1) * (int)(chunkSize.y + 1) * (int)(chunkSize.z + 1));
                                    int next = z + ((y) * (int)(chunkSize.z + 1) + ((x + 2) * (int)((chunkSize.y + 1) * (chunkSize.z + 1))));
                                    int sup = self + (int)chunkSize.z + 1;
                                    int nup = next + (int)chunkSize.z + 1;
                                    triangles[index] = self;
                                    triangles[index + 1] = sup + 1;
                                    triangles[index + 2] = sup;
                                    triangles[index + 3] = self;
                                    triangles[index + 4] = self + 1;
                                    triangles[index + 5] = sup + 1;
                                    index += 6;
                                }
                            }
                        }
                    }
                }
            }
        }
        return triangles;
    }
}