Unity网格篇Mesh(一)

news2025/2/7 15:16:26

Unity网格篇Mesh(一)

  • 本文的目标
  • 1.渲染
    • 仔细看下面的图你会发现,锯齿状
  • 2.创建网格顶点
    • 4 x 2网格
    • 网格的顶点
  • 3.创建网格
    • 网格只在Play模式下显示
    • 逆时针和顺时针三角形
    • 第一个三角面
    • 一个四边形由两个三角面组成
    • 第一个四边形
    • 填充剩余网格
  • 接下一篇文章

本文的目标

  • 创建网格坐标
  • 使用携程计算他们位置
  • 利用三角形确定一个面
  • 自动生成法线
  • 添加纹理坐标和切线

这篇教程中我们将利用顶点和三角面创建一个网格。
在这里插入图片描述
原英文篇

1.渲染

  • 如果你想要在Unity显示一些东西,你需要一个网格。他可以是一个3D模型从另一个程序倒入的(3dmax,maya)。它也可以是程序生成的网格。它可以是精灵、UI元素或者是粒子系统,它们一样都是使用unity网格,甚至是屏幕特效也是使用网格渲染的。
  • 什么是网格?概念上来说网格由图形硬件(GPU Graphics Processing Unit图形处理单元)构成来绘制复杂的材料。它至少包含一组在3D空间中位置明确的点再加一组三角形构成。
  • 最基础的2D图形,由点连接组成,面上的三角形就是此类网格的代表。
  • 因为三角形是平坦的并且拥有直边,所以他们可以完美地被用来显示平坦的和连续的东西,像一个立方体的面孔。曲面的或者是圆的面只能被大量小的三角形来接近组成。如果三角面足够的小(不大于一个像素),那么你就不会感觉曲面和圆是由三角面组成的。从实时性能角度来讲通常这种情况是不可能的,所以我们总能够在面的某个程度上发现锯齿。

仔细看下面的图你会发现,锯齿状

在这里插入图片描述
网格图如下
在这里插入图片描述
Unity自带的胶囊体,立方体和球体 着色vs线框

如何显示线框
再视图左上角选择Display Mode,前三个选项分别是Shaded(着色)、Wireframe(线框)和Shaded
Wireframe着色并带着线框

  • 如果你想要展示一个3D游戏物体,它必须拥有两个组件。
  • MeshFilter这个组件记录了你想要展示的网格数据
  • MeshRenderer使用这个组件告诉网格如何渲染,比如使用哪个材质球,是否接受阴影和其他设置。
    在这里插入图片描述

为什么是一个材质球数组?
一个网格渲染器可以有多个材质球,它通常被用来渲染多组三角面,也成为子网格。它通常在外界导入的模型中使用,本片文章不使用多个材质球。

  • 你可以完全改变网格的显示效果通过调整材质球。Unity默认的材质球是简单的白色立体。你可以自己创建一个新的材质球通过Assets->Create->Material并拖拽到你的游戏物体上来代替它。新的材质球默认为Unity Standard Shader,你可以调节这个材质球的属性得到你想要的模型表现,如果你会写Shader你可以创建自己的Shader。
  • 一个快速添加细节的方法是给你的网格提供一个反射贴图,这个纹理描绘了材质球的基础颜色。当然我们需要知道如何投射纹理到网格的三角面上。这需要添加2D纹理坐标到定点上。这二维纹理空间被称为U和V,也是常说的UV坐标。UV坐标通常在(0,0)到(1,1)之间,它覆盖了整个纹理。超出范围的坐标将造成clamped或者Tiling平铺的效果,这取决于纹理设置。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2.创建网格顶点

如何创建自己的网格?
通过创建一个简单的矩形网格来了解一下。这个网格将包括方形瓷砖(单位长度的四边形)。创建一个新的C#脚本并加入水平和垂直尺寸。

using UnityEngine;
using System.Collections; //协程使用

//依赖组件(使用时当该脚本挂载到游戏对象身上会自动添加下面两个组件,作为该脚本的依赖项)
[RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))] 
public class Grid : MonoBehaviour  {

    /// <summary>
    /// 矩阵x,y位置
    /// </summary>
    public int xSize, ySize;
}

