Unity Mesh 生成图形(一)

目录

一、概述

二、获取顶点坐标和索引

三、绘制正方形

1.显示顶点坐标

2.顶点坐标的顺序

3.顶点排序

4.绘制最终效果

结束


一、概述

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

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

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

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

二、获取顶点坐标和索引

在讲解 Mesh 案例之前,这里先做个小案例来演示下 Unity 中模型是怎么渲染出来的,本节的主要作用就是展示 Mesh 中两个重要的知识点:顶点 和 顶点下标,即使看不明白也不要紧,后面会有更详细的案例。

在场景中新建一个 Quad

创建完成后,将 Shading Mode 的默认值 Shaded 改为 Shaded Wireframe

场景中效果如下:

图中可以看到方块中间有一条斜线,一般情况下,这么设置只是为了看模型的顶点,并没有其他作用,还是恢复成默认值吧。

接下来新添加一个脚本 Test1,拖到 Quad 上,代码如下:

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

public class Test1 : MonoBehaviour
{
    void Start()
    {
        //1.获取mesh对象
        Mesh mesh = GetComponent<MeshFilter>().mesh;

        //2.获取mesh的顶点坐标数组
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i++)
        {
            Debug.Log(vertices[i]);
        }

        //3.获取mesh的索引数组
        int[] triangles = mesh.triangles;
        for (int i = 0; i < triangles.Length; i++)
        {
            Debug.Log(triangles[i]);
        }
    }
}

运行后的打印:

注意这里的坐标是水平的

将视野转到背面可以看到,背面是透明的,根本没有渲染

由于正面和背面共用这4个顶点,只要改下顶点的索引就可以让背面同样的渲染了

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

public class Test1 : MonoBehaviour
{
    void Start()
    {
        //1.获取mesh对象
        Mesh mesh = GetComponent<MeshFilter>().mesh;

        //2.获取mesh的顶点坐标数组
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i++)
        {
            Debug.Log(vertices[i]);
        }

        //3.获取mesh的索引数组
        int[] triangles = mesh.triangles;
        for (int i = 0; i < triangles.Length; i++)
        {
            Debug.Log(triangles[i]);
        }

        triangles = new int[12] { 0, 3, 1, 3, 0, 2, 0, 1, 3, 3, 2, 0 };
        mesh.triangles = triangles;
    }
}

效果:

三、绘制正方形

看了上面的案例,如果是第一次接触 Mesh 肯定有很多的疑惑,比如说  triangles 这个变量,它的值是一堆无序的整型数字,为什么要这么写呢?它的作用又是什么呢?

triangles = new int[12] { 0, 3, 1, 3, 0, 2, 0, 1, 3, 3, 2, 0 };

要搞明白这个问题,还是得以各种小案例来慢慢讲解这些知识点。

在默认的场景中,创建一个空物体,取名为 Root,将位置坐标设置为0,并将视角调整为从上往下看(鸟瞰视角),那么在场景中就是这样的:

从场景中可以看到有很多的格子,其中 Transform 的值中 1 代表 1 格,也代表游戏场景中 1 米的距离,在后面的案例中,顶点坐标的位置也是以此作为标准

接下来创建一个脚本 Test3,将其拖到 Root 上。

1.显示顶点坐标

为了理解顶点坐标在三维空间是怎样的,下面我用四个球来表示四个顶点的位置

第一个球的位置为:0,0,0,它所在的位置是世界坐标的零点。

第二个球的位置为:0,1,0

第三个球的位置为:1,0,0

第四个球的位置为:1,1,0

我们分别给这四个球添加材质,颜色按照顺序为:红、绿、蓝、紫,大家可以记一下这几个颜色的顺序,因为后面会涉及到渲染正反面的问题。

这时候场景中如下:

从侧面45°视角看是这样的:

运行后在 Game  视图,排在上面的两个球只显示了一半,为了让三个球显示完整,我将摄像机的位置向后拉了一些,Z 轴设置为 -2,这样就能将四个球完整的显示了。

2.顶点坐标的顺序

由于 Unity 在一般只渲染一个面,顶点坐标的顺序会影响到渲染的是正面还是反面,这对理解 Mesh 是至关重要的,最好去亲自动手操作一遍,加深印象。

下面这个图就是一个平面顶点坐标的顺序,在 Unity 中,一个平面是由两个三角形组合而成的,左边三角形的顶点顺序为:0,1,2,右边的三角形的顶点顺序为:2,1,3,可以理解为一个顺时针的顺序进行排列的

我们先来渲染左边的三角形,那么数组可以这么写:

Vector3[] vertices = new Vector3[]
{
    new Vector3(0, 0, 0), 
    new Vector3(0, 1, 0), 
    new Vector3(1, 0, 0),
};

那么,它的下标应该这么写:

int[] triangles = new int[]{ 0, 1, 2 };

3.顶点排序

如果说顶点 Vector3 坐标需要按照严格的顺序进行排列,那么顶点的下标如果不按照这个顺序会有怎样的效果呢?下面就来测试吧。

首先,先按照正常的顺序:

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

public class Test3 : 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),
        };

        //顶点下标顺序
        int[] triangles = new int[]{ 0, 1, 2 };

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

运行:

从上图可以看到,按照正常的下标顺序,结果是对的,如果将顶点下标的顺序颠倒过来,会发生什么呢?

int[] triangles = new int[]{ 2, 1, 0 };

运行:

这时,正面看不到三角形了,将视角转到反面

反面虽然能看到三角形,但是颜色有点暗。

这其实是灯光的问题,默认的全局环境光位置在正面,所以背面的光线就比较暗。

我们先关闭编辑器的运行,将灯光再复制一份

将坐标向后拉一点,为了就是让灯光照到背面

再将旋转角度设置为 150°

再次运行后,从背面也能看到和正面一样的效果了

在这里,下标顺序换成 2,0,1 也能正常的渲染

int[] triangles = new int[]{ 2, 0, 1 };

效果:

继续换一个,换成 1,2,0 效果也是一样的。

int[] triangles = new int[]{ 1, 2, 0 };

运行:

虽然下标顺序打乱也能实现效果,但是并不推荐这么做,要想渲染一个正方形,最好是按照:0,1,2,2,1,3 这种顺序进行渲染。

4.绘制最终效果

理解了上面的知识点,想要绘制一个正方形就简单了,代码:

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

public class Test3 : 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),
        };

        //顶点下标顺序
        int[] triangles = new int[] { 0, 1, 2, 2, 1, 3 };

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

        Debug.Log(string.Join(",", triangles));
    }
}

效果:

继续将 Shading Mode --> Shaded 改为 Shaded Wireframe 

就能看到模型对应的三角形面和中间的那条斜线了,现在回到上面的第二章节看看,Quad 和 当前案例中的斜线的方向是不是不一样呢?

结束

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

end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熊思宇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值