unity渲染 - Mesh基础 自己创建mesh

English :
coordinate : 坐标
tangent : 切线
normal :法线
triangle : 三角形
vertice : 顶点
 
 
mesh 中存储着 三维模型的数据 : vertices (顶点数组Vector3[]) 、triangles (三角形 int[]) 、normals (法线 Vector3 []) 、uv(纹理坐标 ,Vector2 [])
tips:
uv类似于unity的坐标系下的x,y,是纹理贴图坐标的简称它定义了图片上每个点的位置的信息。baiUV就是将图像上每一个点精确对应到模型物体的表面。在点与点之间的间隙位置由软件进行图像光滑插值处理。这就是所谓的UV贴图。
一  绘制物体 
如果想在unity的场景中看到物体,我们都会使用mesh。它可以使其他程序导入的3D模型,也可以是我们自己生成的mesh。可以是一个图片精灵,ui元素,或者是特效,unity本身也使用了网格。甚至是我们屏幕的效果也可以通过网格文件绘制渲染。
所以,究竟什么是网格信息?
 从概念上讲,网格是图形硬件用来绘制复杂内容的结构。 它至少包含一组定义3D空间中点的顶点,以及一组连接这些点的三角形-最基本的2D形状。 三角形构成任何网格所代表的表面。
 
由于三角形是平坦的并且具有笔直的边缘,因此可以使用它们完美地可视化平坦和笔直的物体,例如立方体的面。 只能通过使用许多小三角形来近似曲面或圆形表面。 如果三角形看起来足够小(不大于单个像素),则您不会注意到近似值。 通常,这对于实时性能而言是不可行的,因此表面在一定程度上始终会出现锯齿。
 
unity中点击Scene页面的左上角按钮,选择Wireframe , 就可以看到你场景中游戏对象的网格信息了。
 
通常,我们可以在场景中看到的游戏对象他们对应的都会有两个组件 Mesh Filter 和 MeshRenderer. 其中MeshFilter 的作用是告诉程序你所绘制的网格信息是什么, 也就是,你要绘制的是什么,而MeshRenderer是通过你的Material的赋值,来告诉程序,你要怎么绘制。
 
二 生成网格信息的顶点(Vertices)
 
创建网格关键还是创建顶点,所以第一步我们先去创建顶点。对于网格信息来说,如果我们有一个4*3 的网格,我们可以排列看一下他的格子和顶点的排列
 
 
(红色标注为定点信息)
可以得到一个公式, 顶点的个数 = (X +1)*(Y+1),同时为顶点坐标赋值
 
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
for(int i =0 , y =0;y<ySize;y++)
{
     for(int x =0;x<xSize;x++,i++)
     {
           vertices[i] = new Vector3(x, y);
     }
}
 
为了更加直观的看到我们所需要的顶点,可以通过Gizom绘制出来所有的顶点
      private void OnDrawGizmos()
    {
        if (null == vertices)
            return;
        Gizmos.color = Color.red;
        for(int i =0;i<vertices.Length;i++)
        {
            Gizmos.DrawSphere(vertices[i], 0.1f);
        }
    }
 
为了看清楚,整个顶点生成的过程,可以通过协程的方式,来逐个生成顶点,查看对应顶点的摆放
 
 
三 创建网格信息(Triangle)
 
在创建好的顶点信息的基础上,我们就可以开始创建mesh的三角形信息
 
我们知道,mesh是由三角形组成的,所以每一个方形的格子都可以按照上面的方法进行切割,生成两个三角形。
那么我们所绘制的顺序应该是什么样子的的。
就第一个方形的格子为例, 
在绘制第一个三角形的时候,顶点的顺序可以是 [0,1,5] 也可以是 [0,5,1]
但是当绘制的定点顺序如果是[0,1,5]的时候,其实在z轴正方向是看不到三角形, 其实三角形的那一侧可以看到取决于顶点的索引方向。如果按照顺时针排列, 则三角形都被视为朝前的, 并且可见。相反逆时针的三角形都将会被丢弃。
 
所以我们就按照这个规则:
第一个三角形  [0,5,1]
第二个三角形 [1,5,6]
下图分别为绘制一个三角形,和两个三角形的效果图
以此类推,可以找到对应的队列绘制规律
  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;
            }
        }
       /*        triangles = new int[6]; // 0,5,1 ; 156
                triangles[0] = 0;
                triangles[1] = xSize + 1;
                triangles[2] = 1;
                triangles[3] = 1;
                triangles[4] = xSize + 1;
                triangles[5] = xSize + 2;*/
//赋值
mesh.triangles = triangles;
 
 
 
三  绘制顶点的其他信息 (Normals 法线,uv)
 
法线 :      
mesh.RecalculateNormals();
Mesh.RecalculateNormals方法计算出每个顶点的法线,方法是找出哪些三角形与该顶点连接,确定这些扁平三角形的法线,对其进行平均,然后对结果进行归一化。
 
uv 坐标; 为了将图片信息和顶点信息结合,从而显示图片,我们需要设置uv坐标和我们之前设置的定点信息结合
在没有设置mesh的uv信息的时候,会发现,即使给材质添加了图片,但是场景中的依然看不到对应的图片显示,只有对应图片颜色的一个显示
只有设置了uv信息才会看到对应的图片显示。为了在整个网格上获得介于零和一之间的正确坐标,我们必须确保使用浮点数。
vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        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(x *1f / xSize, y *1f / ySize);
            }
        }
mesh.uv= uv;
 
当把格子的长宽设置为 10*5的时候,横向是纵向的2倍,这个时候贴图会被拉伸
可以通过设置 材质的tiling值,来设置为图片为平铺的模式
 
还可以通过使用法线贴图, 这些贴图包含编码为颜色的法线向量。 将它们应用到表面上将产生比仅使用顶点法线所创建的更为精细的光照效果。
 
 
切线 
法线贴图是在切线空间中定义的。这是一个围绕对象表面流动的3D空间。可以让我们在不同位置和方向上使用相同的法线贴图。
 
表面法线应该是在该空间中表示向上,这是由切线定义的。理想情况下,法线和切线的向量之间的角度应该为90°。他们的叉积产生定义3D空间所需要的第三个方向。实际上,角度通常都不是90°,但是结果还是足够很好的。
 
因此,切线是3D向量,但是是实际上unity中使用的是4D。他的第四部分,始终为-1或者1. 用于控制第三切线空间尺寸的方向-向前或向后。这有助于法线贴图的镜像,法线贴图通常用于具有双边对称性的事物(例如 人)的3D模型中。 untiy着色器执行词计算的方式要求我们使用-1。
 
  Vector2[] uv = new Vector2[vertices.Length];
        Vector4[] tangents = new Vector4[vertices.Length];
        Vector4 tangent = new Vector4(1, 0, 0, -1);
        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(x*1f / xSize, y*1f / ySize);
                tangents[i] = tangent;
            }
        }
 
 
      mesh.RecalculateNormals();
        mesh.tangents = tangents; //切线在设置法线之后
 
 
 
 
 
 
制作mesh的几个要素点
顶点 , 三角形, 法线, uv , 切线(可以没有,只用于有法线贴图的时候)
 
 
 
 
 
 
 
 
 

你们如果有想法欢迎讨论~~
一起学习呀~~ 欢迎一起交流
QQ群 :780697909

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值