最近在学习mesh, mesh的顶点,三角面,UV的一些属性
刚开始一直搞不懂三角面和顶点的关系,后来这篇文章给了很大的启发
有几点需要注意:
对于顶点 即 mesh.vertices 是由一个Vector3[]数组 里边记录了所有的顶点位置,注意 这里边所有的Vector3在数组里的index就是下标,这里边每一个下标都是用来构成三角形的 如下图
四个顶点分别为
V0(1, 1, 0),
V1(-1, 1, 0),
V2(1, -1, 0),
V3(-1, -1, 0)
注意:三角形的顶点顺序必须是顺时针,顺时针表示正面,逆时针表示背面,而unity3d在渲染时默认只渲染正面,背面是看不见的。
那么该三角形可以表示为:
mesh.triangles = new int[2 * 3]{0, 3, 1, 0, 2, 3};
这里是一面墙抠一个洞的情况
(暂时略过)
这里是一面墙抠2个以上的洞的情况
这是一种三角形拼接方法,单个图太大 我截图放上来 能看清楚就行
这种方式的弊端就是如果两个洞的高低不同 其三角形的排列是不同的
所以我决定使用下边这种方式
这种方式排列顶点,万变不离其宗 嘿嘿~
废话不多说 上代码
using UnityEngine;
public class MyMesh : MonoBehaviour {
public Material ma;
public Vector2[] uvs;
void Start ()
{
测试第二次不重复顶点();
}
public float 墙体高度 = 4;
public float 墙体长度 = 10;
/// <summary>
/// 门窗的位置和类型x为左侧位置 y为右侧位置 z为底部位置 w为顶部位置
/// </summary>
public Vector4[] 门窗;
public int factor;//UV缩放调整
/// <summary>
/// 根据新增门窗计算三角面和顶点数量
/// </summary>
void GetLength(out int san, out int ding)
{
san = 4; ding = 6;
if (门窗.Length == 0) return;
for (int i = 0; i < 门窗.Length; i++)
{
san += 8;
ding += 18;
}
}
void 测试第二次不重复顶点()
{
int nowSan = 0, nowDing = 0;//当前计算到的三角面和顶点
int san, ding;//三角面顶点总数
GetLength(out san, out ding);//计算下三角形数和顶点数
Mesh mesh = new Mesh();
MeshFilter filter = gameObject.AddComponent<MeshFilter>();
Vector3[] vertices = new Vector3[san];
int[] triangle = new int[ding];
Vector3 pos = this.transform.position;
//计算顶点和顶点排序
if (门窗.Length == 0)//没传门窗信息 则生成一个墙体
{
vertices[nowSan++] = new Vector3(pos.x, pos.y + 墙体高度, pos.z);
vertices[nowSan++] = pos;
vertices[nowSan++] = new Vector3(pos.x + 墙体长度, pos.y, pos.z);
vertices[nowSan++] = new Vector3(pos.x + 墙体长度, pos.y + 墙体高度, pos.z);
triangle = new int[2 * 3] { 3, 1,0, 1, 3, 2 };
}
else
{
//门窗数量大于1 先生成左侧两个
vertices[nowSan] = new Vector3(pos.x, pos.y + 墙体高度, pos.z);//0
vertices[nowSan+1] = pos;//1
vertices[nowSan+2] = new Vector3(pos.x + 门窗[0].x, pos.y, pos.z);//2
vertices[nowSan+3] = new Vector3(pos.x + 门窗[0].x, pos.y + 墙体高度, pos.z);//3
triangle[nowDing++] = 3; triangle[nowDing++] = 2; triangle[nowDing++] = 1;
triangle[nowDing++] = 1; triangle[nowDing++] = 0; triangle[nowDing++] = 3;
nowSan = 3;
for (int i = 0; i < 门窗.Length; i++)//再生成剩下的 循环赋值三角形和顶点信息
{
vertices[nowSan + 1] = new Vector3(pos.x + 门窗[i].y, pos.y, pos.z); //4 12
vertices[nowSan + 2] = new Vector3(pos.x + 门窗[i].y, pos.y + 门窗[i].z, pos.z); //5 13
vertices[nowSan + 3] = new Vector3(pos.x + 门窗[i].x, pos.y + 门窗[i].z, pos.z); //6 14
vertices[nowSan + 4] = new Vector3(pos.x + 门窗[i].x, pos.y + 门窗[i].w, pos.z); //7 15
vertices[nowSan + 5] = new Vector3(pos.x + 门窗[i].y, pos.y + 门窗[i].w, pos.z); //8 16
vertices[nowSan + 6] = new Vector3(pos.x + 门窗[i].y, pos.y + 墙体高度, pos.z); //9 17
vertices[nowSan + 7] = new Vector3(pos.x + ((i == 门窗.Length - 1) ? 墙体长度: 门窗[i+1].x) , pos.y+ 墙体高度, pos.z); //10 18
vertices[nowSan + 8] = new Vector3(pos.x + ((i == 门窗.Length - 1) ? 墙体长度: 门窗[i+1].x) , pos.y , pos.z); //11 19
//顶点顺序排序
triangle[nowDing++] = nowSan + (i == 0 ? -1 : 0); triangle[nowDing++] = nowSan + 2; triangle[nowDing++] = nowSan + 1;
triangle[nowDing++] = nowSan + (i == 0 ? -1 : 0); triangle[nowDing++] = nowSan + 3; triangle[nowDing++] = nowSan + 2;
triangle[nowDing++] = nowSan + 4; triangle[nowDing++] = nowSan + 6; triangle[nowDing++] = nowSan + 5;
triangle[nowDing++] = nowSan + 4; triangle[nowDing++] = nowSan + (i == 0 ? 0 : -1); triangle[nowDing++] = nowSan + 6;
triangle[nowDing++] = nowSan + 1; triangle[nowDing++] = nowSan + 6; triangle[nowDing++] = nowSan + 7;
triangle[nowDing++] = nowSan + 1; triangle[nowDing++] = nowSan + 7; triangle[nowDing++] = nowSan + 8;
nowSan += 8;
}
}
//UV计算
int iuv = 0, idx = 0;
Vector3[] uvv = new Vector3[san];
uvs = new Vector2[san];
uvv[0] = Vector3.zero;
for (int u = 1; u < san; u++)
uvv[u] = vertices[idx] - vertices[idx + u];
idx += 8;
uvs[iuv++] = Vector2.zero;
for (int u = 1; u < san; u++)
uvs[iuv++] = new Vector2(uvv[u].x, -uvv[u].y) * factor;
mesh.vertices = vertices;
mesh.triangles = triangle;
mesh.uv = uvs;
mesh.MarkDynamic();
mesh.RecalculateBounds();
mesh.RecalculateNormals();
MeshRenderer render = this.gameObject.AddComponent<MeshRenderer>();
render.material = ma;
filter.mesh = mesh;
}
}
效果图如下
可以看到 生成的三角面和定点顺序和计划生成的吻合
...无奈 竟然有人复制了我的博客....这里