以下内容是转载Spring5211大佬的博客地址
效果图
什么是网格?
- 如果你想要在Unity显示一些东西,你需要一个网格。它可以是一个3D模型从另一个程序导入的(比如33dmax or maya)。它也可以是程序生成的网格。它可以是精灵、UI元素或者是粒子系统,它们一样都是使用unity网格,甚至是屏幕特效也是使用网格渲染的。
So,什么是网格?概念上来说网格由图形硬件(GPU Graphics Processing Unit图形处理单元)构成来绘制复杂的材料/东西。它至少包含一组在3D空间中位置明确的点再加一组三角形
- 最基础的2D图形,由点连接组成,面上的三角形就时此类网格的代表。
因为三角形是平坦的并且拥有直边,所以他们可以完美地被用来显示平坦的和连续的东西,像一个立方体的面孔。曲面的或者是圆的面只能被大量小的三角形来接近组成。如果三角面显示足够的小(不大于一个像素),那么你就不会感觉曲面或者是圆是由三角面组成的。从实时性能角度来讲通常这种情况是不可能的,所以我们总能够在面的某个程度上发现锯齿。
什么是Gizemos?
- 在编辑模式下Gizmos可以提供可视化的提示。它们只在Scene场景中显示不在Play模式下显示,但是你可以通过工具栏调整它们。Gizmos公共类允许你绘制图标,线条,和其他的东西。
- Gizmos在OnDrawGizmos方法中执行绘制,它被Unity编辑器自动调用。另一个可选的方法是OnDrwaGizmosSelected,它只能被可选的对象调用。
法线工作原理?
- 法线是垂直于面的向量。我们通常使用单位长度的法向量,并向量指向面的外部,而不是内部。
- 法线可以用于确定光线与顶点的夹角。这个细节的使用取决于Shader。
- 作为三角面它永远是平的,因此它不应该需要被提供一个单独的法线信息。然而,我们需要造假。在现实中,顶点时不存在法线的,三角面才有。通过附加自定义顶点法线和三角面插着,我们可以奖状我们有一个平滑的曲面代替一堆平的三角面。这个错觉是令人信服的,只要你不去注意网格锋利的轮廓(锯齿)。
材质球和UV?
- 你可以完全改变网格的显示效果通过调整材质球。Unity默认的材质球是简单的白色立体。你可以自己创建一个新的材质球通过Assets->Create->Material并拖拽到你的游戏物体上来代替它。新的材质球默认为Unity Standard Shader,它有一组口控制,你可以调节这些属性得到你想要模型表现。
- 一个快速添加细节的方法是给你的网格提供一个反射贴图,这个纹理描绘了材质球的基础颜色。当然我们需要知道如何投射纹理到网格的三角面上。这需要添加2D纹理坐标到顶点上。这二维纹理空间被称为U和V,也是常说的UV坐标。UV坐标通常在(0,0)到(1,1)之间,它覆盖了整个纹理。超出范围的坐标将造成clamped或者Tiling平铺的效果,这去取决于纹理设置。
切线的工作原理?
- 法线贴图在切线空间中定义。这是一个流动在物理表面的3D空间。这个方法使我们能够使用相同的法线贴图在不同的空间和方向。
- 表面法相用于描述空间中的向上方向。但是哪个方向是正确的?它是有切线决定得。理论上,法线和切线的夹角应该是90度。两者的叉积可求出三维空间的第三个方向。但是现实中这个结果并不是90度,但是效果依然是令人比较满意的。
- 所以切线是一个三维向量,但是在Unity中它是使用四维向量定义的。第四个值通常是1或者-1,用于控制第三切线空间唯独方向-朝前或朝后,这有助于展示法线贴图,通常用于左右对称的3D模型,像人一样。Untiy的shader执行此计算要求我们使用-1。
代码部分 我做了很详细的注释
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class MeshGrid : MonoBehaviour
{
//设置Mesh网格的长度,x*y 为Mesh的面积 从0开始
public int xSize, ySize;
private Vector3[] vertices; //vertices为顶点数组
public Mesh mesh;
private void Awake()
{
Generate();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void Generate()
{
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Procedural Grid";
//创建一个x*y的网格 vertices为顶点数组
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
//---------------------------------------------------------------------------------
//点击Play播放按钮之后,在Scene视图中我们只能看见一个球体在世界的原点。
//因为我们还没有定位顶点的位置,所以所有的球体重叠在一个位置。我们必须会用双重循环遍历所有的位置
//---------------------------------------------------------------------------------
for (int i = 0, y = 0; y <= ySize; y++)
{
for (int x = 0; x <= xSize; x++, i++)
{
vertices[i] = new Vector3(x, y);
}
}
//mesh的顶点信息
mesh.vertices = vertices;
//-------------------------------------------------------
// xsize*6 是一位 每个三角面有3个顶点,也就是而每个正方形有6个顶点
// 一行有xsiz个正方形 也就有xsize*6的顶点
//-------------------------------------------------------
int[] triangles = new int[xSize * ySize * 6];
for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++)
{
for (int x = 0; x < xSize; x++, ti += 6, vi++)
{
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 2] = vi + 1;
triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
triangles[ti + 5] = vi + xSize + 2;
}
}
//mesh的三角面信息
mesh.triangles = triangles;
// 网格自动计算法线向量
mesh.RecalculateNormals();
Vector2[] uv = new Vector2[vertices.Length];
for (int i = 0, y = 0; y <= ySize; y++)
{
for (int x = 0; x <= xSize; x++, i++)
{
vertices[i] = new Vector3(x, y);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
}
}
//mesh的uv信息
mesh.uv = uv;
//mesh的切线信息
Vector4[] tangents = new Vector4[vertices.Length];
Vector4 tangent = new Vector4(1f, 0f, 0f, -1f);
for (int i = 0, y = 0; y <= ySize; y++)
{
for (int x = 0; x <= xSize; x++, i++)
{
vertices[i] = new Vector3(x, y);
uv[i] = new Vector2((float)x / xSize, (float)y / ySize);
tangents[i] = tangent;
}
}
mesh.tangents = tangents;
}
//------------------------------------------------------
//Gizmos在OnDrawGizmos方法中执行绘制,它被Unity编辑器自动调用。
//另一个可选的方法是OnDrwaGizmosSelected,它只能被可选的对象调用。
//------------------------------------------------------
private void OnDrawGizmos()
{
if (vertices == null) return;
Gizmos.color = Color.black;
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], 0.1f);
}
}
}