之前的文章mesh在Unity中的简单使用说过,会创建CubeMesh。嗯,来了。
之前已经知道如何创建一个简单的片mesh,那么同理,CubeMesh的创建,同样是从顶点、三角面、uv坐标三个方面生成。
(1) 顶点的生成
一个cube只需要8个顶点就可以表示了。以中心点为(0,0,0),边长为1,按前面顶点index为0,1,2,3,后面顶点index为4,5,6,7顺时针顺序添加顶点,顺序如下图所示:
1 | Mesh m = new Mesh(); |
(2) 生成三角面
和前面一样,按照顺时针方向,顶点index尽量由小到大排列,添加: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 // 前面
_triList.Add(0);
_triList.Add(1);
_triList.Add(2);
_triList.Add(0);
_triList.Add(2);
_triList.Add(3);
// 后面
_triList.Add(4);
_triList.Add(7);
_triList.Add(5);
_triList.Add(5);
_triList.Add(7);
_triList.Add(6);
// 左面
_triList.Add(1);
_triList.Add(5);
_triList.Add(6);
_triList.Add(1);
_triList.Add(6);
_triList.Add(2);
// 右面
_triList.Add(0);
_triList.Add(3);
_triList.Add(4);
_triList.Add(3);
_triList.Add(7);
_triList.Add(4);
// 上面
_triList.Add(2);
_triList.Add(6);
_triList.Add(3);
_triList.Add(3);
_triList.Add(6);
_triList.Add(7);
// 下面
_triList.Add(1);
_triList.Add(4);
_triList.Add(5);
_triList.Add(0);
_triList.Add(4);
_triList.Add(1);
// 赋值给mesh
m.SetTriangles(_triList,0);
(3) 生成uv坐标
按照之前的想法,每个顶点对应一个uv坐标,所以,也是只需要8个uv坐标就可以了。先让uv坐标为0或1,看看效果:
1 | _uvList.Add(new Vector2(1,0)); |
(4) 看看效果
完整代码如下,挂到GameObejct上就可以了:
1 | using UnityEngine; |
mesh生成ok,运行后的效果如下图所示:
好像不对!!前面和后面的uv是对的,其他的几个面uv并不是我想想中的那样!
(5) 理论和对比
在《3D游戏编程大师技巧》中,有几种类型的模型文件解析,基本的结构是,一个完整的顶点列表,在三角面的定义中,指定需要的顶点index和uv坐标。例如:1
2
3
4
5
6vertices:
v0,v1,v2,v3,v4,...,vn
faces: // 每行代表一个三角面的定义
<0,uv0> <1,uv1> <2,uv2>
<0,uv3> <2,uv4> <4,uv5>
....
Unity中,没有面的定义。并且需要uv的数量和顶点的数量一样。即一个顶点对应一个uv坐标。
查看Unity原生的CubeMesh,效果是这样的:
查看其顶点信息,如下图所示:
可以看出,同样的一个位置的顶点由三个。
因为6个面,每个面的uv都不相同,所以,其实需要8*3=24个顶点来表示一个CubeMesh。
那么,只能用24个顶点和24个uv来表示了。
(6) 修改
比较方便的一点是,利用之前的工具MeshViewer,可以很方便的找到顶点的对应顺序。
按照 前面、后面、上面、下面、左面、右面,每个面顶点从右下角开始顺时针的顺序构建mesh,顶点顺序分别为:
- 前面 0,1,2,3
- 后面 4,5,6,7
- 上面 8,9,10,11
- 下面 12,13,14,15
- 左面 16,17,18,19
- 右面 20,21,22,23
有了查看工具的帮助,耐心构建24个顶点,12个三角面,并按照顺序给出24uv坐标,完整代码如下: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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179using UnityEngine;
using System.Collections.Generic;
namespace YanCheZuo
{
[RequireComponent(typeof(MeshFilter))]
public class TestCubeMesh2 : MonoBehaviour
{
private MeshFilter _meshFilter;
private Mesh _mesh;
private List<Vector3> _verticesList = new List<Vector3>();
private List<Vector2> _uvList = new List<Vector2>();
private List<int> _triList = new List<int>();
private void Start()
{
_meshFilter = this.GetComponent<MeshFilter>();
_mesh = _meshFilter.mesh;
RebuildMesh();
}
private void RebuildMesh()
{
_mesh = GetCubeMesh();
_meshFilter.mesh = _mesh;
}
private Mesh GetCubeMesh()
{
Mesh m = new Mesh();
// 本来,只需要8个顶点就可以了。
// 但是,由于6个四边形面的纹理坐标,不能共用顶点的纹理坐标
// 所以,需要8x3个顶点(同样的顶点被3个四边形面共用)
// 前面 0,1,2,3
_verticesList.Add(new Vector3(0.5f, -0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f, -0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, -0.5f));
_verticesList.Add(new Vector3(0.5f, 0.5f, -0.5f));
// 后面 4,5,6,7
_verticesList.Add(new Vector3(0.5f, -0.5f, 0.5f));
_verticesList.Add(new Vector3(-0.5f, -0.5f, 0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, 0.5f));
_verticesList.Add(new Vector3(0.5f, 0.5f, 0.5f));
// 上面 8,9,10,11
_verticesList.Add(new Vector3(0.5f, 0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, 0.5f));
_verticesList.Add(new Vector3(0.5f, 0.5f, 0.5f));
// 下面 12,13,14,15
_verticesList.Add(new Vector3(0.5f, -0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f,-0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f, -0.5f, 0.5f));
_verticesList.Add(new Vector3(0.5f, -0.5f, 0.5f));
// 左面 16,17,18,19
_verticesList.Add(new Vector3(-0.5f, -0.5f, -0.5f));
_verticesList.Add(new Vector3(-0.5f,-0.5f, 0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, 0.5f));
_verticesList.Add(new Vector3(-0.5f, 0.5f, -0.5f));
// 右面 20,21,22,23
_verticesList.Add(new Vector3(0.5f, -0.5f, -0.5f));
_verticesList.Add(new Vector3(0.5f,-0.5f, 0.5f));
_verticesList.Add(new Vector3(0.5f, 0.5f, 0.5f));
_verticesList.Add(new Vector3(0.5f, 0.5f, -0.5f));
m.SetVertices(_verticesList);
// 前面
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(0,1));
_uvList.Add(new Vector2(1,1));
// 后面
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(1,1));
_uvList.Add(new Vector2(0,1));
// 上面
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(0,1));
_uvList.Add(new Vector2(1,1));
// 下面
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(1,1));
_uvList.Add(new Vector2(0,1));
// 左面
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(0,1));
_uvList.Add(new Vector2(1,1));
// 右面
_uvList.Add(new Vector2(0,0));
_uvList.Add(new Vector2(1,0));
_uvList.Add(new Vector2(1,1));
_uvList.Add(new Vector2(0,1));
m.SetUVs(0,_uvList);
// 前面
_triList.Add(0);
_triList.Add(1);
_triList.Add(2);
_triList.Add(0);
_triList.Add(2);
_triList.Add(3);
// 后面
_triList.Add(4);
_triList.Add(7);
_triList.Add(5);
_triList.Add(5);
_triList.Add(7);
_triList.Add(6);
// 上面
_triList.Add(8);
_triList.Add(9);
_triList.Add(10);
_triList.Add(8);
_triList.Add(10);
_triList.Add(11);
// 下面
_triList.Add(14);
_triList.Add(12);
_triList.Add(15);
_triList.Add(12);
_triList.Add(14);
_triList.Add(16);
// 左面
_triList.Add(16);
_triList.Add(17);
_triList.Add(18);
_triList.Add(16);
_triList.Add(18);
_triList.Add(19);
// 右面
_triList.Add(20);
_triList.Add(23);
_triList.Add(21);
_triList.Add(21);
_triList.Add(23);
_triList.Add(22);
m.SetTriangles(_triList,0);
return m;
}
}
}
运行结果如下图所示:
结果正确,nice!
(7) 总结
- 共用顶点的面,如果uv坐标不能共用的话,Unity中需要添加重复的顶点。
- 工欲善其事必先利其器。有了查看Mesh信息的工具,事半功倍。不容易出错,出了错也比较容易找到问题所在。
(8) 预告
接下来,将会给自定义的mesh贴上正确的mineCraft元素的贴图。
期间,会修改查看Mesh信息的工具,显示我们需要的信息。