3D模型一般是由网格(Mesh)和纹理(Texture)两部分构成。那什么是网格?从概念上讲,网格是图形硬件用来绘制复杂内容的结构。它至少包含一组基于三维空间点的顶点,以及一组连接这些点的三角形(最基本的2D形状)。而网格是由这些三角形(直角等腰三角形)构成的表面。那什么又是纹理?纹理是应用于3D模型表面的图像,用于增加模型的细节和真实感。纹理可以是物体表面的图案、颜色或材质效果,如木材的纹理、皮肤的质感等。纹理映射(Texture Mapping)是将纹理图像映射到3D模型表面的过程,通过这个过程,可以使模型看起来更加逼真。
在Unity中我们制作3D游戏时,需要各种各样的模型,你可以选择用3DMax、Maya等建好模型后导入Unity,也可以选择在Unity中用代码程序化生成网格,然后再加上各种细节,从而生成模型。比如程序化生成地型等。下面我们会用Perlin噪声图去生成山洞地型。
1. 绘制三角形
要绘制网格,我们需要一个也具有MeshFilter和MeshRenderer组件的游戏对象。我们可以强制将这些组件添加到同一游戏对象中,方法是为其赋予RequireComponent具有两种组件类型作为参数的属性。
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class CreateMesh : MonoBehaviour{
}
Mesh包含但不限于:
- 顶点坐标数组
- 三角形顶点顺序的索引数组
- 顶点在UV坐标系中的位置信息
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class DrawTriangle : MonoBehaviour
{
private Mesh mesh;
private Vector3[] vertices;//顶点坐标数组
private int[] triangles;//三角形顶点绘制顺序数组
private void Start()
{
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
vertices = new Vector3[]
{
Vector3.zero, Vector3.right, Vector3.up,
};
triangles = new int[]
{
0, 1, 2
};
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = new Vector3[] {
Vector3.back, Vector3.back, Vector3.back
};
}
}
三角形顺序
顺时针和逆时针:
当使用顺时针的顶点顺序去绘制三角形,这意味着三角形可以从外部去看见他们,而内部或者说是背面是不会被绘制的。而使用逆时针的顶点顺序去绘制三角形,表现是相反的。
法向量
法向量是一个单位长度的向量,它描述了如果你站在表面上时的局部向上方向。因此,这些向量直接指向远离表面的方向。因此,我们的三角形表面的法向量应该是Vector3.back,指向网格局部空间中 Z 轴负方向的下方。但如果没有提供法向量,Unity 默认使用前向向量,因此三角形会从错误的一侧被照亮的。
虽然定义表面的法向量才有意义,但网格会定义每个顶点的法向量。用于着色的最终表面法线是通过在三角形表面上插入顶点法线来找到的。通过使用不同的法向量,可以为平面三角形添加表面曲率的幻觉。这使得网格看起来是光滑的,而实际上它们是多面的。
Vector3在设置顶点位置后,我们可以通过将数组分配给网格的属性来将法线向量添加到顶点normals。 Unity 检查数组是否具有相同的长度,如果我们提供的法线向量数量错误,Unity 将失败并发出警告。
2. 绘制圆筒
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
public class Dr