找回密码
 立即注册
查看: 658|回复: 0

[笔记] 在Unity中代码绘制Mesh

[复制链接]
发表于 2021-12-15 21:04 | 显示全部楼层 |阅读模式
在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[vertNumX * vertNumZ];
    uvData = new Vector2[vertNumX * vertNumZ];
    triData = new int[3 * 2 * countX * countZ];
}
//应用数据
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[index] + vertOff;
                vertData[vertIndex[index]] = 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[vertIndex[posIndex]] = (baseUVs[posIndex] + 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[subTriIndex * 3 + posIndex];
                    triData[3 * fargIndex + posIndex] = vertIndex[pos];
                }
            }
        }
    }
}绘制结果:


03、增加一个高度纹理

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


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


04、尾声

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 20:49 , Processed in 0.089680 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表