本篇文章主要介绍了利用Unity中的mesh 实时生成圆环的过程以及思想,我会在开头直接放出源码。如若有任何疑问,可向后继续观看详细解说~~~
(PSPSPS:Mesh生成的顺序,方式等有很多,当前代码中部分逻辑若不理解,可自行推导一下圆的方程,即可得出解答 //顺带说一下,代码中的英文是我锻炼英文用的。。。。遇见语法错误不准笑……)
首先 放上效果图:
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter) , typeof(MeshRenderer))]
public class CylinderGenerateScript : MonoBehaviour {
//the outside radius must lager than the inside one
[Range(0, 100)] public float innerRadius;
[Range(1, 100)] public float outsideRadius;
public int blockCounts = 80; //how many blocks that the obj will be split into?
public float height = 10; //the height of the obj.
private float increment;
private float currentAngle = 0;
private MeshFilter meshFilter;
void Start () {
meshFilter = transform.GetComponent();
GenerateMesh();
//show the order we generate the obj.
StartCoroutine(SequenceTest());
}
private void GenerateMesh()
{
//declare all the array we need
List vertices = new List();
List uvs = new List();
List triangles = new List();
//initialize the parameters
increment = 2 * Mathf.PI / blockCounts;
//Generate the vertex we need
vertices = GenerateVertics();
//Fill the triangles in order
triangles = FillTriangles(vertices.Count);
meshFilter.mesh.vertices = vertices.ToArray();
meshFilter.mesh.triangles = triangles.ToArray();
}
private List GenerateVertics()
{
//The order to Generate the vertics : choose the left bottom as the first point, and assign the id by clockwise, inside circle generate first
//顶点标号顺序 : 以左下角为起点,以顺时针顺序给各顶点标号,从内层圆环开始
List vertices = new List();
//used to load the radius we have [Use Array to help us expand the plies]
float[] radiuses = {innerRadius , outsideRadius };
//For now this code will generate the inner circle first
for (int i = 0; i < radiuses.Length; i++)
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
//TODO : for now ,this script will generate 4 more vertices
Vector3 v1 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), 0, radiuses[i] * Mathf.Cos(currentAngle));
Vector3 v2 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), height, radiuses[i] * Mathf.Cos(currentAngle));
//Generate next two vertices
currentAngle += increment;
Vector3 v3 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), height , radiuses[i] * Mathf.Cos(currentAngle));
Vector3 v4 = new Vector3(radiuses[i] * Mathf.Sin(currentAngle), 0 , radiuses[i] * Mathf.Cos(currentAngle));
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
return vertices;
}
private List FillTriangles( int vertCount )
{
List triangles = new List();
//1.fill the inner && outside surface
for (int i = 0; i < vertCount - 2; i+=2)
{
if (i == vertCount - 2 || i == vertCount - 1) //connect with the origin points
{
triangles.AddRange(GetTriangleOrder(i , i + 1 , i - (blockCounts - 2) , i - (blockCounts - 3)));
}
else if(i < vertCount / 2)
{
//inner circle only needs to see the inside surface
triangles.AddRange(GetTriangleOrder(i, i + 1, i + 2 , i + 3));
}
else
{
//outside surface
triangles.AddRange(GetTriangleOrder(i + 3, i + 2, i + 1, i));
}
}
//2.fill the top && bottom surface
for (int i = 0 , j = vertCount/2 ; i < vertCount/2; i+=4 , j+=4)
{
if(i >= vertCount/2 - 2)
{
triangles.AddRange(GetTriangleOrder(0, vertCount/2 , j , i));
triangles.AddRange(GetTriangleOrder(i + 1, j + 1, vertCount / 2 + 1, 1));
}
else
{
triangles.AddRange(GetTriangleOrder(i + 3, j + 3, j , i ));
triangles.AddRange(GetTriangleOrder(i + 1, j + 1, j + 2, i + 2));
}
}
return triangles;
}
private List GetTriangleOrder(int p1 , int p2 , int p3 , int p4) //the input must be from the left bottom corner && sort by clockwise
{
//use this code to return a particular order
List output = new List();
//Add first triangle
output.Add(p1);
output.Add(p2);
output.Add(p3);
//Add the second one
output.Add(p3);
output.Add(p4);
output.Add(p1);
return output;
}
IEnumerator SequenceTest()
{
float interval = 0.01f;
for (int i = 0; i < meshFilter.mesh.triangles.Length; i += 3)
{
Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 1]], Color.red, 100f);
yield return new WaitForSeconds(interval);
Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 1]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 2]], Color.yellow, 100f);
yield return new WaitForSeconds(interval);
Debug.DrawLine(meshFilter.mesh.vertices[meshFilter.mesh.triangles[i + 2]], meshFilter.mesh.vertices[meshFilter.mesh.triangles[i]], Color.blue, 100f);
yield return new WaitForSeconds(interval);
}
}
}
Mesh的生成过程说白了就是生成点,然后再将各点连接成为一个个的小三角形的过程,以上的代码也都是基于这个思想的。
在Mesh的生成过程中,先说一些基本的东西:
vertices :mesh中的顶点集,mesh所有的顶点位置信息都存储在这里,其类型为vertex。
triangles : mesh中存储连接顺序的集合,在mesh生成中,unity会依照此集合中的标号依次连接vertices中的顶点,在Unity中,由于mesh都是由一个个的小三角形组成的,因此,这个集合使用时将是每三个顶点号为一组,然后以此往复向后。(请注意在给triangles 赋值时,标号一定不要超过vertices中记录的标号,否则会导致错误出现。)
uvs :mesh中存储材质的集合,类型为vector3的数组,这个数组提供的参数将会用于贴图在物体表面的匹配。
解说在此解说在此解说在此::::::
innerRadius,outsideRadius:内层以及外层环形的半径,内层圆半径请勿大于外层,本文代码中,并未提供判断此项的方法。
blockCounts :规定圆环会被划分为多少份来生成,此项越小,环形的边界也会相应的慢慢变为多边形的样子,同时,此项不宜过大,否则生成的效果一样,但是需要花费更多的CPU资源来生成,请自行斟酌。
height : 规定生成的圆环的高度。
increment :划分这么多份,每一份的角度。后面生成各个点时,需要用到。
其余的~~~~~~~~~~~~~~~~~~:略!
角度计算:在这里,我们首先要求出分了这么多块,每一块的角度,也就是基本的圆的公式:2 * PI / blockCounts , 算出这个值以后,我们通过GenerateVertics函数就可以开始生成顶点信息了,
顶点生成:我这里采用的是先生成内层顶点,然后依次向外延伸,生成外层顶点的顺序,在自己生成顶点时请注意,一定要记好自己生成顶点的顺序,否则后面填充triangles数组时会产生混乱。
各边连接(填充triangles):这里就是连接各个顶点的过程,一般情况下,一个小的面(四边形)需要填充两个三角形,这也就意味着我们每四个顶点,要互相连接,形成两个三角形。(PSPSPS:大写的强调:三角形不可重叠 &&& 三角形的连接顺序为你所需要看见的面的方向的顺时针,否则是看不见的。当然你可以将顺时针和逆时针都加进去,这样可以做到双面可见)
这里是用了一个协程操作,来向我们一步一步的展示了这个三角形的具体生成过程,这一小段代码取自这里这里这里。
到这里也就没什么了,其实主要就是计算顶点,以及判断生成顺序的一个问题而已~~,希望大家喜欢~~
本帅哥乃小白界中的一员,难免有错,发现的话,请评论啥玩意的~~大家一起学习啊~~~