先看效果
还未生成mesh时挖去圆柱的立方体
生成mesh后挖去圆柱的立方体
放代码为敬(脚本挂在空物体上即可):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class body : MonoBehaviour
{
//the outside radius must lager than the inside one
[Range(0, 100)] public float innerRadius;
[Range(1, 100)] public float outsideRadius;
[Range(1, 100)] public float outsideRadius1;
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<MeshFilter>();
GenerateMesh();
//show the order we generate the obj.
StartCoroutine(SequenceTest());
}
private void GenerateMesh()
{
//declare all the array we need
List<Vector3> vertices = new List<Vector3>();
List<Vector2> uvs = new List<Vector2>();
List<int> triangles = new List<int>();
//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<Vector3> 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<Vector3> vertices = new List<Vector3>();
//used to load the radius we have [Use Array to help us expand the plies]
float[] radiuses = { innerRadius, outsideRadius };
float[] radiuses1 = { innerRadius, outsideRadius1 };
//For now this code will generate the inner circle first
for (int i = 0; i < radiuses.Length; i++)
{
if (i == 0)
{
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);
}
}
int c = blockCounts / 4, k0 = c/2, k1 = 0, k2 = 0, k3 = 0, k4 = 0,k5 = 0; //c = 10,正方形一个边有10个点位
float deltaMeshdistance = radiuses1[1] / c; //deltaMeshdistance = 3,相邻点位的距离
if (i == 1)
{
if ((0.5 * c <= k0) && (k0 < c))
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
if ((0.5 * c <= k0) && (k0 < c))
{
Vector3 v1 = new Vector3(k5 * deltaMeshdistance, 0, radiuses1[i] / 2);
Vector3 v2 = new Vector3(k5 * deltaMeshdistance, height, radiuses1[i] / 2);
k0++;k5++;
Vector3 v3 = new Vector3(k5 * deltaMeshdistance, height, radiuses1[i] / 2);
Vector3 v4 = new Vector3(k5 * deltaMeshdistance, 0, radiuses1[i] / 2);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
}
if ((c <= k0) && (k0 < 2 * c))
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
if ((c <= k0) && (k0 < 2 * c))
{
Vector3 v1 = new Vector3(radiuses1[i] / 2, 0, radiuses1[i] / 2 - k1 * deltaMeshdistance);
Vector3 v2 = new Vector3(radiuses1[i] / 2, height, radiuses1[i] / 2 - k1 * deltaMeshdistance);
k0++; k1++;
Vector3 v3 = new Vector3(radiuses1[i] / 2, height, radiuses1[i] / 2 - k1 * deltaMeshdistance);
Vector3 v4 = new Vector3(radiuses1[i] / 2, 0, radiuses1[i] / 2 - k1 * deltaMeshdistance);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
}
if ((2 * c <= k0) && (k0 < 3 * c))
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
if ((2 * c <= k0) && (k0 < 3 * c))
{
Vector3 v1 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, 0, -radiuses1[i] / 2);
Vector3 v2 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, height, -radiuses1[i] / 2);
k0++;k2++;
Vector3 v3 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, height, -radiuses1[i] / 2);
Vector3 v4 = new Vector3(radiuses1[i] / 2 - k2 * deltaMeshdistance, 0, -radiuses1[i] / 2);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
}
if ((3 * c <= k0) && (k0 < 4 * c))
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
if ((3 * c <= k0) && (k0 < 4 * c))
{
Vector3 v1 = new Vector3(-radiuses1[i] / 2, 0, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
Vector3 v2 = new Vector3(-radiuses1[i] / 2, height, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
k0++;k3++;
Vector3 v3 = new Vector3(-radiuses1[i] / 2, height, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
Vector3 v4 = new Vector3(-radiuses1[i] / 2, 0, -radiuses1[i] / 2 + k3 * deltaMeshdistance);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
}
if ((4 * c <= k0) && (k0 < 4.5 * c))
{
for (int j = 0; j < blockCounts * 4; j += 4)
{
if ((4 * c <= k0) && (k0 < 4.5 * c))
{
Vector3 v1 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, 0, radiuses1[i] / 2);
Vector3 v2 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, height, radiuses1[i] / 2);
k0++;k4++;
Vector3 v3 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, height, radiuses1[i] / 2);
Vector3 v4 = new Vector3(-radiuses1[i] / 2 + k4 * deltaMeshdistance, 0, radiuses1[i] / 2);
vertices.Add(v1);
vertices.Add(v2);
vertices.Add(v3);
vertices.Add(v4);
}
}
}
}
}
return vertices;
}
/// <summary>
/// 填充三角形
/// </summary>
/// <param name="vertCount"></param>
/// <returns></returns>
private List<int> FillTriangles(int vertCount)
{
List<int> triangles = new List<int>();
//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 += 2, j += 2) //i < 160
{
if (i >= vertCount / 2 - 2) //i >= 156, vertCount = 320
{
triangles.AddRange(GetTriangleOrder(0, vertCount / 2, j, i)); //123, 341 填充顶部
triangles.AddRange(GetTriangleOrder(i + 1, j + 1, vertCount / 2 + 1, 1)); //填充底部
//triangles.AddRange(GetTriangleOrder(1, 161, 318, 158)); //123, 341 填充顶部
//triangles.AddRange(GetTriangleOrder(159, 319, 160, 0)); //填充底部
}
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<int> 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<int> output = new List<int>();
//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;
}
/// <summary>
/// 协程,网格生成过程
/// </summary>
/// <returns></returns>
IEnumerator SequenceTest()
{
float interval = 0.01f;
Debug.Log(meshFilter.mesh.triangles.Length);
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);
}
}
}
我这里用到了协程,可以看到网格的生成过程,如果想直接看到结果,改动如下:
将第27行的
StartCoroutine(SequenceTest());
改为
SequenceTest();
再将SequenceTest()函数前的IEnumerator换为 private void
删除所有yield行的代码即可
在代码中
innerRadius为圆的半径,可以自行设定
blockCounts为切割的份数,数量越大消耗的电脑性能越多
height为高度,可以自行设定
increment为圆的角度增量
网格的生成顺序如下图红色箭头所示: