一个小demo的开发日记

Posted Betairy linkzeldagg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个小demo的开发日记相关的知识,希望对你有一定的参考价值。

啊~Re: 0怎么这么赞啊~

啊~

=====================================================

好吧我知道我很久没更新了。

这不重要!EMT!

=====================================================

嘛,进入正题嗯ww

 

一、3D几何体的组成

在进入正题之前,请允许我先说些关于…嗯…怎么说呢,基础的东西。

 

说到底啊,游戏里用到的这些场景。

它们都是什么?

它们怎么组成的?

它们又是怎么被画到屏幕上的?

为什么我在场景中安放了几个光源,它们就能反光,有阴影,各种各样的效果?

 

我们都知道计算机程序是通过一行一行的指令执行的。那么上述这些过程又是怎么完成的呢?如果不清楚这个过程的话,是没办法对其进行"深入的改造"的 ——

 

个人认为,这个demo中如果不了解这些内容的话,是没有办法做出来的。

在这个demo里 ——

  • 为了让树有平滑的生长过程,还要美观,我需要完全用程序生成这棵树的模型。

    而且说到底我也做不出一个像样的树。大概…能做出一个正在长大的史莱姆

  • 为了让树叶能够好看一点,我希望我能够自己控制光照的计算。

    而且Unity的PBR / GI我没自信在surface上不卡啊。还丑。

  • 为了有一个赞的天空和日夜交替,我希望我能够自己计算整个天空是什么样子的。

    而且Asset store里的东西太贵了。买得起的话谁自己写啊(误

  • ……

(PBR:基于物理模型的渲染技术;GI:全局光照)

 

…所以,我需要自己搞。所以,我需要了解这个过程(上面提到的)到底是怎么进行的。

当然,忽略了诸多细节。

 

那么首先,我们需要表示出整个场景。这大概算是一个切入点吧。

不过在这个demo中我们不需要考虑场景的问题。Unity已经为我们做好了;我们只需要考虑场景中的某个物体的"形状""贴图"等等要素。

 

我们知道,在现今的渲染体系中,物体都是由一堆小面拼起来的。就像下面这个茶壶:

 

这一个个四边形面组成了茶壶。不过实际上我们关注的并非是面,而是面的顶点。如果我们调整顶点的位置,它会牵动一些面的变化,最终反应到茶壶形状的变化。

 

除了位置之外,顶点还有许多别的属性。比如给顶点设置一个"颜色"属性,那我们就可以给这个茶壶上色。而且随着顶点颜色的变化,茶壶表面的颜色也会相应的做出改变。

(下图是一个简化的例子,有三个分别为红色绿色蓝色顶点。)

 

现在我们有顶点了。为了表示它们,让所有顶点的各项属性分别表示成成一个数组:

[ A的位置,B的位置,… ]

[ A的颜色,B的颜色,… ]

 

好了。但是现在,我们还只有一堆顶点,我们需要把它们组成一个面。为此,我们需要告诉计算机:那些点该组成一个面呢?

假设这里,面都是三角面。我们把它也表示成一个数组:

[ 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, … ]

这表示:0-1-2是一个面,0-2-3是一个面,0-3-4是一个面,…

这里数字是顶点的序号,这个例子中A是顶点0,B是顶点1。

 

好,现在我们有整个模型了。该怎么画它呢?

这部分是显卡(图形处理器,GPU)的工作。首先,我们把这几个数组丢给显卡,随后——

 

显卡会把这几个数组里的数据转化为空间中的点,这些点具有它们的属性。

这个过程可以人为设定转换的过程,以及最后它们应该具有怎样的属性。这也是通过写一段小程序实现的,这个程序必须包含一个函数,这个函数接收传进来的一堆数组中的某一列,输出空间中这个点的位置,以及它的各种属性值。这段程序称为顶点着色器(Vertex Shader)。

 

随后,再经过几个可编程和不可编程的过程,这些点最终组成了面。

然后经过了一个叫做栅格化的过程,它们被映射到了一些像素上。有点像画图程序里拉出一个圆,随后它"落入"像素点中,变成一幅图的过程。

 

注意,到现在为止,这些像素还没有颜色。

不过这些像素各自拥有属性值,这些属性值是从上一步设置好的属性值中计算得出的:就像颜色的渐变一样,每个属性值都会经过"渐变"的过程,然后称为某个像素的属性值

"渐变"的过程被称为插值。这是一个线性插值。

 

然后,我们得到某个像素的属性值,需要计算出这个像素该有的颜色。

这一步也是可以编程的。这个函数要实现的目的就是输入属性值,输出一个颜色值(RGBA),这被称为片段 / 像素着色器(Fragment Shader 或 Pixel Shader)

 

最后再经过一些乱七八糟的过程(比如扔掉被挡住的顶点之类),最终成为图像呈现给我们。

 

在上面那个渐变三角形的例子中,颜色值随着顶点位置被传入,在顶点着色器中颜色值原封不动的传出,作为像素着色器的输入值(这时已经拥有渐变了);像素着色器再原封不动的把它输出,就成了那样一副图像。

上面是一个被简化过的渲染流程。

(想看真货吗www?)

不过其实我们大多数情况下,并不关心中间那一坨。所以也不要方w

 

那么,每个物体都是由什么组成的?

之前说过,物体由顶点组成,而每个顶点有着许多种属性。实际上,上文中用作例子的"颜色"并不是一个什么常用的属性,比较常用的属性大概有这么几种:

位置。这是必须的。

法线。这代表了顶点的朝向,可以用来判断是否朝向光源等。法线是个单位矢量(长度为1)。

纹理坐标。这代表了作为贴图的图片该如何"贴"到模型上。

切线。用来建立切线空间。比较高级的技术会用到,可以先不用在意。

乱七八糟的一些自定义的参数。当然了 —— 你想传一些自有用途的东西到着色器里,不会有人拦着你的。

 

法线的话大概是这个样子:

 

纹理坐标(为和坐标加以区别,常用(u, v)的方式表示):

可以这么来理解:贴图上有几个被顶点标记好的点,把图上被标记的点钉在对应的顶点上。大概是这个感觉。

 

切线

其实这个东西可以先不在意,不过还是蛮重要的。

有的时候在计算中,我们需要用到切线空间:这个空间的正交基(xyz轴)是以顶点的法线(N)和两个与法线垂直的单位矢量(B & T)组成的。不过事实上,和法线垂直的矢量有无穷多个(一个平面),所以我们需要人为指定一个和它垂直的单位矢量便于计算。这个人为指定的矢量就是切线(T),然后我们可以简单的将N和T叉乘来得到B,这就建立起了切线空间。

N:Normal(法矢(向)量)

T:Tangent(切矢(向)量)

B:Bi-Normal(副法矢(向)量)

 

一言不合就这么多字了…好吧,那下回见w

 

 

 

 

E M T!

K M T!

 

(pixivid = 56926503)

以上是关于一个小demo的开发日记的主要内容,如果未能解决你的问题,请参考以下文章

FJOI游记(日记向 不定期更新)

Android开发日记Popupwindow 完美demo

[Django] Django基础环境配置 | 日记

[Django] Django基础环境配置 | 日记

18.9.26日记

开发日记:KBEngine+Unity+php做个扑克棋牌小游戏-DAY1