Unity Mesh 生成图形(二)

一、概述

Unity 的 Mesh 是用于表示三维物体的网格数据结构。它是由一系列顶点和三角形组成的网格,用于描述物体的形状和外观。

Mesh 是由顶点、三角形和其他相关信息组成的,它用于在 Unity 中创建和渲染三维对象。顶点是网格的基本构建单元,它们定义了物体的形状,每个顶点都有三维坐标和其他可选属性,如法线、 UV 坐标和颜色。三角形则是由三个顶点组成的,它们定义了网格表面的平面,形成了物体的可见表面。

Mesh 类提供了许多方法来操作顶点和三角形,例如添加、删除、移动顶点和三角形,以及调整网格的大小和形状。这些操作可以在 Unity 编辑器中进行,也可以在代码中通过使用 Unity 的 API 来实现。

使用 Mesh 可以创建各种类型的三维对象,如静态物体、动态物体、碰撞检测对象等。在 Unity 中,Mesh 还支持各种纹理和光照技术,以便更好地渲染物体的外观和效果。
 

在上一篇文章中,我介绍了 Unity 单个面 Mesh 的绘制方法,本章继续讲解 Mesh 多个面的绘制方法,参考:

Unity Mesh 生成图形(一)-CSDN博客

二、绘制立方体

Mesh 多个面的绘制,最简单的案例就是立方体了,在上一篇文章中,我用到的是 4 个顶点来绘制一个面,那个立方体 4 个面就是 8 个顶点了,先给这 8 个顶点用球型标记出来。

在场景中加入 8 个球,并给每个球设置一个颜色

对应的顶点是:

根据上图的序号,这 8 个球对应的位置是:

第1个球:0,0,0

第2个球:0,1,0

第3个球:1,0,0

第4个球:1,1,0

第5个球:1,0,1

第6个球:1,1,1

第7个球:0,0,1

第8个球:0,1,1

所以他们对应的顶点是:

//顶点坐标
Vector3[] vertices = new Vector3[]
{
    new Vector3(0, 0, 0),
    new Vector3(0, 1, 0),
    new Vector3(1, 0, 0),
    new Vector3(1, 1, 0),
    new Vector3(1, 0, 1),
    new Vector3(1, 1, 1),
    new Vector3(0, 0, 1),
    new Vector3(0, 1, 1),
};

虽然有了多个面,三角形的画法不变,唯一要改变的是顶点的下标,参考下图:

我们先来画第2个面试试

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

public class Test4 : MonoBehaviour
{
    void Start()
    {
        GameObject obj = new GameObject();
        obj.name = "TestMesh";
        obj.transform.position = Vector3.zero;

        //网格渲染器
        MeshRenderer meshRenderer = obj.AddComponent<MeshRenderer>();
        meshRenderer.material = new Material(meshRenderer.material);
        //网格过滤器
        MeshFilter meshFilter = obj.AddComponent<MeshFilter>();

        //顶点坐标
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
        };
        //顶点下标顺序
        int[] triangles = new int[] 
        { 
            //第1个面
            //0, 1, 2, 
            //2, 1, 3,
            //第二个面
            2, 3, 4,
            4, 3, 5,
        };

        //用列表数据创建网格 Mesh 对象
        Mesh mesh = new Mesh();
        mesh.name = "MestTest";
        //设置顶点
        mesh.SetVertices(vertices);
        //设置顶点索引
        mesh.triangles = triangles;
        // 自动计算法线
        mesh.RecalculateNormals();
        // 自动计算物体的整体边界
        mesh.RecalculateBounds();
        // 将mesh对象赋值给网格过滤器,就完成了
        meshFilter.mesh = mesh;
    }
}

由于 Unity 只渲染正面,摄像机的视角,默认指向这个渲染平面的背面,所以是看不到的,要转一下视角,效果:

知道了原理就很容易了,现在把四个面先画出来

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

public class Test4 : MonoBehaviour
{
    void Start()
    {
        GameObject obj = new GameObject();
        obj.name = "TestMesh";
        obj.transform.position = Vector3.zero;

        //网格渲染器
        MeshRenderer meshRenderer = obj.AddComponent<MeshRenderer>();
        meshRenderer.material = new Material(meshRenderer.material);
        //网格过滤器
        MeshFilter meshFilter = obj.AddComponent<MeshFilter>();

        //顶点坐标
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
        };
        //顶点下标顺序
        int[] triangles = new int[] 
        { 
            //第1个面
            0, 1, 2,
            2, 1, 3,
            //第2个面
            2, 3, 4,
            4, 3, 5,
            //第3个面
            4, 5, 6,
            6, 5, 7,
            //第4个面
            6, 7, 0,
            0, 7, 1
        };

