• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Unity-网格编程

武飞扬头像
莉萝爱萝莉
帮助3

1. 简介

1. 基础理论

  1. 模型是由点和面构成的,每三个点构成一个三角面。
  2. 根据三个顶点排列的顺序,根据左手定则决定三角面的正反面
  3. 三角形序列是一组int数组,数组元素数量为3的倍数,表示三角形的顶点 对应的顶点ID
  4. Unity想要显示一个模型,必须在对象上挂载组件Mesh Filter(网格过滤器)与Mesh Renderer(网格渲染器)

2. Mesh构成

  1. Vertex
  2. Normal
  3. UV
  4. Trangle(三角形序列)

2. 基本函数

1. 使用代码创建Mesh模型

1. Mesh类
  1. Unity允许使用Mesh类创建模型,并将创建的Mesh赋值给MeshFilter。
  2. 模型顶点列表 记录了所有顶点的位置信息;
    三角形序列 决定了哪三个顶点会构成一个三角面。以左手定则决定面的正方向;
    UV坐标列表 决定了每个顶点对应UV纹理坐标的具体位置。三角面之间的UV值将通过三个顶点的UV值,以插值的方式确定面每个位置的的UV值;
Mesh参数 描述
name 模型名称
vertices 模型顶点列表
triangles 三角形序列(序列数量必须为3的倍数)
uv UV坐标列表
normals 法线列表
tangents 切线列表
Mesh函数 描述
RecalculateNormals() 自动计算法线方向
RecalculateTangents() 自动计算切线方向
RecalculateBounds() 重新计算模型边缘界限
2. 示例

一个正方形

MeshFilter filter;

void Start()
{
    filter = GetComponent<MeshFilter>();
    Mesh mesh = new Mesh();
    mesh.name = "Mesh_01";
    mesh.vertices = GetVertexs();
    mesh.triangles = GetTriangles();
    mesh.uv = GetUVs();
    mesh.normals = GetNormals();
    mesh.tangents = GetTangent();
    filter.mesh = mesh;

}

// 设定顶点位置
Vector3[] GetVertexs()
{
    return new Vector3[] 
    {
        new Vector3(0, 0, 0),
        new Vector3(1, 0, 0),
        new Vector3(0, 1, 0),
        new Vector3(1, 1, 0),
    };
}

// 设定三角形序列
int[] GetTriangles()
{
    return new int[]
    {
        0, 1, 2, 1, 3, 2
    };
}

// 设定UV
Vector2[] GetUVs()
{
    return new Vector2[]
    {
        new Vector2(1, 0),
        new Vector2(0, 0),
        new Vector2(1, 1),
        new Vector2(0, 1),
    };
}

// 设定顶点位置
Vector3[] GetNormals()
{
    return new Vector3[]
    {
        new Vector3(0, 0, 1),
        new Vector3(0, 0, 1),
        new Vector3(0, 0, 1),
        new Vector3(0, 0, 1),
    };
}

// 设定顶点位置
Vector4[] GetTangent()
{
    return new Vector4[]
    {
        new Vector4(-1, 0, 0, -1),
        new Vector4(-1, 0, 0, -1),
        new Vector4(-1, 0, 0, -1),
        new Vector4(-1, 0, 0, -1),
    };
}
学新通

动态创建指定尺寸的矩形

public int width, height;

MeshFilter filter;

private void OnDrawGizmos()
{
    Start();
}

void Start()
{
    filter = GetComponent<MeshFilter>();
    Mesh mesh = new Mesh();
    DrawMesh(mesh);
    filter.mesh = mesh;
}

