这篇我来讲一下rectangle长方形拓扑网格的创建,大部分时候,3d图形引擎提供的基础立体网格并不能完全达到我们学习的要求,就比如unity,我需要一个拓扑信息完好的rectangle长方形就没法提供了,此时我们只能使用图形api来代码创建一个。
首先我来解释一下mesh所包含的信息,也就是Vertices,Triangles,以及uvs,什么意思呢?看下图:
上图中正方形假设是我们要创建的mesh网格,那么我们创建这个网格,首先要知道四个顶点的坐标,也就是vertices,其次我们还要知道拓扑信息,也就是节点(或者说坐标点)之间的关联信息,比如图形学中网格三角面的三个顶点的逆时针顺时针拓扑信息,这个正方形网格包含两个三角面,那么三角面的拓扑信息就是(012),(023),这就是triangles。最后如果这个网格要承载一张贴图,那么贴图的每个顶点对应的网格的顶点是怎么样的呢?这个也就是uvs所记录的信息。
所以说一个网格需要包含着三种信息才能在图形程序中使用。那么unity要创建一个这种正方形具体怎么办呢?代码如下:
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
-
public
class
MeshSquare :
MonoBehaviour
-
{
-
private Mesh mMesh;
-
-
void Start()
-
{
-
mMesh =
new Mesh();
-
Vector3[] vertices =
new Vector3[
4] {
-
new Vector3(
0,
0,
0),
-
new Vector3(
1,
0,
0),
-
new Vector3(
1,
0,
1),
-
new Vector3(
0,
0,
1)
-
};
-
int[] triangles =
new
int[
6] {
-
0,
1,
2,
-
0,
2,
3
-
};
-
Vector2[] uvs =
new Vector2[
4]
-
{
-
new Vector3(
0,
0),
-
new Vector3(
1,
0),
-
new Vector3(
0,
1),
-
new Vector3(
1,
1),
-
};
-
mMesh.vertices = vertices;
-
mMesh.triangles = triangles;
-
mMesh.uv = uvs;
-
GetComponent<MeshFilter>().sharedMesh = mMesh;
-
}
-
-
}
可以看得出代码就是上面讲的正方形创建方法,效果就是这样的:
绑定meshfilter和meshrenderer以及材质球后就能得到一个正方形了。
可惜啊可惜,实际上我们写图形程序中需要的大部分时候都是长方形,而不是这么规范的正方形,比如这个矩阵论书籍的封面就是600*820分辨率的,那么其实我们只需要修改vertices中的网格点坐标就达到目的了,比如这样:
改下顶点坐标就达到目的了。实际上这种方式在我们图形学计算中会导致很多问题,因为这种网格不是单位化的,也就是说网格的长宽比例不同,如果我们要是想用无数个单位正方形组成长方形该怎么办呢?下面我描绘一下长方形的拓扑信息,如下图:
这里我没有标明坐标和uv信息,因为坐标和uv只需要通过坐标系的xy进行for循环计算就得到了,可以根据需要任意轴向的正负计算,所以这里我只标明了长方形网格的拓扑三角信息,比如这时候就是(0,4,5),(0,5,1),(1,5,6),(1,6,2)...,这时候我们就来写程序吧,如下图:
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
-
[
ExecuteInEditMode]
-
public
class
MeshRectangle :
MonoBehaviour {
-
-
public
bool Refresh =
false;
-
[
SerializeField]
public
int xCount =
60;
//单位方块x轴数量
-
[
SerializeField]
public
int yCount =
82;
//单位方块y轴数量
-
-
private
float mCellLen =
0.1f;
//单位小方块边长
-
-
private Mesh mMesh;
-
-
void Start()
-
{
-
CreateMesh();
-
}
-
-
void Update()
-
{
-
if (Refresh)
-
{
-
CreateMesh();
-
Refresh =
false;
-
}
-
}
-
-
private void CreateMesh()
-
{
-
//构建一个任意单位长宽的长方形
-
mMesh =
new Mesh();
-
int xPointCount = xCount +
1;
//x轴网格点数量
-
int yPointCount = yCount +
1;
//y轴网格点数量
-
int xyMeshPointCount = xPointCount * yPointCount;
//网格顶点的数量
-
int triangleCount = xCount * yCount *
2;
//三角面数量(小正方形的两倍)
-
//构建mesh网格的所有信息数组
-
Vector3[] vertices =
new Vector3[xyMeshPointCount];
-
int[] triangles =
new
int[triangleCount *
3];
-
Vector2[] uvs =
new Vector2[xyMeshPointCount];
-
//记录拓扑信息循环的间隔
-
int triangleIndex =
0;
-
for (
int x =
0; x < xPointCount; x++)
-
{
-
for (
int y =
0; y < yPointCount; y++)
-
{
-
int index = x + y * xPointCount;
-
vertices[index] =
new Vector3((xCount - x) * mCellLen,
0, (yCount - y) * mCellLen);
-
-
if (x < xCount && y < yCount)
-
{
-
//这里就是拓扑信息的循环计算,结合绘画的拓扑信息图算一下
-
triangles[triangleIndex] = x + y * xPointCount;
-
triangles[triangleIndex +
1] = x + (y +
1) * xPointCount;
-
triangles[triangleIndex +
2] = x + (y +
1) * xPointCount +
1;
-
-
triangles[triangleIndex +
3] = x + y * xPointCount;
-
triangles[triangleIndex +
4] = x + (y +
1) * xPointCount +
1;
-
triangles[triangleIndex +
5] = x + y * xPointCount +
1;
-
-
triangleIndex +=
6;
-
}
-
uvs[index] =
new Vector2((
float)x / (
float)xCount, (
float)y / (
float)yCount);
-
}
-
}
-
-
mMesh.vertices = vertices;
-
mMesh.triangles = triangles;
-
mMesh.uv = uvs;
-
GetComponent<MeshFilter>().sharedMesh = mMesh;
-
}
-
-
}
看下实际运行效果,如下图:
我们按照60:82的宽高比来绘制网格,这样矩阵论的封面网格就匹配了,顺便看下我们生成的网格,如下图:
生成的网格数量和三角面以及uv都是符合我们需求的。这种网格生成方式我们以后会用来制作计算机图形程序,如果没有这种需求,那么就按照我最开始生成四个顶点的网格方式生成节省资源会更好。