        //用列表数据创建网格 Mesh 对象
        Mesh mesh = new Mesh();
        mesh.name = "MestTest";
        //设置顶点
        mesh.SetVertices(vertices);
        //设置顶点索引
        mesh.triangles = triangles;
        // 自动计算法线
        mesh.RecalculateNormals();
        // 自动计算物体的整体边界
        mesh.RecalculateBounds();
        // 将mesh对象赋值给网格过滤器,就完成了
        meshFilter.mesh = mesh;
    }
}

效果:

由于后面两个面是背面,所以没渲染出来,只要把视角转到另一边,就可以看到了

现在把顶部和底部的面加上去吧

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

public class Test4 : MonoBehaviour
{
    void Start()
    {
        GameObject obj = new GameObject();
        obj.name = "TestMesh";
        obj.transform.position = Vector3.zero;

        //网格渲染器
        MeshRenderer meshRenderer = obj.AddComponent<MeshRenderer>();
        meshRenderer.material = new Material(meshRenderer.material);
        //网格过滤器
        MeshFilter meshFilter = obj.AddComponent<MeshFilter>();

        //顶点坐标
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
        };
        //顶点下标顺序
        int[] triangles = new int[] 
        { 
            //第1个面
            0, 1, 2,
            2, 1, 3,
            //第2个面
            2, 3, 4,
            4, 3, 5,
            //第3个面
            4, 5, 6,
            6, 5, 7,
            //第4个面
            6, 7, 0,
            0, 7, 1,
            //顶部
            1, 7, 3,
            3, 7, 5,
            //底部
            6, 0, 4,
            4, 0, 2
        };

        //用列表数据创建网格 Mesh 对象
        Mesh mesh = new Mesh();
        mesh.name = "MestTest";
        //设置顶点
        mesh.SetVertices(vertices);
        //设置顶点索引
        mesh.triangles = triangles;
        // 自动计算法线
        mesh.RecalculateNormals();
        // 自动计算物体的整体边界
        mesh.RecalculateBounds();
        // 将mesh对象赋值给网格过滤器,就完成了
        meshFilter.mesh = mesh;
    }
}

底部由于需要反过来渲染,所以方向也要反着写,效果如下:

加上 着色线框 好像看的更清楚一些

但是立方体的光影好像有点问题,用 Unity 自带的 Cube 就没有这个问题。

下面创建一个立方体来看看 Unity 中的 Cube 有什么不同

添加一个脚本 Test5,并将其拖拽到 Cube 组件上

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

public class Test5 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        MeshFilter meshFilter = GetComponent<MeshFilter>();
        if (meshFilter != null)
        {
            Mesh mesh = meshFilter.sharedMesh;
            Debug.Log("Vertex Count: " + mesh.vertexCount);
        }
    }
}

运行:

可以看到,默认的 Cube 有 24 个顶点,而我生成的立方体只有 8 个顶点,两个构建方式应该不一样。

其实解决光影的问题也很简单,改下材质的类型,也是可以解决光影问题的

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

public class Test4 : MonoBehaviour
{
    void Start()
    {
        GameObject obj = new GameObject();
        obj.name = "TestMesh";
        obj.transform.position = Vector3.zero;

        //网格渲染器
        MeshRenderer meshRenderer = obj.AddComponent<MeshRenderer>();
        //创建无光影材质
        Material material = new Material(Shader.Find("Unlit/Color"));
        //设置材质颜色为白色
        material.color = Color.white; 
        meshRenderer.material = material;
        //网格过滤器
        MeshFilter meshFilter = obj.AddComponent<MeshFilter>();
        //顶点坐标
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0),
            new Vector3(1, 0, 0),
            new Vector3(1, 1, 0),
            new Vector3(1, 0, 1),
            new Vector3(1, 1, 1),
            new Vector3(0, 0, 1),
            new Vector3(0, 1, 1),
        };
        //顶点下标顺序
        int[] triangles = new int[] 
        { 
            //第1个面
            0, 1, 2,
            2, 1, 3,
            //第2个面
            2, 3, 4,
            4, 3, 5,
            //第3个面
            4, 5, 6,
            6, 5, 7,
            //第4个面
            6, 7, 0,
            0, 7, 1,
            //顶部
            1, 7, 3,
            3, 7, 5,
            //底部
            6, 0, 4,
            4, 0, 2
        };

        //用列表数据创建网格 Mesh 对象
        Mesh mesh = new Mesh();
        mesh.name = "MestTest";
        //设置顶点
        mesh.SetVertices(vertices);
        //设置顶点索引
        mesh.triangles = triangles;
        // 自动计算法线
        mesh.RecalculateNormals();
        // 自动计算物体的整体边界
        mesh.RecalculateBounds();
        // 将mesh对象赋值给网格过滤器,就完成了
        meshFilter.mesh = mesh;
    }
}

效果:

结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊思宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值