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

来源:互联网 发布:大数据目前发展情况 编辑:程序博客网 时间:2024/05/22 03:09

本篇为上一篇的原理讲解,我觉得我的表达能力很差,看上一篇的源代码以及边上的注释可能理解到会容易一些


先说ray.cs 射线探测 鼠标按键的探测也写在这里面

0是左键  1右键 2中间滚轮键    px,py,pz是射线所碰到的方块面提供的坐标

 

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Input.GetMouseButtonDown(0))

{

    terraManager.BuildBlock(px, py 1pz, 0);

}

else if (Input.GetMouseButtonDown(1))

{

    terraManager.BuildBlock(px, py, pz, 1);

}

else if (Input.GetMouseButtonDown(2))

{

    terraManager.SetTerrain(1010105);

}

else

{

    //没有碰撞时


}

TerrainManager里改写的比较多因为要建立的是三维的。之前的面片是二维的

思路是获取鼠标指针射线碰撞的坐标,转化成要操作的方块坐标。

目前是操作一个区块里的方块。

private Vector3 chunkSize;//区块的长宽高

private int groundHeight;//地面高度

private ushort[] blockData;//方块数组

方块数组初始化对象的时候元素数([]里面要表示的)就是 区块 长*宽*高,代码如下

 

 C# Code 
1
blockData new ushort[(int)(chunkSize.x chunkSize.y chunkSize.z) 1];

