第七章:网格
在接下来的好几章内,我们来玩水。
7 如何产生Mesh?
我们在Unity中看到的所有3D形状都是由mesh构成的。那么如何产生一个mesh?大概分成两步:产生mesh数据和将mesh数据渲染出来。前者由cpu帮你操作后者由gpu帮你操作。
如果你没有看过前面几章的gpu渲染流程,这边建议是你回顾一下,那样比较好。
7.1 生成mesh数据
如果你有一点的opengl或者directx基础(固定管线基础或者渲染管线<着色器>基础)那你就会知道,一个三角面的基本成分:
1.顶点数据
2.索引数据
3.uv(和显示的颜色有关)
7.1.1 顶点数据:
顶点数据其实很容易理解,它就是一组x,y,z的点。ok,现在提问,一个三角面有几个顶点?
答案是3个。
一个四边形呢?
答案是4个。
7.1.2 索引数据
你有顶点数据了,你就能画一个三角面吗?不,如果是你的话,你就连一条线,让它看起来像。但是,计算机不知道。gpu不知道。
opengl或者d3d对这个过程做了一个简单的封装。也就是说你可以通过传递一个索引顺序的数组,通知gpu这样画。当然,这个顺序是由你来确定的。
为了简单一点,我么你先画一个三角面。如图7-1所示。
来看一下mesh数据
7.1.3 uv
现在我们来思考一个新的问题。我们往往会有一些新的想法,比如给一个mesh画上一个软萌妹子。怎么操作?我们可以这样做:
1.我们创建一个新的shader文件t
2.我们给t定义一个2D类型的纹理文件
3.我们引用这个纹理文件(用CG变量)
4.我们通过片元着色器将这个2D的纹理文件以变换到UV坐标,然后将变换后的数据贴到这个mesh上面去。
这个过程就能够处理上述需求。那么这里面的uv,就是一个新的坐标系,就是我给mesh定义的一个用来贴图的坐标系。
你可以创建一个纹理,比如一张萌妹:在unity里面纹理采样时的默认坐标系如图7-3所示。
然后他做了一个什么操作呢?它计算得到这个纹理在你定义的uv坐标系的对应的块的像素,然后将该像素绘制到mesh上面去就像图7-4这种。
值得注意的是,通常情况下,uv都是一个长度为4的数组,因为你的图形是2d的是有长宽的是有4个角哒!
7.2 指定mesh
这一步就相当简单了,见图7-5吧
7.3 源码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleMesh : MonoBehaviour
{
public MeshFilter meshFilter;
void Start()
{
Mesh mesh = createMesh();
meshFilter.mesh = mesh;
}
Mesh createMesh()
{
Mesh mesh = new Mesh();
Vector3[] v3s = new Vector3[4];
v3s[0] = new Vector3(0, 0, 0);
v3s[1] = new Vector3(0, 1, 0);
v3s[2] = new Vector3(1, 0, 0);
mesh.vertices = v3s;
int[] index = new int[12];
index[0] = 0;
index[1] = 1;
index[2] = 2;
mesh.triangles = index;
Vector2[] uvs = new Vector2[3];
uvs[0] = new Vector2(0, 0);
uvs[1] = new Vector2(1, 0);
uvs[2] = new Vector2(0, 1);
mesh.uv = uvs;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
return mesh;
}
}
7.4 使用