void DrawMesh(Mesh mesh)
{
    mesh.name = "Mesh_02";

    width = width > 0 ? width : 0;
    height = height > 0 ? height : 0;
    // 顶点列表
    Vector3[] vertices = new Vector3[(width   1) * (height   1)];
    Vector2[] uvs = new Vector2[(width   1) * (height   1)];
    int[] triangles = new int[width * height * 2 * 3];
    for (int y = 0; y < height   1; y  )
    {
        for (int x = 0; x < width   1; x  )
        {
            vertices[x   y * (width   1)] = new Vector3(x, y, 0);
            uvs[x   y * (width   1)] = new Vector2((float)x / width, (float)y / height);
        }
    }
    // 开始坐标依次递增,内层循环在最后额外让开始坐标 1.从而避开了结尾点
    for (int y = 0, trianglesIndex = 0, startIndex = 0; y < height; y  , startIndex  )
    {
        for (int x = 0; x < width; x  , startIndex  , trianglesIndex  = 6)
        {
            triangles[trianglesIndex] = startIndex   width   1;
            triangles[trianglesIndex   1] = startIndex   1;
            triangles[trianglesIndex   2] = startIndex;
            triangles[trianglesIndex   3] = startIndex   width   1;
            triangles[trianglesIndex   4] = startIndex   width   2;
            triangles[trianglesIndex   5] = startIndex   1;
        }
    }
    mesh.vertices = vertices;
    mesh.triangles = triangles;
    mesh.uv = uvs;
}
学新通

创建正方体

void DrawMesh(Mesh mesh)
{
    mesh.name = "Mesh_03";
    Vector3[] vertices = new Vector3[8]
    {
        new Vector3(-0.5f, -0.5f, -0.5f),
        new Vector3(0.5f, -0.5f, -0.5f),
        new Vector3(-0.5f, 0.5f, -0.5f),
        new Vector3(0.5f, 0.5f, -0.5f),
        new Vector3(-0.5f, -0.5f, 0.5f),
        new Vector3(0.5f, -0.5f, 0.5f),
        new Vector3(-0.5f, 0.5f, 0.5f),
        new Vector3(0.5f, 0.5f, 0.5f),
    };
    int[] triangles = new int[] 
    {
        0, 3, 1,
        0, 2, 3,
        2, 6, 7,
        2, 7, 3,
        3, 7, 5,
        3, 5, 1,
        0, 4, 6,
        0, 6, 2,
        1, 5, 4,
        1, 4, 0,
        6, 4, 5,
        6, 5, 7
    };
    foreach (var vertex in vertices) Gizmos.DrawSphere(vertex   transform.position, 0.15f);
    mesh.vertices = vertices;
    mesh.triangles = triangles;
    mesh.RecalculateNormals();
    mesh.RecalculateTangents();
    mesh.RecalculateBounds();
}
学新通

创建圆角正方体,胶囊体,球体