这时我们创建一个空物体并挂在组件,它将自动同时添加MeshFilter和MeshRenderer组件。设置MeshRender的材质并确保MeshFilter的mesh属性为未定义。并设置网格尺寸为x = 10和 y = 5。

在这里插入图片描述

  • 现在我们先考虑定点位置稍后处理三角面序号。我们需要一个数组存储3D顶点位置。顶点的数量取决于网格的尺寸。我们需要获取每个四边形的顶点,但是相邻的四边形可以共享相同的顶点。所以每个维度上顶点数量比网格数多一个。
    在这里插入图片描述

4 x 2网格

    /// <summary>
    /// 网格顶点坐标
    /// </summary>
    private Vector3[] vertices;

    private void Generate()
    {
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
    }
  • 我们在场景中绘制这些顶点,这样我们就可以正确地核对他们的位置。利用OnDrawGizmos方法来挥之顶点的位置,利用OnDrawGizmos在每个顶点绘制一个小球。
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.black;
		if (vertices == null) return;
        for (int i = 0; i < vertices.Length; i++)
        {
            Gizmos.DrawSphere(vertices[i],0.1f);
        }
    }
  • 什么是Gizmos?
  • 在编辑器模式下Gizmos可以提供可视化的提示。他们只在Scene场景中显示不在PLay模式下显示,但是你可以通过工具栏调整它们。Gizmos公共类允许你绘制图表,线条,和其他的东西。
  • Gizmos在OnDrawGizmos方法中执行绘制,它被Unity编辑器自动调用。另一个可选的方法是OnDrawGizmosSelected,他只能被可选的对象调用。
  • 上面的没有画出来是因为Vector3数组为空,所以我们将其Generate方法修改一下
    private void Generate()
    {
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        for (int i = 0, y = 0; y <= ySize; y++)
        {
            for (int x = 0; x <= xSize; x++, i++)
            {
                vertices[i] = new Vector3(x, y);
            }
        }
    }
  • 生成真实的网格在物理被唤醒的时候,Awake方法将在我们游戏运行模式时自动调用。
  private void Awake()
    {
        Generate();
    }

在这里插入图片描述

网格的顶点

  • 为什么在Gizmos绘制不能被移动?
  • Gizmos直接使用世界坐标绘制,不是使用对象的本地坐标系,如果你想遵循对象Transform组件,你必须声明使用transform.TransformPoint(vertices[i])代替vertices[i].
  • 现在我们可以看见这些顶点,但是他们生成的顺序我们不能明显地看出来。我们可以使用颜色来标识,但是我们也可以使用协程减慢这个过程的速度。
    观察顶点逐个生成

3.创建网格

  • 现在我们知道顶点的位置是正确的,接下来我们就处理真正的网格。初次之外我们想要我们的组件持有这些顶点,我们必须要把顶点指定到MeshFilter.mesh中。我们处理过顶点之后,就可以网格存储在MeshFilter中。修改如下

    private Mesh mesh;

    private IEnumerator Generate()
    {
        WaitForSeconds wait = new WaitForSeconds(0.05f);
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "Procedual Grid";
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        for (int i = 0, y = 0; y <= ySize; y++)
        {
            for (int x = 0; x <= xSize; x++, i++)
            {
                vertices[i] = new Vector3(x, y);
                yield return wait;
            }
        }

        mesh.vertices = vertices;
    }
  • 如何让组件持有网格?
  • 大家可能发现MeshFilter组件的Mesh属性只有在Play模式下才能看得到,在Editor模式下是不存在的,这里我们需要如何才能将网格持久化保存呢。持久化

