什么是Mesh?
Mesh是指的模型的网格,3D模型是由多边形拼接而成,而多边形实际上又是由多个三角形拼接而成的。即一个3D模型的表面其实是由多个彼此相连的三角面构成。三维空间中,构成这些三角形的点和边的集合就是Mesh。
原理
即动态创建一个Mesh,设置三角形和顶点数据,然后赋值给MeshFilter(增加mesh属性),通过MeshRenderer(增加材质并渲染出Mesh)绘制出来
Mesh的组成部分
1.vertices(顶点数据数组Vector3[])
2.triangles(三角形顶点索引数组,int[])
3.normals(法线向量数组,Vector3[])
4.uv(纹理坐标数组,Vector2[])
顶点坐标:顶点坐标数组存放Mesh的每个顶点的空间坐标,假设某mesh有n个顶点,则vertex的size为n
法线:法线数组存放mesh每个顶点的法线,大小与顶点坐标对应,normal[i]对应顶点vertex[i]的法线
纹理坐标:它定义了图片上每个点的位置的信息. 这些点与3D模型是相互联系的, 以决定表面纹理贴图的位置. UV就是将图像上每一个点精确对应到模型物体的表面. uv[i]对应vertex[i]
三角形序列:每个mesh都由多个三角面组成,而三角面的三个点就是顶点坐标里的点,三角形的数组的size = 三角形个数 * 3
创建一个立方体
1.定顶点坐标
一般我们会以立方体几何中心为坐标原点。
代码:
1 //顶点数组 2 Vector3[] _vertices = 3 { 4 // front 5 new Vector3(-5.0f, 10.0f, -5.0f), 6 new Vector3(-5.0f, 0.0f, -5.0f), 7 new Vector3(5.0f, 0.0f, -5.0f), 8 new Vector3(5.0f, 10.0f, -5.0f), 9 10 11 // left 12 new Vector3(-5.0f, 10.0f, -5.0f), 13 new Vector3(-5.0f, 0.0f, -5.0f), 14 new Vector3(-5.0f, 0.0f, 5.0f),// 15 new Vector3(-5.0f, 10.0f, 5.0f), 16 17 // back 18 new Vector3(-5.0f, 10.0f, 5.0f), 19 new Vector3(-5.0f, 0.0f, 5.0f), 20 new Vector3(5.0f, 0.0f, 5.0f), 21 new Vector3(5.0f, 10.0f, 5.0f), 22 23 24 // right 25 new Vector3(5.0f, 10.0f, 5.0f), 26 new Vector3(5.0f, 0.0f, 5.0f), 27 new Vector3(5.0f, 0.0f, -5.0f), 28 new Vector3(5.0f, 10.0f, -5.0f), 29 30 31 // Top 32 new Vector3(-5.0f, 10.0f, 5.0f), 33 new Vector3(5.0f, 10.0f, 5.0f), 34 new Vector3(5.0f, 10.0f, -5.0f), 35 new Vector3(-5.0f, 10.0f, -5.0f), 36 37 // Bottom 38 new Vector3(-5.0f, 0.0f, 5.0f), 39 new Vector3(5.0f, 0.0f, 5.0f), 40 new Vector3(5.0f, 0.0f, -5.0f), 41 new Vector3(-5.0f, 0.0f, -5.0f), 42 43 };
这里有人会有疑问,立方体不是八个顶点吗,哪来这么多顶点,考虑一下一个面4个角,一共6个面,24个,是的,8个顶点也可以勾勒出来,但是这里考虑贴图效果,一般不共点。还有就是Unity中是左手坐标系,一定记好,因为在绘制三角面时很重要。
2.三角面索引
//索引数组 int[] _triangles = { //front 2,1,0, 0,3,2, //left 4,5,6, 4,6,7, //back 9,11,8, 9,10,11, //right 12,13,14, 12,14,15, ////up //16,17,18, //16,18,19, ////buttom //21,23,22, //21,20,23, //不可跳跃设置索引值(否则会提示一些索引超出边界顶点 15直接20不可,要连续15-16) 17,19,18, 17,16,19, };
这里设置的原则时外面被渲染里面剔除掉,顺时针构建(注意里外面的区别),还要注意的一个点,如上所写,比如我想生成5个面,那你的索引值也要是连续的,不可16直接蹦到20。这里立法体面的绘制顺序是(即绘制三角面的面与上面顶点顺序要一致)设置顶点的顺序
3.UV坐标
代码:
1 //UV数组 2 Vector2[] uvs = 3 { 4 // Front 5 new Vector2(1.0f, 0.0f), 6 new Vector2(1.0f, 1.0f), 7 new Vector2(1.0f, 0.0f), 8 new Vector2(0.0f, 0.0f), 9 10 11 // Left 12 new Vector2(1.0f, 1.0f), 13 new Vector2(0.0f, 1.0f), 14 new Vector2(0.0f, 0.0f), 15 new Vector2(1.0f, 0.0f), 16 17 18 // Back 19 new Vector2(1.0f, 0.0f), 20 new Vector2(1.0f, 1.0f), 21 new Vector2(1.0f, 0.0f), 22 new Vector2(0.0f, 0.0f), 23 24 25 // Right 26 new Vector2(1.0f, 1.0f), 27 new Vector2(0.0f, 1.0f), 28 new Vector2(0.0f, 0.0f), 29 new Vector2(1.0f, 0.0f), 30 31 //// Top 32 //new Vector2(0.0f, 0.0f), 33 //new Vector2(1.0f, 0.0f), 34 //new Vector2(1.0f, 1.0f), 35 //new Vector2(0.0f, 1.0f), 36 37 38 // Bottom 39 new Vector2(0.0f, 0.0f), 40 new Vector2(1.0f, 0.0f), 41 new Vector2(1.0f, 1.0f), 42 new Vector2(0.0f, 1.0f), 43 44 };
UV坐标从左上角开始(想象摄像机在立方体内部去判断),
1 Mesh mesh = new Mesh() 2 { 3 vertices = _vertices, 4 uv = uvs, 5 triangles = _triangles, 6 }; 7 8 //重新计算网格的法线 9 //在修改完顶点后,通常会更新法线来反映新的变化。法线是根据共享的顶点计算出来的。 10 //导入到网格有时不共享所有的顶点。例如:一个顶点在一个纹理坐标的接缝处将会被分成两个顶点。 11 //因此这个RecalculateNormals函数将会在纹理坐标接缝处创建一个不光滑的法线。 12 //RecalculateNormals不会自动产生切线,因此bumpmap着色器在调用RecalculateNormals之后不会工作。然而你可以提取你自己的切线。 13 mesh.RecalculateNormals();
给mesh属性赋值。
5.增加MeshFilter组件,网格过滤。以及增加MeshRenderer组件添加材质实现渲染。OK!!!到这基本已经绘制完了,Mesh已经出来了。
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class ShaderBase : MonoBehaviour 6 { 7 8 void Start() 9 { 10 GameObject gameObject = new GameObject("Cube"); 11 gameObject.transform.position = Vector3.zero; 12 13 //顶点数组 14 Vector3[] _vertices = 15 { 16 // front 17 new Vector3(-5.0f, 10.0f, -5.0f), 18 new Vector3(-5.0f, 0.0f, -5.0f), 19 new Vector3(5.0f, 0.0f, -5.0f), 20 new Vector3(5.0f, 10.0f, -5.0f), 21 22 23 // left 24 new Vector3(-5.0f, 10.0f, -5.0f), 25 new Vector3(-5.0f, 0.0f, -5.0f), 26 new Vector3(-5.0f, 0.0f, 5.0f),// 27 new Vector3(-5.0f, 10.0f, 5.0f), 28 29 // back 30 new Vector3(-5.0f, 10.0f, 5.0f), 31 new Vector3(-5.0f, 0.0f, 5.0f), 32 new Vector3(5.0f, 0.0f, 5.0f), 33 new Vector3(5.0f, 10.0f, 5.0f), 34 35 36 // right 37 new Vector3(5.0f, 10.0f, 5.0f), 38 new Vector3(5.0f, 0.0f, 5.0f), 39 new Vector3(5.0f, 0.0f, -5.0f), 40 new Vector3(5.0f, 10.0f, -5.0f), 41 42 43 // Top 44 new Vector3(-5.0f, 10.0f, 5.0f), 45 new Vector3(5.0f, 10.0f, 5.0f), 46 new Vector3(5.0f, 10.0f, -5.0f), 47 new Vector3(-5.0f, 10.0f, -5.0f), 48 49 // Bottom 50 new Vector3(-5.0f, 0.0f, 5.0f), 51 new Vector3(5.0f, 0.0f, 5.0f), 52 new Vector3(5.0f, 0.0f, -5.0f), 53 new Vector3(-5.0f, 0.0f, -5.0f), 54 55 }; 56 //索引数组 57 int[] _triangles = 58 { 59 //front 60 2,1,0, 61 0,3,2, 62 //left 63 4,5,6, 64 4,6,7, 65 //back 66 9,11,8, 67 9,10,11, 68 //right 69 12,13,14, 70 12,14,15, 71 ////up 72 //16,17,18, 73 //16,18,19, 74 ////buttom 75 //21,23,22, 76 //21,20,23, 77 78 //不可跳跃设置索引值(否则会提示一些索引超出边界顶点 15直接20不可,要连续15-16) 79 17,19,18, 80 17,16,19, 81 }; 82 83 //UV数组 84 Vector2[] uvs = 85 { 86 // Front 87 new Vector2(1.0f, 0.0f), 88 new Vector2(1.0f, 1.0f), 89 new Vector2(1.0f, 0.0f), 90 new Vector2(0.0f, 0.0f), 91 92 93 // Left 94 new Vector2(1.0f, 1.0f), 95 new Vector2(0.0f, 1.0f), 96 new Vector2(0.0f, 0.0f), 97 new Vector2(1.0f, 0.0f), 98 99 100 // Back 101 new Vector2(1.0f, 0.0f), 102 new Vector2(1.0f, 1.0f), 103 new Vector2(1.0f, 0.0f), 104 new Vector2(0.0f, 0.0f), 105 106 107 // Right 108 new Vector2(1.0f, 1.0f), 109 new Vector2(0.0f, 1.0f), 110 new Vector2(0.0f, 0.0f), 111 new Vector2(1.0f, 0.0f), 112 113 //// Top 114 //new Vector2(0.0f, 0.0f), 115 //new Vector2(1.0f, 0.0f), 116 //new Vector2(1.0f, 1.0f), 117 //new Vector2(0.0f, 1.0f), 118 119 120 // Bottom 121 new Vector2(0.0f, 0.0f), 122 new Vector2(1.0f, 0.0f), 123 new Vector2(1.0f, 1.0f), 124 new Vector2(0.0f, 1.0f), 125 126 }; 127 128 Mesh mesh = new Mesh() 129 { 130 vertices = _vertices, 131 uv = uvs, 132 triangles = _triangles, 133 }; 134 135 //重新计算网格的法线 136 //在修改完顶点后,通常会更新法线来反映新的变化。法线是根据共享的顶点计算出来的。 137 //导入到网格有时不共享所有的顶点。例如:一个顶点在一个纹理坐标的接缝处将会被分成两个顶点。 138 //因此这个RecalculateNormals函数将会在纹理坐标接缝处创建一个不光滑的法线。 139 //RecalculateNormals不会自动产生切线,因此bumpmap着色器在调用RecalculateNormals之后不会工作。然而你可以提取你自己的切线。 140 mesh.RecalculateNormals(); 141 gameObject.AddComponent<MeshFilter>().mesh=mesh; 142 //Material/New Material 1 143 gameObject.AddComponent<MeshRenderer>().material = Resources.Load<Material>("Material/New Material"); 144 145 } 146 147 }