public int XGridCount, YGridCount, ZGridCount;
    public float XSize, YSize, ZSize, Radius;
    public bool debug;

    MeshFilter filter;

    /// <summary>
    /// 顶点数量
    /// </summary>
    int VertexCount
    {
        get
        {
            // 顶角顶点数量
            int connerVertexCount = 8;
            // 边顶点数量
            int edgeVertexCount = (XGridCount   YGridCount   ZGridCount - 3) * 4;
            // 面顶点数量
            int faceVertexCount = (XGridCount - 1) * (YGridCount - 1) * 2   (XGridCount - 1) * (ZGridCount - 1) * 2   (ZGridCount - 1) * (YGridCount - 1) * 2;
            return connerVertexCount   edgeVertexCount   faceVertexCount;
        }
    }
    /// <summary>
    /// 三角形序列数量
    /// </summary>
    int TriangeCount
    {
        get
        {
            return XGridCount * YGridCount * 4   XGridCount * ZGridCount * 4   ZGridCount * YGridCount * 4;
        }
    }
    int FloorCount
    {
        get
        {
            return (XGridCount   ZGridCount) * 2;
        }
    }

    private void OnDrawGizmos()
    {
        Start();
    }

    void Start()
    {
        filter = GetComponent<MeshFilter>();
        Mesh mesh = new Mesh();
        DrawMesh(mesh);
        filter.mesh = mesh;
    }

    void DrawMesh(Mesh mesh)
    {
        mesh.name = "Mesh_04";

        XGridCount = XGridCount >= 1 ? XGridCount : 1;
        YGridCount = YGridCount >= 1 ? YGridCount : 1;
        ZGridCount = ZGridCount >= 1 ? ZGridCount : 1;
        XSize = XSize >= 1 ? XSize : 1;
        YSize = YSize >= 1 ? YSize : 1;
        ZSize = ZSize >= 1 ? ZSize : 1;
        Radius = Radius < XSize / 2 ? Radius : XSize / 2;
        Radius = Radius < YSize / 2 ? Radius : YSize / 2;
        Radius = Radius < ZSize / 2 ? Radius : ZSize / 2;

        SetVertex(mesh);
        SetNormal(mesh);
        SetTriange(mesh);
    }

    void SetVertex(Mesh mesh)
    {
        Vector3[] vertices = new Vector3[VertexCount];
        int index = 0;
        for (int y = 0; y < YGridCount   1; y  )
        {
            for (int i = 0; i < XGridCount; i  , index  )
            {
                vertices[index] = new Vector3((float)i / XGridCount * XSize, (float)y / YGridCount * YSize, 0);
            }
            for (int i = 0; i < ZGridCount; i  , index  )
            {
                vertices[index] = new Vector3(XSize, (float)y / YGridCount * YSize, (float)i / ZGridCount * ZSize);
            }
            for (int i = XGridCount; i > 0; i--, index  )
            {
                vertices[index] = new Vector3((float)i / XGridCount * XSize, (float)y / YGridCount * YSize, ZSize);
            }
            for (int i = ZGridCount; i > 0; i--, index  )
            {
                vertices[index] = new Vector3(0, (float)y / YGridCount * YSize, (float)i / ZGridCount * ZSize);
            }
        }
        for (int z = 1; z < ZGridCount; z  )
        {
            for (int x = 1; x < XGridCount; x  , index  )
            {
                vertices[index] = new Vector3((float)x / XGridCount * XSize, ZSize, (float)z / ZGridCount * ZSize);
            }
        }
        for (int z = 1; z < ZGridCount; z  )
        {
            for (int x = 1; x < XGridCount; x  , index  )
            {
                vertices[index] = new Vector3((float)x / XGridCount * XSize, 0, (float)z / ZGridCount * ZSize);
            }
        }
        mesh.vertices = vertices;
    }

    void SetTriange(Mesh mesh)
    {
        int[] triangles = new int[TriangeCount * 3];

        int index = 0;
        // 生成边缘一圈
        for (int h = 0; h < YGridCount; h  )
        {
            for (int i = 0; i < FloorCount - 1; i  , index  )
            {
                SetQuad(triangles, index * 6, index, index   1, index   FloorCount, index   FloorCount   1);
            }
            SetQuad(triangles, index * 6, index, h * FloorCount, index     FloorCount, (h   1) * FloorCount);
        }

        // 生成顶面左下边
        for (int x = 0; x < XGridCount - 1; x  , index  )
        {
            SetQuad(triangles, index * 6, index, index   1, index   FloorCount - 1, index   FloorCount);
        }
        // 生成顶面右下角
        SetQuad(triangles, index * 6, index, index   1, index   FloorCount - 1, index     2);
        // 第二行第一个面的v00
        int topMin = FloorCount * (YGridCount   1) - 1;
        // 生成左右侧边
        for (int i = 0; i < ZGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, topMin - i, topMin   1   i * (XGridCount - 1), topMin - 1 - i, topMin   1   (i   1) * (XGridCount - 1));
        }
        for (int i = 0; i < ZGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, topMin   (XGridCount - 1) * (i   1), topMin - FloorCount   XGridCount   2   i, topMin   (XGridCount - 1) * (i   2), topMin - FloorCount   XGridCount   3   i);
        }
        for (int z = 0; z < ZGridCount - 2; z  )
        {
            for (int x = 0; x < XGridCount - 2; x  , index  )
            {
                SetQuad(triangles, index * 6,
                    topMin   x   z * (XGridCount - 1)   1,
                    topMin   x   z * (XGridCount - 1)   2,
                    topMin   x   z * (XGridCount - 1)   XGridCount,
                    topMin   x   z * (XGridCount - 1)   XGridCount   1);
            }
        }

        SetQuad(triangles, index   * 6, topMin - ZGridCount   2, topMin   (XGridCount - 1) * (ZGridCount - 2)   1, topMin - ZGridCount   1, topMin - ZGridCount);

        for (int i = 0; i < XGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, topMin   (XGridCount - 1) * (ZGridCount - 2)   1   i, topMin   (XGridCount - 1) * (ZGridCount - 2)   2   i, topMin - ZGridCount - i, topMin - ZGridCount - 1 - i);
        }

        SetQuad(triangles, index   * 6, topMin   (XGridCount - 1) * (ZGridCount - 1), topMin - (ZGridCount - 1) - (XGridCount - 1) - 2, topMin - (ZGridCount - 1) - (XGridCount - 1), topMin - (ZGridCount - 1) - (XGridCount - 1) - 1);

        // 地面中间第一个点
        int btmMin = topMin   (XGridCount - 1) * (ZGridCount - 1)   1;
        SetQuad(triangles, index   * 6, FloorCount - 1, btmMin, 0, 1);

        for (int i = 0; i < XGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, btmMin   i, btmMin   1   i, 1   i, 2   i);
        }

        SetQuad(triangles, index   * 6, btmMin   XGridCount - 2, XGridCount   1, XGridCount - 1, XGridCount);

        for (int i = 0; i < ZGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, FloorCount - 2 - i, btmMin   (XGridCount - 1) * (i   1), FloorCount - 1 - i, btmMin   (XGridCount - 1) * i);
        }

        for (int i = 0; i < ZGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, btmMin   (XGridCount - 1) * (2   i) - 1, XGridCount   2   i, btmMin   (XGridCount - 1) * (1   i) - 1, XGridCount   1   i);
        }

        for (int z = 0; z < ZGridCount - 2; z  )
        {
            for (int x = 0; x < XGridCount - 2; x  , index  )
            {
                SetQuad(triangles, index * 6,
                    btmMin   x   (z   1) * (XGridCount - 1),
                    btmMin   x   (z   1) * (XGridCount - 1)   1,
                    btmMin   x   z * (XGridCount - 1),
                    btmMin   x   z * (XGridCount - 1)   1);
            }
        }

        SetQuad(triangles, index   * 6, FloorCount - ZGridCount, FloorCount - ZGridCount - 1, FloorCount - ZGridCount   1, btmMin   (XGridCount - 1) * (ZGridCount - 2));

        for (int i = 0; i < XGridCount - 2; i  , index  )
        {
            SetQuad(triangles, index * 6, FloorCount - ZGridCount - i - 1, FloorCount - ZGridCount - i - 2, btmMin   (XGridCount - 1) * (ZGridCount - 2)   i, btmMin   (XGridCount - 1) * (ZGridCount - 2)   i   1);
        }

        SetQuad(triangles, index   * 6, ZGridCount   XGridCount   1, ZGridCount   XGridCount, btmMin   (XGridCount - 1) * (ZGridCount - 1) - 1, ZGridCount   XGridCount - 1);

        mesh.triangles = triangles;
    }

    void SetNormal(Mesh mesh)
    {
        Vector3[] normals = new Vector3[VertexCount];
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i  )
        {
            SetNormalPoint(vertices, normals, i);
            if (debug) Gizmos.DrawSphere(transform.position   vertices[i], .07f);
        }
        mesh.normals = normals;
        mesh.vertices = vertices;
    }

    /// <summary>
    /// 构建圆角四边形
    /// </summary>
    void SetNormalPoint(Vector3[] vertices, Vector3[] normals, int i)
    {
        var vertex = vertices[i];
        // 圆心
        var inner = vertex;
        if (vertex.x < Radius)
        {
            inner.x = Radius;
        }
        else if (vertex.x > XSize - Radius)
        {
            inner.x = XSize - Radius;
        }
        if (vertex.y < Radius)
        {
            inner.y = Radius;
        }
        else if (vertex.y > YSize - Radius)
        {
            inner.y = YSize - Radius;
        }
        if (vertex.z < Radius)
        {
            inner.z = Radius;
        }
        else if (vertex.z > ZSize - Radius)
        {
            inner.z = ZSize - Radius;
        }
        normals[i] = (vertex - inner).normalized;
        vertices[i] = normals[i] * Radius   inner;
    }

    /// <summary>
    /// 设置面片
    /// </summary>
    void SetQuad(int[] triangles, int i, int v00, int v10, int v01, int v11)
    {
        triangles[i] = v00;
        triangles[i   1] = v01;
        triangles[i   2] = v11;

        triangles[i   3] = v00;
        triangles[i   4] = v11;
        triangles[i   5] = v10;
    }
学新通

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhbhff
系列文章
更多 icon
同类精品
更多 icon
继续加载