unity中Mesh网格编程

unity中Mesh网格编程_第1张图片
上图是效果
一.关于mesh的意义
有了mesh网格,物体才能被渲染出来。
(1)mesh中包含顶点,
mesh.vertices
(2)顶点对应的uv(一张图的uv左下角00,右上角11)
mesh.uv
(3)指定每个三角面对应的顶点位置(顺时针方向culling back:默认不绘制背面)
mesh.triangles
(4)切线信息
mesh.tangents
(5)法线信息
mesh.normals
还有其它就不再说了,这里主要是 顶点“veticles”,“uv”, 三角面“triangles”!!!

二.一个物体的正常渲染流程:
顶点坐标 -》顶点对应的UV坐标-》三角面对应的顶点位置
三.设置顶点的坐标和顺序可以多种多样,但是条条大路通罗马
例如:一个长方体:
设置顶点坐标的方式:从上往下 从左往右 等

怎么从0到1绘制一个简单的长方形有很多教程,解释的很清楚mesh编程入门精讲
有两个函数注意一下:
(1)重置法线垂直于当前的三角面
mesh.RecaculateNormals()
(2)将当前mesh,拆分成3个submesh
mesh.submeshCount = 3
mesh.SetTriangles(trianglesX, 0);
mesh.SetTriangles(trianglesY, 1);
mesh.SetTriangles(trianglesZ, 2);
并且 MeshRender中的Materials中的 第一个material对应渲染第一个submesh;第二个material对应渲染第二个;。。。。

四介绍绘制一个立方体的思路:
(1)计算顶点的个数:

//三个面的交点
        int conerVerticles = 8;
        // 两个面的交点
        int edgeVerticles = (xSize + ySize + zSize - 3) * 4;
        // 上中下 三个面的点 (共6个面,所以要乘以2)
        int faceVerticles = ((xSize - 1) * (ySize - 1) + (xSize - 1) * (zSize - 1) + (ySize - 1) * (zSize - 1)) * 2;
        // 总顶点数量
        int totalVerticles = conerVerticles + edgeVerticles + faceVerticles;
        Vector3[] veticles = new Vector3[totalVerticles];

(2)在形成三角形的时需要用到三角形顶点的个数:
有n个四边形,那么总的三角形顶点数目: 4*n

 		//一共多少四边形
        int quads = (xSize * zSize + xSize * ySize + zSize * ySize) * 2;
        // 三角面的顶点数
        int totalCount = quads * 6;
        int[] triangles = new int[totalCount];

(3)计算下一个triangles的索引:

    // 返回值是 :下一个triangles的索引
    static int SetQuad(int[]triangles,int t,int v00,int v10,int v01,int v11)
    {
        triangles[t] = v00;
        triangles[t + 1] = triangles[t+4] = v01;
        triangles[t + 2] = triangles[t+3] = v10;
        triangles[t + 5] = v11;
        return t + 6;
    }

(4)其它的就没有可讲的了,都是如何拼接三角形形成mesh。顺序和方法比较多。。思想都是一样的。
下面附详细代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(MeshFilter),  typeof(MeshRenderer))]
public class SplittingMesh : MonoBehaviour
{
    public int xSize, ySize, zSize;
    public int Roundness;

    private Mesh mesh;
    private Vector3[] vertices;
    private Vector3[] normals;
    private Color32[] CubeUV;

    void Start()
    {
        GenerateVertices();
       StartCoroutine(GenerateTriangles());
    }
    /// 
    /// 生成顶点
    /// 
    void GenerateVertices()
    {
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "Procedural Cube ";

        int cornerVertices = 8; //八个角 八个顶点
        int edgeVertices = (xSize +ySize +zSize -3)*4; //不考虑顶点公用的话 应该是 (xSize+ySize+zSize +1)*4
        int faceVertices = (
            (xSize-1)*(ySize-1)+
            (xSize-1)*(zSize-1)+
            (ySize-1)*(zSize-1)
         )*2;
        int vCount = cornerVertices + edgeVertices + faceVertices;
        vertices = new Vector3[vCount];
        normals = new Vector3[vertices.Length];
        CubeUV = new Color32[vertices.Length];
            
        int v = 0;
        //赋予前后左右四个面顶点
        for (int y = 0; y <=ySize; y++)
        {
            //前面
            for (int x = 0; x <= xSize; x++)
            {
                SetVertex(v++, x, y, 0);
            }
            //右面 一开始  因为上面已经把最后一个点 公共顶点绘制完成
            for (int z = 1; z <= zSize; z++)
            {
                SetVertex(v++, xSize, y, z);
            }
            //后面
            for (int x = xSize - 1; x >= 0; x--)
            {
                SetVertex(v++, x, y, zSize);
            }
            //左面
            for (int z = zSize - 1; z > 0; z--)
            {
                SetVertex(v++, 0, y, z);

            }
        }

        //赋予上面顶点
        for (int z = 1; z < zSize; z++)
        {
            for (int x = 1; x < xSize; x++)
            {
                SetVertex(v++, x, ySize, z);
            }
        }
        //赋予下面顶点
        for (int z = 1; z < zSize; z++)
        {
            for (int x = 1; x < xSize; x++)
            {
                SetVertex(v++, x, 0, z);
            }
        }
        mesh.vertices = vertices;
        mesh.normals = normals;
        mesh.colors32 = CubeUV;
    }

    /// 
    /// 计算顶点 法线
    /// 
    private void SetVertex(int i, int x , int y, int z)
    {
       Vector3 inner =  vertices[i] = new Vector3(x, y, z);
        if (x <Roundness)
        {
            inner.x = Roundness;
        }
        else if (x > xSize -Roundness)
        {
            inner.x = xSize - Roundness;
        }
        if (y < Roundness)
        {
            inner.y = Roundness;
        }
        else if (y> ySize -Roundness)
        {
            inner.y = ySize - Roundness;
        }
        if (z < Roundness)
        {
            inner.z = Roundness;
        }
        else if (z > zSize - Roundness)
        {
            inner.z = zSize - Roundness;
        }

        normals[i] = (vertices[i] - inner).normalized;
        vertices[i] = inner + normals[i] * Roundness;
        CubeUV[i] = new Color32((byte)x, (byte)y, (byte)z,0);
    }


    IEnumerator GenerateTriangles()
    {
        WaitForSeconds wait = new WaitForSeconds(0.1f);


        int[] trianglesZ = new int[xSize * ySize * 12];
        int[] trianglesX = new int[zSize*ySize*12];
        int[] trianglesY = new int[xSize * zSize * 12];

        int tZ = 0, tX = 0, tY = 0, v = 0;
        int ring = (xSize + zSize) * 2;// 行与行的 顶点偏移量

        for (int y = 0; y < ySize; y++, v++)
        {
            for (int q = 0; q < xSize; q++, v++)
            {
                tZ = SetQuad(trianglesZ, tZ, v, v+1, v+ring, v+ring+1);
            }

            for (int q = 0; q < zSize; q++, v++)
            {
                tX = SetQuad(trianglesX, tX, v, v + 1, v + ring, v + ring + 1);
            }

            for (int q = 0; q < xSize; q++, v++)
            {
                tZ = SetQuad(trianglesZ, tZ, v, v + 1, v + ring, v + ring + 1);
            }

            for (int q = 0; q < zSize-1; q++, v++)
            {
                tX = SetQuad(trianglesX, tX, v, v + 1, v + ring, v + ring + 1);
            }
            tX = SetQuad(trianglesX, tX, v, v  -ring +1, v + ring, v + 1);
        }


        tY = CreateTopFace(  trianglesY, tY, ring);
        tY = CreateBottomFace(trianglesY, tY, ring);

        mesh.subMeshCount = 3;

        mesh.SetTriangles(trianglesZ, 0);
        mesh.SetTriangles(trianglesX, 1);
        mesh.SetTriangles(trianglesY, 2);
        mesh.subMeshCount = 3;
        mesh.SetTriangles(trianglesX, 0);

        yield return wait;
    }

    /// 
    /// 创建上面
    /// 
    /// 
    int CreateTopFace( int [] trinagles,  int t ,  int ring)
    {
        int v = ring * ySize;
        for (int x = 0; x < xSize-1; x++,v++)
        {
            t = SetQuad( trinagles, t,v,v+1,v+ring-1,v+ring);
        }
        t = SetQuad( trinagles, t,v,v+1,v+ring-1,v+2);

        int vMin = ring * (ySize + 1) - 1;
        int vMid = vMin + 1;
        int vMax = v + 2;

        for (int z = 1; z < zSize-1; z++,vMin--,vMid++,vMax++)
        {
            t = SetQuad(trinagles, t, vMin, vMid, vMin - 1, vMid + xSize - 1);
            for (int x = 1; x < xSize - 1; x++, vMid++)
            {
                t = SetQuad(trinagles, t, vMid, vMid + 1, vMid + xSize - 1, vMid + xSize);
            }

            t = SetQuad(trinagles, t, vMid, vMax, vMid + xSize - 1, vMax + 1);
        }
        //最后一行
        int vTop = vMin - 2;
        t = SetQuad(trinagles, t, vMin, vMid, vTop+1, vTop );
        for (int x = 1; x < xSize-1; x++, vTop--,vMid++)
        {
            t = SetQuad(trinagles, t, vMid, vMid+1, vTop , vTop-1);
        }
        t = SetQuad(trinagles, t, vMid, vTop-2, vTop, vTop - 1);

        return t;
    }

    /// 
    /// 创建底面
    /// 
    /// 
    /// 
    /// 
    /// 
    int CreateBottomFace(int[] trinagles, int t, int ring)
    {
        int v = 1;
        int vMid = vertices.Length - (xSize - 1) * (zSize - 1);
        int vOriginMid = vMid;

        t = SetQuad(trinagles, t, ring-1, vMid, 0, 1);
        for (int x = 1; x < xSize-1; x++, vMid++,v++)
        {
            t = SetQuad(trinagles, t, vMid, vMid+1, v, v+1);
        }
        t = SetQuad(trinagles, t, vMid, v+2, v, v + 1);

        /
        int vMin = ring - 2;
        int vMax = v + 2;
        vMid++;

        for (int z = 1; z < zSize-1; z++,vMin--,vMax++,vMid++,vOriginMid++)
        {
            t = SetQuad(trinagles, t, vMin, vMid, vMin + 1, vOriginMid);
            for (int x = 1; x < xSize - 1; x++, vMid++, vOriginMid++)
            {
                t = SetQuad(trinagles, t, vMid, vMid + 1, vOriginMid, vOriginMid + 1);
            }
            t = SetQuad(trinagles, t, vMid, vMax + 1, vOriginMid, vMax);
        }

        int vTop = vMin - 1;

        t = SetQuad(trinagles, t, vTop+1, vTop, vTop+2, vOriginMid);
        for (int x = 1; x < xSize-1; x++, vOriginMid++,vTop--)
        {
            t = SetQuad(trinagles, t, vTop, vTop-1,  vOriginMid, vOriginMid+1);
        }

        t = SetQuad(trinagles, t, vTop, vTop - 1, vOriginMid, vTop-2);
        return t;
    }



    /// 
    /// 我们封装这个 三角形拼接四边形的方法 返回三角形的下一轮第一个索引  参数v00 是顶点的索引
    /// 
    private static  int SetQuad(int[] triangles,  int i , int v00 , int v10 ,int v01 , int v11  )
    {
        triangles[i] = v00;
        triangles[i + 2] = triangles[i + 3] = v10;
        triangles[i + 1] = triangles[i + 4] = v01;
        triangles[i + 5] = v11;
        return i + 6;
    }


    private void OnDrawGizmos()
    {
        //if (vertices == null) return;

        //for (int i = 0; i < vertices.Length; i++)
        //{
        //    Gizmos.color = Color.black;
        //    Gizmos.DrawSphere( vertices[i] ,0.1f);
        //    Gizmos.color = Color.yellow;
        //    Gizmos.DrawRay(vertices[i],normals[i]);
        //}
    }


}

你可能感兴趣的:(Mesh和批处理,unity,mesh编程,unity中mesh拆分)