这是根据方块坐标 计算方块编号的函数 方块坐标从0,0,0开始到(chunksize.x-1,chunksize.y-1,chunksize.z-1

 

 C# Code 
1
2
3
4
private int getBlockIndex(int x, int y, int z)

{

    return (z ((int)chunkSize.z) (x (int)(chunkSize.y) (int)(chunkSize.z)));

}

方块数组的值设置为0就是空 1就是有方块,然后接下来在顶点以及三角形遍历的时候,就是读取方块数据来判断是否需要绘制该顶点/三角形

先来说顶点绘制。由于顶点比方块多 我们for循环的范围需要+1。比方说2*2*2的方块需要遍历的顶点数就是3*3*3,首先我们要通过函数bool ifIsSide(int x, int y, int z,int VorT)来判断当前遍历是不是周围方块。如果是的话先暂时避开。因为他们并不是上下左右前后6个面都能获取到方块数据。这个函数还有一个参数来区分是顶点的避开还是三角形面的避开,如果是顶点遍历那VorT取0 如果是三角形遍历那 VorT取1

下面附上该函数代码

 

 C# Code 
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
private bool ifIsSide(int x, int y, int z, int VorT) //v =0 t=1

{

    //检测是否在边界

    if (VorT == 0)

    {

        if (x == 0 || == 0 || == 0 || >= (int)chunkSize.x || >= (int)chunkSize.y || >= (int)chunkSize.z)

        {

            return true;

        }

        else

        {

            return false;

        }

    }

    else

    {

        if (x == 0 || == 0 || == 0 || >= (int)chunkSize.x 1 || >= (int)chunkSize.y 1 || >= (int)chunkSize.z 1)

        {

            return true;

        }

        else

        {

            return false;

        }

    }


}

然后在接下来就是判断包含该顶点位置的四周的方块是不是都是空或都是实心。如果不是。那这个顶点就要被加入进去。函数是bool ifDifFromAround(int x, int y, int z) 参数为当前遍历的顶点坐标

 

 C# Code 
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
private bool ifDifFromAround(int x, int y, int z)

{

    //检测是否和周围的方块不同 存在或不存在


    if (blockData[getBlockIndex(x, y, z)] == 0)

    {


        if (blockData[getBlockIndex(x 1y, z)] 0 ||

                blockData[getBlockIndex(x, 1z)] 0 ||

                blockData[getBlockIndex(x, y, 1)] 0 ||

                blockData[getBlockIndex(x 11z)] 0 ||

                blockData[getBlockIndex(x, 11)] 0 ||

                blockData[getBlockIndex(x 1y, 1)] 0 ||

                blockData[getBlockIndex(x 111)] 0)

        {

            return true;

        }

        else

        {

            return false;

        }

    }

    else

    {


        if (blockData[getBlockIndex(x 1y, z)] == 0 ||

                blockData[getBlockIndex(x, 1z)] == 0 ||

                blockData[getBlockIndex(x, y, 1)] == 0 ||

                blockData[getBlockIndex(x 11z)] == 0 ||

                blockData[getBlockIndex(x, 11)] == 0 ||

                blockData[getBlockIndex(x 1y, 1)] == 0 ||

                blockData[getBlockIndex(x 111)] == 0)

        {

            return true;

        }

        else

        {

            return false;

        }

    }

    return false;


}

 

整个顶点遍历的代码如下

 

 C# Code 
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
private Vector3[] GetVertives()

{

    int sum;



    int index 0;

    //GetUV();


    vertives new Vector3[(int)((chunkSize.x 1(chunkSize.y 1(chunkSize.z 11)];

    for (int 0chunkSize.x 1x++)

    {

        for (int 0chunkSize.y 1y++)

        {

            for (int 0chunkSize.z 1z++)

            {


                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;

}

然后就是遍历三角形,其实是遍历方块坐标,先筛选出是实心的方块,然后分别判断这个方块坐标 上下左右前后的方块是不是空的。如果是空的。就需要吧这两个方块之间的面通过添加三角形的方式绘制出来。以下是代码

 

 C# Code 
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
private int[] GetTriangles()

{

    int sum Mathf.FloorToInt(chunkSize.x chunkSize.y chunkSize.z 6);

    triangles new int[sum];

    uint index 0;


    for (int 0chunkSize.x; x++)

    {

        for (int 0chunkSize.y; y++)

        {

            for (int 0chunkSize.z; z++)

            {

                

                if (y == 0)

                {

                    int self ((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                    int next (y (int)(chunkSize.z 1((x 1(int)((chunkSize.y 1(chunkSize.z 1))));


                    triangles[index] self;

                    triangles[index 1self 1;

                    triangles[index 2next 1;

                    triangles[index 3self;

                    triangles[index 4next 1;

                    triangles[index 5next;

                    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, 1z)] != 0)

                            {

                                int self (y 1((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next ((y 1(int)(chunkSize.z 1((x 1(int)((chunkSize.y 1(chunkSize.z 1))));


                                triangles[index] self;

                                triangles[index 1next 1;

                                triangles[index 2self 1;

                                triangles[index 3self;

                                triangles[index 4next;

                                triangles[index 5next 1;

                                index += 6;

                            }

                            //check doawn and draw triangle

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

                            {

                                int self (y) ((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next ((y) (int)(chunkSize.z 1((x 1(int)((chunkSize.y 1(chunkSize.z 1))));


                                triangles[index] self;

                                triangles[index 1self 1;

                                triangles[index 2next 1;

                                triangles[index 3self;

                                triangles[index 4next 1;

                                triangles[index 5next;

                                index += 6;

                            }

                            //side

                            if (blockData[getBlockIndex(x, 1)] != 0)

                            {

                                int self (y) ((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next ((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 1nup;

                                triangles[index 2sup;

                                triangles[index 3self;

                                triangles[index 4next;

                                triangles[index 5nup;

                                index += 6;

                            }

                            if (blockData[getBlockIndex(x, 1)] != 0)

                            {

                                int self 1 (y) ((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next 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 1sup;

                                triangles[index 2nup;

                                triangles[index 3self;

                                triangles[index 4nup;

                                triangles[index 5next;

                                index += 6;

                            }

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

                            {

                                int self (y) ((int)chunkSize.z 1(x (int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next ((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 1sup;

                                triangles[index 2sup 1;

                                triangles[index 3self;

                                triangles[index 4sup 1;

                                triangles[index 5self 1;

                                index += 6;

                            }

                            if (blockData[getBlockIndex(x 1z)] != 0)

                            {

                                int self (y) ((int)chunkSize.z 1((x 1(int)(chunkSize.y 1(int)(chunkSize.z 1));

                                int next ((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 1sup 1;

                                triangles[index 2sup;

                                triangles[index 3self;

                                triangles[index 4self 1;

                                triangles[index 5sup 1;

                                index += 6;

                            }


                            //vertives[index] new Vector3(x, y, z);

                        }

                        //check dawn and draw

                    }

                    //index++;

                }

            }

        }

    }

    return triangles;

}

到这里为止我们就已经实现了改变方块数据。以及根据方块数据绘制面所需要调用的函数了

接下来是执行方块的放置和破坏的函数。表面上是放置和破坏。实际上是把整个地形重新绘制一遍,所以我们要引入区块的思想。不然绘制的太多。会导致运算量过大

 

 C# Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void BuildBlock(float px, float py, float pz, int 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;

}

原创粉丝点击