【Unity】程序创建Mesh(一)Mesh网格、代码创建模型、顶点信息、三角形信息、MeshFilter、MeshRenderer


Mesh(网格)

Mesh在Unity中是一个核心的组件,被称为网格组件,它主要用于表示3D几何体的数据结构。Mesh由顶点、三角形面以及可选的材质等组成,这些元素共同构建了3D模型的基础。

在Unity中,Mesh的功能非常强大且多样化。它不仅可以用来创建3D模型、绘制几何体、渲染场景,还支持多种功能,如顶点颜色、UV贴图、法线贴图等,这使得创建更加真实、生动的3D模型成为可能,同时在渲染时也能提供更为逼真的效果。此外,Mesh还可以用于碰撞检测和光照计算,这对于游戏和虚拟现实应用的开发至关重要。

从构成上来看,Mesh主要包括但不限于下列内容:

  • 顶点坐标数组;
  • 顶点在UV坐标系中的位置信息数组;
  • 三角形顶点索引数组

这些元素共同定义了3D模型的形状和结构。此外,Mesh Filter组件用于获取和管理模型的网格数据,而Mesh Renderer组件则负责将网格数据渲染成可视化的3D模型。

在Unity中,我们可以通过编辑器或编程方式来创建和修改Mesh。Unity编辑器中内置了一些简单的几何体,如立方体(Cube)、球体(Sphere)、胶囊体(Capsule)、圆柱体(Cylinder)等。而通过编程方式,我们可以使用C#等语言动态创建和修改Mesh,例如通过定义顶点的坐标、法线、纹理坐标等信息来生成新的Mesh。

总的来说,Mesh在Unity中扮演着至关重要的角色,是构建3D场景和模型的基础元素。无论是游戏开发、虚拟现实应用还是其他3D图形相关的项目,Mesh都是不可或缺的一部分。

在编辑器中创建Mesh

在编辑器内编辑场景时,通过Hierarchy面板中邮件菜单可以创建一些基本的Mesh网格,如下图:
在这里插入图片描述

在代码中创建Mesh

要在代码中创建一个网格,我们首先需要创建一个Mesh对象,并定义了它的顶点坐标 vertices ,三角形面索引 triangles ,UV坐标 uvs (UV坐标通常用于纹理映射,可选),以及法线信息 normals(可选)。代码示例如下:

public class TestCreateMeshBehaviour : MonoBehaviour
{
    private Mesh mesh;
    private MeshFilter meshFilter;
    public Material mat;

    void Start()
    {
        // 创建一个新的网格对象
        mesh = new Mesh();

        // 设置网格的顶点
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 0, 10),
            new Vector3(10, 0, 10),
            new Vector3(10, 0, 0)
        };

        mesh.vertices = vertices;

        // 设置网格的三角形(每个三角形由三个顶点的索引构成)
        int[] triangles = new int[]
        {
            0, 1, 2,
            2, 3, 0
        };

        mesh.triangles = triangles;

        // 设置网格的法线(可选,但通常用于光照计算)
        Vector3[] normals = new Vector3[]
        {
            Vector3.up,
            Vector3.up,
            Vector3.up,
            Vector3.up
        };

        mesh.normals = normals;

        // 设置网格的UV坐标(可选,但通常用于纹理映射)
        Vector2[] uvs = new Vector2[]
        {
            new Vector2(0, 0),
            new Vector2(1, 0),
            new Vector2(1, 1),
            new Vector2(0, 1)
        };

        mesh.uv = uvs;

        // 创建一个网格过滤器组件,并将网格分配给它
        meshFilter = GetComponent<MeshFilter>();
        if (!meshFilter)
        {
            meshFilter = gameObject.AddComponent<MeshFilter>();
        }

        meshFilter.mesh = mesh;

        // 创建一个网格渲染器组件,以便在场景中显示网格
        MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
        if (!meshRenderer)
        {
            meshRenderer = gameObject.AddComponent<MeshRenderer>();
        }

        meshRenderer.material = mat;
    }
}

指定一张纹理后,生成的Mesh如下图(我放了4个Cube用来标识位置):
在这里插入图片描述

顶点信息

Mesh的组成离不开点和面,我们想要创建一个网格首先要提供的就是顶点信息。下面代码中提供了四个顶点,形成了一个边长为10的正方形。

// 设置网格的顶点
Vector3[] vertices = new Vector3[]
{
    new Vector3(0, 0, 0),
    new Vector3(0, 0, 10),
    new Vector3(10, 0, 10),
    new Vector3(10, 0, 0)
};
mesh.vertices = vertices;

点位信息如图所示:
在这里插入图片描述

注意:此时只是有了点的信息,还并未形成平面。

在定义Mesh的顶点信息vertices时,需要注意一些关键点,以确保Mesh的正确创建和渲染。以下是一些建议和注意事项:

  1. 坐标系统:
    • Unity使用的是左手坐标系,其中X轴向右,Y轴向上,Z轴指向屏幕内部。
    • 确保你的顶点坐标符合这个坐标系,否则Mesh可能会以不正确的方式渲染或放置。
  2. 单位:
    • Unity中默认使用的单位是米(m),因此你应该根据你的项目需求选择合适的单位。
    • 如果你从其他软件或格式导入模型,需要确保单位的一致性。
  3. 顺序和数量:
    • 顶点的顺序对于Mesh的渲染至关重要,特别是在定义三角形面时。
    • 确保你的顶点数量正确,且与后面定义的三角形索引数相匹配。
  4. 精度:
    • 使用适当的精度来定义顶点坐标,避免不必要的浮点误差。
    • 对于需要高精度或特定形状的Mesh,可能需要使用双精度(double)来计算坐标,但最终应转换为单精度(float)以匹配Unity的Vector3类型。
  5. 共享顶点:
    • 在可能的情况下,共享相同的顶点以减少Mesh的复杂度和内存占用。例如,在创建立方体时,相对的顶点(如四个角的顶点)实际上可以共享相同的坐标。