网格只在Play模式下显示

  • 到目前,在Play模式下我们可以持有一个网格,但是它依旧是不可见的,因为我们并没有给它任何三角面。三角面由定点数组索引决定。每一个三角面有三个顶点,三个连续的顶点绘制了一个三角形,让我们来先绘制第一个三角面。修改如下
    private IEnumerator Generate()
    {
        WaitForSeconds wait = new WaitForSeconds(0.05f);
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "Procedual Grid";
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        for (int i = 0, y = 0; y <= ySize; y++)
        {
            for (int x = 0; x <= xSize; x++, i++)
            {
                vertices[i] = new Vector3(x, y);
                yield return wait;
            }
        }

        mesh.vertices = vertices;
        DrawFaces(mesh);
    }

    /// <summary>
    /// 绘制三角面
    /// </summary>
    private void DrawFaces(Mesh mh)
    {
        int[] triangles = new int[3];
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;
        mesh.triangles = triangles;
    }
  • 这时候我们发现绘制了一个三角面,但是由于这三个顶点在一条直线上,所以生成了一个失败的三角形,它是不可见的一条线。如下图
    在这里插入图片描述
  • 第三个顶点我们将其转到下一行的第一个顶点。
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = xSize + 1;

在这里插入图片描述

  • 通过以上操作,我们绘制了一个三角形,但是它只能在一个方向可见。这种情况下,只有Z轴的反方向可见,所以你可能需要旋转视角才能看得到。
    在这里插入图片描述
  • 三角形的哪一面可见是由定点序号的方向来确定的。默认情况下,如果定点顺序是顺时针方向的话那么三角形就是正面可见。逆时针(就是逆屏幕方向)的三角形是被抛弃的,所以我们不必花费时间去渲染这部分定点,以为他们通常都是不可见的。
    在这里插入图片描述

逆时针和顺时针三角形

  • 所以为了实线从Z轴负方向到正方向可见,我们必须改变顺序相反的顶点的位置。我们交换后两个顶点的序号即可。
        triangles[0] = 0;
        triangles[1] = xSize + 1;
        triangles[2] = 1;

在这里插入图片描述

第一个三角面

  • 现在我们绘制了一个三角面只覆盖了一个四方瓦片的一半,为了覆盖整个瓦片,我们需要第二个三角形面。
int[] triangles = new int[6];
triangles[0] = 0;
triangles[1] = xSize + 1;
triangles[2] = 1;
triangles[3] = 1;
triangles[4] = xSize + 1;
triangles[5] = xSize + 2;

在这里插入图片描述

一个四边形由两个三角面组成

  • 既然这些顶点共用两个顶点,我们就可以减少我们代码的行数,明确地提到每个顶点索引只有一次。
triangles[0] = 0;
triangles[3] = triangles[2] = 1;
triangles[4] = triangles[1] = xSize + 1;
triangles[5] = xSize + 2;

在这里插入图片描述
在这里插入图片描述

第一个四边形

  • 我们可以通过循环来创建剩余第一行的瓦片。尽管我们遍历所有的顶点和三角面序号,但是我们必须要保证顶点和三角面序号是按照顺序的。我们把Yield代码的声明放到循环里,我们就不需要等待顶点的出现了。

    private IEnumerator Generate()
    {
        WaitForSeconds wait = new WaitForSeconds(0.05f);
        GetComponent<MeshFilter>().mesh = mesh = new Mesh();
        mesh.name = "Procedual Grid";
        vertices = new Vector3[(xSize + 1) * (ySize + 1)];
        for (int i = 0, y = 0; y <= ySize; y++)
        {
            for (int x = 0; x <= xSize; x++, i++)
            {
                vertices[i] = new Vector3(x, y);
                yield return wait;
            }
        }

        mesh.vertices = vertices;

        int[] triangles = new int[6 * xSize];
        for (int ti = 0, vi = 0, x = 0; x < xSize; x++, ti += 6, vi++)
        {
            triangles[ti] = vi;
            triangles[ti + 3] = triangles[ti + 2] = vi + 1;
            triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
            triangles[ti + 5] = vi + xSize + 2;
            yield return wait;
        }
        mesh.triangles = triangles;
        yield return wait;
    }
  • 现在,Gizmos可以立刻渲染出顶点,并且所有的三角面在一段时间后统一出现。要想看到瓦片一个接一个的出现,我们必须每次循环都刷新网格代替掉执行完所有循环刷新。
mesh.triangles = triangles;
yield return wait;

填充剩余网格

  • 正如你所能看到的,所有的网格都被三角面填充,每一行都是同时填充,因为我们使用了协程。如果你对想过感到满意,你可以移除掉所有的协程代码,这样网格创建就没有任何的延迟了。
