网格编程基础--01

(原文链接:https://catlikecoding.com/unity/tutorials/procedural-grid/)

创建网格点

使用协程分析网格点的布局

定义三角面

自动生成法线

添加纹理坐标和切线

本篇教程学习简单的顶点和三角形网格的创建

需要具备的基础:

  1. 熟悉基本的Unity编程
  2. 了解协程
  3. 使用Unity5.0.1或更高版本

             

复杂的表面下是简单的几何结构

  1. 渲染知识
  • 如果你想在Unity中使某些物体可视化,那么使用网格(mesh)。可以从别的项目中导入的3D模型。它可以通过网格编程来生成。也可以是纹理、UI元素或者粒子系统。甚至是屏幕效果也是网格来渲染。
  • 那么什么是网格(mesh),从概念上来说,网格是图形硬件设备用来绘制复杂物体的构造体。它至少包含一个顶点集合用来定义3D空间上的点,加上链接这些顶点的三角形集合(三角形是最基础的2D图形)。三角形构成了网格代表的表面。
  • 因为三角形是平的并且有直线边界,因此能用来画出平面(visualize flat and straight things),比如cube的各个面。使用大量的三角形能够大致的画出圆曲面。如果三角形足够小,但不小于一个像素单位的话,你就不会察觉到这种误差。通常来说这在实时渲染中是不可行的,在某些角度看,这些可视表面会呈现出锯齿状。

               

Unity中默认的capsule,cube,sphere  。     shaded  vs  wireframe  (着色的 vs 线框)

如何显示线框呢?

  • 如果你想显示3D模型,那么有两个必要的组件。 Mesh Filter:这个组件持有要显示的网格的引用。Mesh Renderer:网格如何被渲染,需要用到材质(material),不管是否需要投影或接收阴影等

为什么Mesh Renderer组件中有materials集合?

  • 通过调整材质可以完全改变网格的显示。Unity默认的材质是纯白色的。你能创建自己的材质球(Asset/Create/Material)并且拖拽到GameObject上。新创建材质默认使用标准着色器(Standard shader),通过着色器可以控制表面的呈现效果。
  • 赋值一张albedo map能够让你的网格呈现更多的细节。这是一张代表材质基础颜色的纹理。当然我们需要知道怎样将这张纹理投射到网格的三角形中,通过添加2D纹理坐标到顶点上可以完成这一步骤。二维纹理空间是指U和V。这些坐标的范围是((0,0)-(1,1)),覆盖整张纹理。在这个范围之外的坐标会被clamped或者tiling,取决于纹理设置。
    •                              

应用在Unity 网格中的UV测试纹理

  1. 创建顶点网格

你会怎样创建自己的网格呢?通过生成一个矩形网格找到答案吧。这个网格由单位长度的四边形方块组成。创建C#脚本并且把它变成一个带有水平和垂直大小的网格组建

需要System.Collections命名空间吗?

当我们把这个组件添加到一个GameObject时,应该同时添加Mesh Filter和Mesh Renderer组件。通过在类中添加特性,Unity就会自动添加

现在创建一个空物体,并且挂载这个脚本,然后Unity就会自动添加Mesh Filter和Mesh Renderer组件。设置renderer组件的材质,但先不要设置filter组件的网格。在这里我把网格大小设置为10x5

在Awake方法中调用生成网格的方法

先研究一下顶点的位置,三角形放在后面。声明Vector3数组来保存这些顶点。数组大小取决于网格大小。在每一个四边形角落都需要一个顶点,相邻的四边形可以共用相同的顶点。在每一个维度都需要多一个顶点。

(#x+1)(#y+1)

4x2的网格中的顶点和四边形下标

把这些顶点画出来才能确定它们的位置是否正确,在OnDrawGizmos方法中可以为每一个顶点在场景中绘制一个小黑点

什么是gizmos呢?

当没有顶点时,在非Play模式下也不会报错,因为OnDrawGizmos方法在编辑模式下也是可以执行的。为了防止错误,要判断顶点数组是否存在,如果不存在就return

在play模式下,在原点只看到一个圆圈。这是因为还没有放置这些顶点的位置,所以全部顶点都重叠在同一个位置了。需要用双层循环遍历这些位置

顶点网格

如上图所示的顶点我们已经生成好了,但还不知道它们放置的顺序。可以通过上色来呈现这个顺序,也可以通过协程放慢这个生成过程来观察放置的顺序。using System.Collections

-----------------这里可以放一个生成顶点过程的gif动画

  1. 创建网格

目前已经知道顶点的生成位置,那么就可以处理真正的网格了。此外在Grid组件中持有这个网格的引用,并且将它赋值给mesh filter组件。那么就可以将处理好的顶点赋值给网格了

在play模式下就可以看到mesh了

在play模式下已经有网格了,但没有赋值三角形之前是看不到这个网格的。三角形通过顶点数组的下标定义的。因为每一个三角形都有三个点,三个连续的下标就可以构成一个三角形。从只有一个三角形开始吧

现在有一个三角形了,但是这三个点是在一条直线上的。这会生成一个degenerate triangle,它是看不见的。前两个顶点是没有错的,但第三个点应该是下一行的第一个顶点。

这样才能得到一个三角形,但只有一个方向上才是可见的。在这种情况下,只有在Z轴的反方向才能看见这个网格。因此需要旋转视角才能看见。

三角形从哪个方向可以被看见是取决于顶点下标的方向的。默认情况下,如果是顺时针方向的,这个三角形就是前向的并且可见的。逆时针方向的三角形会被丢弃掉,因此就无需浪费时间在绘制物体的内部上了,通常情况下这也是不应该被看见的。

三角形的两个面

为了能从Z轴方向上看到三角形,我们应该改变这个顺序。也就是调换一下第二第三个下标

如上图,已经把第一个三角形给绘制出来了,现在绘制第二个

因为这些三角形共用两个顶点,所有只用四行代码就可以了,每一个顶点下标声明一次就行了

通过一个循环就可以生成一行方块了。当我们对顶点和三角形下标进行遍历时,记得两个都要记录。把yield return加进这个循环中,就不用等待顶点显示了。

顶点立即生成,而想看三角形逐个生成,那得在每一次循环中都更新网格,而不是循环结束后才更新。

到这里,通过双层循环把整个网格铺满了三角形。要注意的是,跳到下一行时顶点下标也要加一,因为每一行方块不会多出来一个顶点的。

填满整个网格

如同我们能看到的那样,网格被三角形填满了,一次一行,如果觉得可以了,那就可以去掉协程了,这样在生成的时候就不会有延迟了。

为什么不用一个四边形呢??

  1. 生成额外的顶点数据

网格以一种特殊的方式生成了。是因为至今还没有给网格添加法线。默认的法线方向是(0,0,1),这个方向正好与我们需要的相反。

法线是如何起到效果的呢?

每一个顶点都会有法线,因此需要用另外一个Vector数组。或者我们可以让网格基于三角形为法线赋值。let‘s be lazy this time and do that

法线是怎么重新计算的呢?

没有法线  vs 有法线

接下来就是UV坐标。现在的网格颜色是均衡的,即使它用的是一个带有albedo(反射)纹理的材质球。这也是说得通的,如果我们没有给UV坐标,那么默认是零。

为了让这张纹理适用整张网格,简单的用顶点位置除于网格维数:

不正确的UV坐标,clamping  vs. wrapping 纹理

如上图,纹理没有铺满整张网格。能否正确显示取决于纹理的重复模式是否设置成了clamp or repeat。上图情况的原因是因为我们用整数除于整数(得到的还是整数)。为了能得到可以铺满整个网格的UV坐标(范围0-1),应该使用float(浮点型)

现在,纹理可以投射到整个网格了。网格大小为10x5,纹理会有所水平拉伸。通过调整材质纹理的tiling设置可以改变这种情况。设置为(2,1)的话,U坐标翻倍,如果这张纹理是设置为repeat的话,就可以看到两个正方形瓦块。

正确的UV坐标,tiling (1,1) vs. (2,1)

另一种增加表面细节的方法是使用法线映射。这些法线纹理包含了被编码为颜色的法线适量。使用法线贴图将会比单单使用顶点法线呈现出更多细节光照效果

一个崎岖不平的表面,使金属质感更带感

把这个材质应用到我们的网格上是不会有效果的,因为要先把切线矢量添加到网格中。

切线是如何起到效果的呢?

因为是一个平面,所以所有的切线都会指向同一个方向--右边

一张模仿颠簸纹理的平面

到现在你已经知道如何创建简单的网格了,并且也知道如何使用材质可以将网格看起来更加复杂了。网格需要顶点位置和三角形,通常还有UV坐标(取决于它的四项设置),另外就是切线了。你可以增加顶点颜色,虽然Unity的标准着色器不会用到这个。你可以创建自己的shader并且使用这些颜色,敬请期待下一篇教程。

备注:

  1. 关于Texture一些属性的介绍
  • Texture.wrapMode 循环模式(Repeat or Clamp  : 重复或强制拉伸),在贴图边界以设置贴图的重复模式的方式避免不真实的情况,使用强制贴图边界拉伸:TextureWrapMode.Clamp.  或者 贴图重复平铺 TextureWrapMode.Repeat
  • TextureWrapMode.Clamp 钳制,钳制纹理到边框的最近像素,也就是单个图片,不重复平铺。这通常用于当映射一个图片到一个物体上时,并不像纹理平铺。纹理坐标被钳制在0-1之间。当UV大于1或小于0时,在边框的最近像素会被使用。
  • TextureWrapMode.Repeat 重复,平铺纹理,创建一个重复图案,当UV不在0-1范围内时,整数部分会被忽略,于是创建一个重复图案。

原文地址:https://www.cnblogs.com/DevMi/p/9742528.html

时间: 2024-08-02 07:09:02

网格编程基础--01的相关文章

Shell脚本编程基础

什么是Shell 操作系统最外层的程序,shell通过提示符让用户输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出来,管理用户与操作系统之间的交互. Shell是一个用户跟操作系统之间的一个命令解释器.Shell是用户与Linux操作系统之间沟通的桥梁.用户可以输入命令执行,又可以利用 Shell脚本编程去运行. 为什么要用到shell shell是一个交互式程序,当用户输入一条命令,shell就解释一条,一次只处理一条命令.如果我们一些复杂操作,逐个敲命令工作量就会增大,因此,我

C#面向对象基础01

面向对象不是取代面向过程的类.对象."人"是类,"张三"是人这个类的对象.类是抽象的,对象是具体的.按钮就是类,某个按钮就是对象.对象可以叫做类的实例.类就像int,对象就像10.字段field(和某个对象相关的变量),字段就是类的状态.人这个 类有姓名.年龄.身高等字段.类不占内存,对象才占内存.方法:方法就是累能够执行的动作,比如问好.吃饭等.类的继承,类之间可以有继承关系,比如电脑类可以从"电器"类继承,这样的好处是"电脑&quo

1.1编程基础之输入输出_01:Hello, World!

/* 1.1编程基础之输入输出 01:Hello, World! 总时间限制: 1000ms 内存限制: 65536kB 描述 对于大部分编程语言来说,编写一个能够输出"Hello, World!" 的程序往往是最基本.最简单的. 因此,这个程序常常作为一个初学者接触一门新的编程语言所写的第一个程序, 也经常用来测试开发.编译环境是否能够正常工作. 现在你就需要完成这样一个程序. 输入 无. 输出 一行,仅包含一个字符串:"Hello, World!" 样例输入 (

C#编程基础:静态构造函数

静态构造函数可能一般对于它有点陌生,静态构造函数是C#的一个新特性,在编程过程中用处并不广,它的主要目的是用于初始化一些静态的变量.可以参考C#入门基础01教程. 1.静态构造函数既没有访问修饰符,也没有参数.因为是.NET调用的,所以像public和private等修饰符就没有意义了. 2.是在创建第一个类实例或任何静态成员被引用时,.NET将自动调用静态构造函数来初始化类,也就是说我们无法直接调用静态构造函数,也就无法控制什么时候执行静态构造函数了. 3.一个类只能有一个静态构造函数. 4.

android动画效果编程基础--Android Animation

动画效果编程基础--Android Animation 动画类型 Android的animation由四种类型组成 XML中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面旋转动画效果 JavaCode中 AlphaAnimation 渐变透明度动画效果 ScaleAnimation 渐变尺寸伸缩动画效果 TranslateAnimation 画面转换位置移动动画效果 RotateAnimation 画面旋转动画

C#面向对象编程基础-喜课堂笔记

**************[5][C#面向对象编程基础]第1讲:类与对象**************** ????????????????*************2.1.1_类与对象的概念************** ? 研究对象的入口是: 静态特征:-------属性(什么样子) 动态特征:-------方法!(能做什么)这两个也是对象区分的重要因素! 3. 对象表示世界中的实体,面向对象编程就是将这些实体模拟到计算机中! 4. 什么是封装? ????封装是指将一个或多个小对象包装在一起,

《Linux高性能服务器编程》学习总结(五)——Linux网络编程基础API

第五章      Linux网络编程基础API 对于网络编程,首先要了解的就是字节序的问题,字节序分为主机字节序和网络字节序,主机字节序又称小端字节序,是低字节存放在地地址,而网络字节序又称大端字节序,是低字节放在高地址.当数据在不同的机器上传播时,就需要统一字节顺序以保证不出现错误.在发送数据前,先将需要转变的数据转成网络字节序再发送,接收时先转成主机字节序再处理,要特别注意的是,即使是本机的两个进程通信,也要考虑字节序的问题,比如JAVA的虚拟机就使用大端字节序.使用如下代码可以查看本机的字

1.1Shell脚本编程基础

编程基础 ? 程序 ?程序:算法+数据结构 ?数据:是程序的核心 ?数据结构:数据在计算机中的类型和组织方式 ?算法:处理数据的方式 ?程序编程风格: 过程式:以指令为中心,数据服务于指令 对象式:以数据为中心,指令服务于数据 ?shell程序:提供了编程能力,解释执行 程序的执行方式 ? 计算机:运行二进制指令 ? 编程语言:人与计算机之间交互的语言 ? 低级编程语言: 机器:二进制的0和1的序列,称为机器指令.与自然语言差异太大,难懂.难写 汇编:用一些助记符号替代机器指令,称为汇编语言 ?

Java网络编程和NIO详解开篇:Java网络编程基础

Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的生活方式,改变了整个世界. 然而,网络的无标度和小世界特性使得它又是复杂的,无所不在,无所不能,以致于我们无法区分甚至无法描述. 对于一个码农而言,了解网络的基础知识可能还是从了解定义开始,认识OSI的七层协议模型,深入Socket内部,进而熟练地