三角形信息

想要形成正常的网格,我们还需要将刚才提供的点连起来,形成一个个面。这时候就需要提供第二类信息,三角形信息。代码如下:

// 设置网格的三角形(每个三角形由三个顶点的索引构成)
int[] triangles = new int[]
{
    0, 1, 2,// 第一个面
    2, 3, 0// 第二个面
};
mesh.triangles = triangles;

首先三角形信息的数据格式是一个 int 类型的数组,数组中的每个元素就是三角形的一个顶点(顶点是可以共用的),这个数组每三个元素形成一个面,所以数组的长度通常是3的倍数。注意,Unity的Mesh系统主要是基于三角形的,它并不直接支持多边形的表示。然而,你可以通过组合多个三角形来近似表示多边形。例如,一个四边形可以由两个三角形组成,一个五边形可以由三个三角形组成,以此类推。在这种情况下,你仍然需要确保triangles数组的元素数量是3的倍数,并且正确地设置顶点索引以表示这些三角形的组合。

设置三角形信息的重点在于顺序,只有顺序对了,网格才会以正常的方式展现,不然就会出现反面甚至错面。

三角形设置顺序示意图:
在这里插入图片描述

顶点顺序与三角形朝向

  1. 顺时针与逆时针:
    Unity使用逆时针(counter-clockwise, CCW)的顶点顺序来表示三角形的正面。这意味着,如果你从三角形的外部观察(外部指的是三角形面向观察者的方向,也可以理解为从这个三角形的背面看三角形),此时顶点的顺序应该是逆时针的。如果顶点顺序是顺时针的,那么三角形可能会被视为背面,并可能被背面剔除(如果启用了该功能)。
    当我们谈论三角形的顶点顺序和朝向时,我们关心的是三角形面相对于观察者的方向。具体来说,如果我们按照逆时针顺序(从三角形的一个顶点开始,沿着边缘到下一个顶点,再到下一个,最后回到起始顶点)来定义三角形的顶点,那么当观察者站在三角形的“外部”时,这个面会朝向观察者,我们称之为“正面”或“前向面”。相反,如果顶点顺序是顺时针的,那么当观察者站在三角形的“外部”时,这个面会背向观察者,我们称之为“背面”或“后向面”。

  2. 法线方向:
    三角形的法线方向是由顶点的顺序决定的。逆时针顺序会产生指向观察者的法线,而顺时针顺序则会产生背向观察者的法线。确保你的法线方向与你想要的光照和阴影效果一致。

保证点的顺序正确

  1. 可视化检查:在Unity的Scene视图中,你可以使用Wireframe模式来查看Mesh的三角形边。这可以帮助你直观地检查顶点的顺序是否正确。
    在这里插入图片描述

  2. 使用Gizmos:你可以编写自定义的Gizmos脚本来在Scene视图中绘制顶点和边,这有助于在开发过程中进行调试。

  3. 代码中的逻辑:在编写代码设置顶点时,保持一致的逻辑顺序。例如,对于立方体的每个面,你可以始终按照相同的顺序(如左下角、右下角、左上角)来设置顶点。

  4. 参考其他资源:查看Unity的官方文档、教程或社区中的示例代码,了解如何设置顶点的顺序。这些资源通常会提供正确的顶点顺序示例。

调试与测试

  1. 渲染测试:在设置了Mesh后,立即在Unity编辑器中进行渲染测试。观察Mesh的朝向、光照和阴影效果,确保它们符合你的预期。
  2. 背面剔除:启用和禁用背面剔除来检查三角形的朝向是否正确。如果启用了背面剔除但某些面仍然可见,那么可能是这些面的顶点顺序设置错误。
  3. 法线可视化:在Unity中,你可以使用法线可视化功能来查看Mesh的每个面的法线方向。这可以帮助你快速识别哪些面的顶点顺序需要调整。不过Unity没有提供默认的功能,需要写Shader或者使用插件来实现法线可视化。

MeshFilter(网格过滤器)

Unity中的 MeshFilter 是一个组件,它用于从资源中获取网格(Mesh)并将其传递给网格渲染器( MeshRenderer ),以便在屏幕上渲染该网格。MeshFilter 本身并不直接参与渲染过程,而是作为一个中介,将Mesh数据传递给 MeshRenderer 。也就是说,GameObject 并不是直接引用了Mesh,因为Mesh并不是组件。一个游戏对象只能通过 MeshFilter 这类的组件来使用 Mesh 。

虽然叫Filter,但是这个组件本身其实并不起过滤器的作用,实际上这个组件更像是一个选择器或是一个持有者,用于将Mesh和GameObject关联起来。

MeshRenderer(网格渲染器)

MeshRenderer是Unity中的一个组件,属于UnityEngine命名空间下的一个类,它继承自Renderer类。MeshRenderer的主要作用是渲染由MeshFilter或TextMesh插入的网格。它根据物体的Transform组件的定义位置,从网格过滤器(Mesh Filter)获取几何形状,并在该位置进行渲染。

关于 MeshRenderer 的细节内容,我会在下一篇文章中做详细的讲解,具体请参看文档下面的目录章节。


更多内容请查看总目录【Unity】Unity学习笔记目录整理

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值