private void Awake () 
{
    Generate();
}

private void Generate () 
{
    GetComponent<MeshFilter>().mesh = mesh = new Mesh();
    mesh.name = "Procedural Grid";

    vertices = new Vector3[(xSize + 1) * (ySize + 1)];
    for (int i = 0, y = 0; y <= ySize; y++) {
        for (int x = 0; x <= xSize; x++, i++) {
            vertices[i] = new Vector3(x, y);
        }
    }
    mesh.vertices = vertices;

    int[] triangles = new int[xSize * ySize * 6];
    for (int ti = 0, vi = 0, y = 0; y < ySize; y++, vi++) {
        for (int x = 0; x < xSize; x++, ti += 6, vi++) {
            triangles[ti] = vi;
            triangles[ti + 3] = triangles[ti + 2] = vi + 1;
            triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1;
            triangles[ti + 5] = vi + xSize + 2;
        }
    }
    mesh.triangles = triangles;
}
  • 为什么不使用单个四边形?
  • 当我们创建一个平面矩形,我们可以仅仅使用两个三角面。这没有问题。但是更多的顶点结构也可以提供更多的控制和表现。这里也只是一个实验!
    在这里插入图片描述在这里插入图片描述

接下一篇文章

Unity网格篇Mesh(一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1336379.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue使用Element表格Table设置所有单元格内容居中对齐

为单个列的单元格设置居中对齐代码如下&#xff1a; <el-table-columnprop"productInfo.productName"label"中文名"width"100"align"center"></el-table-column>需要设置el-table-column标签里面的属性设置为align"c…

Jenkins Tutorial

什么是Jenkins Jenkins是一个自动化平台&#xff0c;它允许你使用pipelines去部署应用。它也可以自动化其他任务。 BUILDTESTDEPLOYMENT Jenkins 架构 首先&#xff0c;你拥有一个Master Server&#xff0c;它控制pipelines和安排Build到你的Agent上&#xff1b; 其次&…

除法计算器 C语言xdoj48

问题描述 小明的弟弟刚开始学习除法&#xff0c;为了检查弟弟的计算结果是否正确&#xff0c;小明决定设计一个简单计算器程序来验算。 输入说明 输入数据由四个整数m&#xff0c;n&#xff0c;q&#xff0c;r构成&#xff0c;m为被除数&#xff0c;n为除数&#xff0c…

JVM GC 算法原理概述

对于JVM的垃圾收集&#xff08;GC&#xff09;&#xff0c;这是一个作为Java开发者必须了解的内容&#xff0c;那么&#xff0c;我们需要去了解哪些内容呢&#xff0c;其实&#xff0c;GC主要是解决下面的三个问题&#xff1a; 哪些内存需要回收&#xff1f; 什么时候回收&…

Explain分析——索引优化实践

欢迎大家关注我的微信公众号&#xff1a; 本文通过Explain分析进行索引优化&#xff0c;需要对Explain工具有一定的了解。可以先学习Explain详解之后再进行本文的学习。 传送门&#xff1a;Explain详解 示例表&#xff1a; CREATE TABLE employees (id int(11) NOT NULL AUT…

[RL1]深度强化学习基础

一、强化学习 强化学习(reinforce learning, RL)的本质是互动学习&#xff0c;即让智能体与其外界环境进行交互。智能体根据自己每次感知到的外界环境状态来选择相应的动作&#xff0c;以对环境进行响应&#xff0c;然后观测该动作所造成的结果&#xff0c;并根据结果来调整自身…

docker安装入门及redis,minio,rabbitmq应用安装

部分笔记来自黑马课堂&#xff1a;【黑马程序员Docker快速入门到项目部署&#xff0c;MySQL部署Nginx部署docker自定义镜像DockerCompose项目实战一套搞定-哔哩哔哩】 https://b23.tv/niWEhEF 一、什么是docker&#xff1a; 快速构建、运行、管理应用的工具。--帮助我们快速部…

毕业首选 | CCF推荐1区SCI,IF:6.0,Elsevier出版社,最快仅1个月Accept!

【SciencePub学术】本期&#xff0c;小编给大家解析的是一本Elsevier旗下、CCF-C类、影响因子为6.0的中科院3区SCI。其详情如下&#xff1a; 期刊简介 COMPUTER COMMUNICATIONS ISSN&#xff1a;0140-3664 E-ISSN&#xff1a;1873-703X IF&#xff08;2022&#xff09;&a…

101、nerfstudio——ScaleAndShiftInvariantLoss

github 归一化深度图约束nerf未归一化深度重建 class ScaleAndShiftInvariantLoss(nn.Module):"""Scale and shift invariant loss as described in"Towards Robust Monocular Depth Estimation: Mixing Datasets for Zero-shot Cross-dataset Transfer&…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Toast组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Toast组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Toast组件 Toast 的应用场景也非常广泛&#xff0c;比如网络请求出错了可以弹一个…

1861_什么是H桥

Grey 全部学习内容汇总&#xff1a; GitHub - GreyZhang/g_hardware_basic: You should learn some hardware design knowledge in case hardware engineer would ask you to prove your software is right when their hardware design is wrong! 1861_什么是H桥 H桥电路可以…

MySQL:通过官方mysql server,搭建绿色版mysql服务器(Windows)

1. 官网下载mysql server 下载mysql server的zip文件&#xff0c;地址&#xff1a; https://downloads.mysql.com/archives/community/ 解压后 2. 初始化数据库 运行cmd&#xff0c; 进入bin目录&#xff0c;运行 mysqld --initialize-insecureinitialize-insecure说明如…

windows中修改my.ini出现MySQL服务正在启动或停止中或服务无法启动

问题&#xff1a; 1.修改my.ini 2.在服务里启动MySQL服务正在启动或停止中或服务无法启动 解决办法&#xff1a; 1.修改my.ini编码方式 2.删除 安装目录中的data文件夹 3.winR&#xff08;管理员身份运行cmd&#xff09; cd 到安装目录中的bin文件夹 4.在cmd中运行 mysql…

2023年国赛高教杯数学建模E题黄河水沙监测数据分析解题全过程文档及程序

2023年国赛高教杯数学建模 E题 黄河水沙监测数据分析 原题再现 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变化和人民生活的影响&#xff0c;以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾等方面都具有重要的理论指导…

开源分布式搜索引擎ElasticSearch结合内网穿透远程连接

文章目录 前言1. Windows 安装 Cpolar2. 创建Elasticsearch公网连接地址3. 远程连接Elasticsearch4. 设置固定二级子域名 前言 简单几步,结合Cpolar 内网穿透工具实现Java 远程连接操作本地分布式搜索和数据分析引擎Elasticsearch。 Cpolar内网穿透提供了更高的安全性和隐私保…

分布式训练通信NCCL之Ring-Allreduce详解

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

SKU低价了如何监测

品牌在做控价的过程中&#xff0c;需要先监测商品的价格&#xff0c;但一条链接里如果有多个SKU应该如何监测呢&#xff0c;有时多个SKU会共用一个标题&#xff0c;只会在款式中体现不同&#xff0c;这就需要监测工作非常细致&#xff0c;否则容易监测失误。 监测低价可以由人工…

C/C++ BM2链表内指定区间反转

文章目录 前言题目1. 解决方案一1.1 思路阐述1.2 源码 2. 解决方案二2.1 思路阐述2.2 源码 总结 前言 这题是BM1的升级版&#xff0c;不过是把完整的链表翻转变成了指定区间。 题目 描述 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 …

第二证券:我国股市涨跌幅限制是多少?

我国股市涨跌幅束缚是多少&#xff1f; 1、主板&#xff1a;新股上市后的前5个交易日不设价格涨跌幅束缚&#xff0c;第6个交易日起&#xff0c;涨跌幅束缚为10%。 2、创业板&#xff1a;新股上市后的前5个交易日没有价格涨跌幅束缚&#xff0c;第6个交易日起&#xff0c;涨跌…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)十七:演示功能模块相关功能实现

一、本章内容 本章实现常见业务功能,包括文章管理、商品管理、订单管理、会员管理等功能。 1. 详细课程地址: https://edu.csdn.net/course/detail/38183 2. 源码下载地址: 点击下载 二、界面预览 三、开发视频 3.1 B站视频地址: