fwalker 发表于 2021-12-15 21:04

在Unity中代码绘制Mesh

在Unity中,通过代码绘制mesh,是地形编辑器的基础。本片文章讲如何在Unity中绘制一个Panel的Mesh,并应用一个简单的噪声纹理生成一个随机山形:
01、简单四边面Mesh绘制

一个Mesh常用一下几个信息:vertices mesh中的顶点数据(对象的坐标系) uv 基础的uv纹理坐标triangles 三角面片 color 顶点色normals 法线 tangles 切线 * uv2-8 其他纹理坐标数据,按照需要定义


在绘制一个简单的四边面Mesh时,我们需要至少4个顶点数据,并且包含uv、以及三角面片,绘制面片是,我们使用左手螺旋定则来绘制。
参考代码:
//四个顶点
Vector3[] baseVerts = new Vector3[]
{
      new Vector3(0,0,0),
      new Vector3(1,0,0),
      new Vector3(1,0,1),
      new Vector3(0,0,1),
};
//每个顶点的uv坐标
Vector2[] baseUVs = new Vector2[]
{
      new Vector2(0,0),
      new Vector2(1,0),
      new Vector2(1,1),
      new Vector2(0,1),
};
//每三个顶点组成一个三角面,面朝向依据顶点绘制的左手螺旋定则
int[] baseTriangles = new int[]
{
      0,3,1,
      1,3,2,
};
//将数据赋值给MeshFilter组件的sharedMesh进行绘制
meshData = new Mesh();
meshData.vertices = baseVerts;
meshData.uv = baseUVs;
meshData.triangles = baseTriangles;
meshFilter.sharedMesh = meshData;开启scene窗口的线框模式


可以看到我们代码生成的4个顶点,两个三角面片,以及uv分布


02、Panel绘制

我们以一个四边型mesh为基础来扩展绘制一个大的panel,通过x与z方向上的偏移设置对应顶点数据、uv数据、三角面片数据。 为了之后便于修改数据,我们可以将数据缓存下来;
//初始化数据
void InitMeshData()
{
    meshData = new Mesh();
    vertData = new Vector3;
    uvData = new Vector2;
    triData = new int;
}
//应用数据
void ApllyMeshChange()
{
    meshData.Clear();
    meshData.vertices = vertData;
    meshData.uv = uvData;
    meshData.triangles = triData;
    meshFilter.sharedMesh = meshData;
}
//根据方格位置,返回方格的四个顶点的数组下标
int[] GetRectVerts(int x, int y)
{
    return new int[]
    {
      x + y * vertNumX,
      x + 1 + y * vertNumX,
      x + 1 + (y + 1) * vertNumX,
      x + (y + 1) * vertNumX,
    };
}
//刷新数据
public void RefreshMeshData()
{
    //countX、countY是在x、y方向上网格(四边面)的数目
    for (int i = 0; i < countX; i++)
    {
      for(int j = 0; j < countZ; j++)
      {
            int[] vertIndex = GetRectVerts(i,j);
            //顶点
            Vector3 vertOff = new Vector3(i, 0, j);
            for(int index = 0; index < 4; index++)
            {
                Vector3 pos = baseVerts + vertOff;
                vertData] = pos;   
            }
            //uv
            Vector2 uvCell;
            uvCell.x = 1 / ((float)countX);
            uvCell.y = 1 / ((float)countZ);
            Vector2 uvOff = new Vector2(i,j);
            for (int posIndex = 0; posIndex < 4; posIndex++)
            {
                uvData] = (baseUVs + uvOff) * uvCell;
            }
            //面片(每个四边形面要绘制两个三角面)
            int rectIndex = i +j * countX;
            for (int subTriIndex = 0; subTriIndex < 2; subTriIndex++)
            {
                int fargIndex = 2 * rectIndex + subTriIndex;
                for (int posIndex = 0; posIndex < 3; posIndex++)
                {
                  int pos = baseTriangles;
                  triData = vertIndex;
                }
            }
      }
    }
}绘制结果:


03、增加一个高度纹理

我们新增一个可读写的噪声纹理,作为高度值输入。


vertpos.y = heightMap.r * maxheight;绘制结果:


04、尾声

Panel的绘制大致如此,这只是一次简单代码绘制的尝试,但动态的Mesh+Texture数据组合也是实现一些高级的工具或特效的基础,在一些高计算量的地方,可以考虑使用ComputeShader优化。
页: [1]
查看完整版本: 在Unity中代码绘制Mesh