Unity3D之Mesh(七)绘制长方体
发表于2018-11-19
前面的内容给大家介绍的都是平面的模型mesh,下面这篇就来介绍一些复杂的,动态创建三维立体模型mesh,首先还是从长方体来着手。
一、基本思路
由于是创建长方体mesh,由之前的研究得知,两个数据必须要有,即:顶点的数据:vertices与索引的三角形(即负责管理每个三角形的三点的索引顺序):triangles。长方体:一般会得知:长宽高;即今天我们由长宽高为参数得到vertices与triangles。
二、基本程序框架
创建一个empty的gameobject,挂在脚本。
由基本思路可得基本框架,之后,实现函数功能即可;
using UnityEngine; [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))] public class cube_mesh : MonoBehaviour { public float Length = 5; //长方体的长 public float Width = 6; //长方体的宽 public float Heigth = 7; //长方体的高 private MeshFilter meshFilter; void Start() { meshFilter = GetComponent<MeshFilter>(); meshFilter.mesh = CreateMesh(Length, Width, Heigth); } Mesh CreateMesh(float length, float width, float heigth) { //vertices(顶点、必须): //......... //triangles(索引三角形、必须): //......... //uv: //......... //负载属性与mesh Mesh mesh = new Mesh(); //......... return mesh; } }
三、绘制函数的实现以及整个程序代码
using UnityEngine; [RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))] public class cube_mesh : MonoBehaviour { public float Length = 5; //长方体的长 public float Width = 6; //长方体的宽 public float Heigth = 7; //长方体的高 private MeshFilter meshFilter; void Start() { meshFilter = GetComponent<MeshFilter>(); meshFilter.mesh = CreateMesh(Length, Width, Heigth); } Mesh CreateMesh(float length, float width, float heigth) { //vertices(顶点、必须): int vertices_count = 4*6; //顶点数(每个面4个点,六个面) Vector3[] vertices = new Vector3[vertices_count]; vertices[0] = new Vector3(0, 0, 0); //前面的左下角的点 vertices[1] = new Vector3(0, heigth, 0); //前面的左上角的点 vertices[2] = new Vector3(length, 0, 0); //前面的右下角的点 vertices[3] = new Vector3(length, heigth, 0); //前面的右上角的点 vertices[4] = new Vector3(length, 0, width); //后面的右下角的点 vertices[5] = new Vector3(length, heigth, width); //后面的右上角的点 vertices[6] = new Vector3(0, 0, width); //后面的左下角的点 vertices[7] = new Vector3(0, heigth, width); //后面的左上角的点 vertices[8] = vertices[6]; //左 vertices[9] = vertices[7]; vertices[10] = vertices[0]; vertices[11] = vertices[1]; vertices[12] = vertices[2]; //右 vertices[13] = vertices[3]; vertices[14] = vertices[4]; vertices[15] = vertices[5]; vertices[16] = vertices[1]; //上 vertices[17] = vertices[7]; vertices[18] = vertices[3]; vertices[19] = vertices[5]; vertices[20] = vertices[2]; //下 vertices[21] = vertices[4]; vertices[22] = vertices[0]; vertices[23] = vertices[6]; //triangles(索引三角形、必须): int 分割三角形数 = 6 * 2; int triangles_cout = 分割三角形数 * 3; //索引三角形的索引点个数 int[] triangles = new int [triangles_cout]; //索引三角形数组 for(int i=0,vi=0;i< triangles_cout;i+=6,vi+=4) { triangles[i] = vi; triangles[i+1] = vi+1; triangles[i+2] = vi+2; triangles[i+3] = vi+3; triangles[i+4] = vi+2; triangles[i+5] = vi+1; } //uv: //......... //负载属性与mesh Mesh mesh = new Mesh(); mesh.vertices = vertices; mesh.triangles = triangles; return mesh; } }
四、效果图
五、其他相关的说明
1、冗余的顶点坐标
正方体6个面,每个面由2个三角形组成,所以共需要36个三角形顶点索引。但是正方体只有8个顶点,为什么需要24个顶点坐标数据呢?
答案是:Unity3D的Mesh.triangles是三角形索引数组,不仅依靠这个索引值索引三角形顶点坐标,而且索引纹理坐标,索引法线向量。即正方体的每个顶点都参与了3个平面,而这3个平面的法线向量是不同的,该顶点在渲染这3个平面的时候需要索引到不同的法线向量。而由于顶点坐标和法线向量是由同一个索引值triangles[Index]取得的,例如,根据vertices[0],vertices[10],vertices[22]在vertices中索引到的顶点都为(0,0,0),但是在normals中索引到的法向量值各不相同。这就决定了在正方体中一个顶点,需要有3份存储。(如果你需要创建其它模型,需要根据实际情况决定顶点坐标的冗余度。实质上顶点坐标的冗余正是方便了法线坐标、纹理坐标的存取。)
2、三角形的渲染
准则:三角形有两面,正面可见,背面不可见。三角形的渲染顺序与三角形的正面法线呈左手螺旋定则。
这就决定了,如果我们需要渲染如下一个正方形面,那么就需要保证组成这个正方形的两个小三角形的正面法线都是指向屏幕外的。
程序中的顶点顺序为,三角形1: 0--->1--->2,三角形2:3--->2--->1 。